home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / apilot.lha / APilot / APilot_Opt / collision.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-03  |  17.7 KB  |  601 lines

  1. /*************************************************************************
  2.  *
  3.  * collision.c -- Routines for collision detection...
  4.  *
  5.  *-------------------------------------------------------------------------
  6.  * Authors: Casper Gripenberg  (casper@alpha.hut.fi)
  7.  *          Kjetil Jacobsen  (kjetilja@stud.cs.uit.no)
  8.  * 
  9.  */
  10.  
  11. /*-------------------------------------------------------------------------*/
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <exec/types.h>
  16.  
  17. #include "map.h"
  18. #include "common.h"
  19. #include "prefs.h"
  20.  
  21. #include "ships_protos.h"
  22. #include "points_protos.h"
  23. #include "cannon_protos.h"
  24. #include "collision_protos.h"
  25.  
  26. /*-------------------------------------------------------------------------*/
  27.  
  28. #define CHECK_DEAD_CANNON if( ((ACannon *) \
  29.                                map_points[mapp_y][mapp_x].objectptr) \
  30.                                ->cstate == DEAD ) \
  31.                             break
  32.  
  33. #define KILL_PLAYER player->status = 100; \
  34.                     add_explosion(player->pos.x, player->pos.y)
  35.  
  36. #define IN_RANGE(o1, o2, r) (abs((o1)->pos.x-(o2)->pos.x)<(r)     \
  37.                              && abs((o1)->pos.y-(o2)->pos.y)<(r))
  38.  
  39. extern AWorld World;
  40.  
  41. /*-------------------------------------------------------------------------*/
  42.  
  43. void 
  44. check_collisions( void )
  45. {
  46.   AShip *player = World.players->next;
  47.  
  48.   check_points();
  49.  
  50.   while (player->next != player) {
  51.     check_ships( player );
  52.     check_player2points( player );
  53.     check_player2player( player );
  54.     player = player->next;
  55.   }
  56.  
  57. }
  58.  
  59. /*-------------------------------------------------------------------------*/
  60.  
  61. /*
  62.  * check_player2player -- Checks player collisions between this player
  63.  *                        and the following players in the player list.
  64.  */
  65. void
  66. check_player2player( AShip *player )
  67. {
  68.   AShip *other_player = player->next;
  69.  
  70.   if (player->status > 0)
  71.     return;
  72.  
  73.   while (other_player->next != other_player) {
  74.     if (IN_RANGE(player, other_player, SHL_SIZE-3)) {
  75.       /*
  76.        * Add ship2ship bouncing etc. here later...
  77.        */
  78.       if (!other_player->shields) {
  79.         other_player->status = 100;
  80.         add_explosion(other_player->pos.x, other_player->pos.y);
  81.       }      
  82.       if (!player->shields) {
  83.         player->status = 100;
  84.         add_explosion(player->pos.x, player->pos.y);
  85.       }
  86.       return;
  87.     }
  88.     other_player = other_player->next;
  89.   }
  90. }
  91.  
  92. /*-------------------------------------------------------------------------*/
  93.  
  94. /*
  95.  * check_ships -- Goes through every point in the ship shape and checks
  96.  *                it's not inside something it shouldn't be, like a wall
  97.  *                or cannon..
  98.  */
  99. void
  100. check_ships( AShip *player )
  101. {
  102.   int i;
  103.   int bp_x, bp_y;
  104.   int cu_x, cu_y;
  105.   int mapp_x, mapp_y;      /* The map block we currently are inside */
  106.   int pos_x, pos_y;        /* The players current position          */
  107.   int point_x, point_y;    /* Points of the ship.                   */
  108.  
  109.   BOOL is_landing = FALSE; /* Is the ship landing or not.           */
  110.  
  111.   struct Coordinates *currc;
  112.   MAP_Point **map_points = World.map_points;
  113.  
  114.   currc = player->currc;
  115.   pos_x = player->pos.x;
  116.   pos_y = player->pos.y;
  117.  
  118.   if (player->status > 0)
  119.     return;
  120.  
  121.   if ( map_points[pos_y / MAP_BLOCKSIZE]
  122.                  [pos_x / MAP_BLOCKSIZE].blocktype == BLOCK_BASE )
  123.     is_landing = landing(player);
  124.  
  125.   for (i = 1; i < player->shapesize; i++) {
  126.     point_x = pos_x + currc[i].x;
  127.     point_y = pos_y + currc[i].y;
  128.  
  129.     mapp_x = point_x / MAP_BLOCKSIZE;
  130.     mapp_y = point_y / MAP_BLOCKSIZE;
  131.  
  132.     if (mapp_x >= World.Width || mapp_y >= World.Width ||
  133.         mapp_x < 0 || mapp_y < 0)
  134.       continue;
  135.  
  136.     switch (map_points[mapp_y][mapp_x].blocktype) {
  137.       case BLOCK_EMPTY:
  138.         break;
  139.       case BLOCK_FILLED:
  140.       case BLOCK_FILLED_ND:
  141.       case BLOCK_FUEL:
  142.         if (is_landing) {
  143.           player->pos.y = map_points[mapp_y][mapp_x].edge_y - currc[i].y - 1;
  144.           player->yvel  = -(player->yvel >> 1);
  145.           player->xvel  = (player->xvel >> 1);
  146.           player->angle = 0;
  147.           player->turning = YES;
  148.           return;
  149.         }
  150.         KILL_PLAYER;
  151.         return; 
  152.         break;
  153.       case BLOCK_LU:
  154.         if ( (point_x - map_points[mapp_y][mapp_x].edge_x) +
  155.              (point_y - map_points[mapp_y][mapp_x].edge_y)
  156.               < MAP_BLOCKSIZE) {
  157.           KILL_PLAYER;
  158.           return;
  159.         }
  160.         break;
  161.       case BLOCK_RD:
  162.         if ( (point_x - map_points[mapp_y][mapp_x].edge_x) +
  163.              (point_y - map_points[mapp_y][mapp_x].edge_y)
  164.               > MAP_BLOCKSIZE) {
  165.           KILL_PLAYER;
  166.           return;
  167.         }
  168.         break;      
  169.       case BLOCK_RU:
  170.         if ( (point_x - map_points[mapp_y][mapp_x].edge_x) +
  171.              (map_points[mapp_y][mapp_x].edge_y + MAP_BLOCKSIZE - point_y) 
  172.               > MAP_BLOCKSIZE) {
  173.           KILL_PLAYER;
  174.           return;
  175.         }
  176.         break;
  177.       case BLOCK_LD:
  178.         if ( (point_x - map_points[mapp_y][mapp_x].edge_x) +
  179.              (map_points[mapp_y][mapp_x].edge_y + MAP_BLOCKSIZE - point_y) 
  180.               < MAP_BLOCKSIZE) {
  181.           KILL_PLAYER;
  182.           return;
  183.         }
  184.         break;
  185.       case BLOCK_CU:
  186.         CHECK_DEAD_CANNON;
  187.         if ( (point_y - map_points[mapp_y][mapp_x].edge_y) >
  188.              (MAP_BLOCKSIZE-(CAN_HEIGHT - 
  189.                (((PRECS * CAN_HEIGHT)/(MAP_BLOCKSIZE/2) * 
  190.                  abs(point_x -
  191.                      map_points[mapp_y][mapp_x].edge_x -
  192.                      MAP_BLOCKSIZE/2)) >> SHFTPR))) ) {
  193.           kill_cannon( (ACannon *)map_points[mapp_y][mapp_x].objectptr );
  194.           KILL_PLAYER;
  195.           return;
  196.         }
  197.         break;
  198.       case BLOCK_CD:
  199.         CHECK_DEAD_CANNON;
  200.         if ( (point_y - map_points[mapp_y][mapp_x].edge_y) <
  201.              (CAN_HEIGHT - 
  202.                (((PRECS * CAN_HEIGHT)/(MAP_BLOCKSIZE/2) * 
  203.                  abs(point_x -
  204.                      map_points[mapp_y][mapp_x].edge_x -
  205.                      MAP_BLOCKSIZE/2)) >> SHFTPR)) ) {
  206.           kill_cannon( (ACannon *)map_points[mapp_y][mapp_x].objectptr );
  207.           KILL_PLAYER;
  208.           return;
  209.         }
  210.         break;
  211.       case BLOCK_CL:
  212.         CHECK_DEAD_CANNON;
  213.         if ( (point_x - map_points[mapp_y][mapp_x].edge_x) >
  214.              (MAP_BLOCKSIZE-(CAN_HEIGHT - 
  215.                (((PRECS * CAN_HEIGHT)/(MAP_BLOCKSIZE/2) * 
  216.                  abs(point_y -
  217.                      map_points[mapp_y][mapp_x].edge_y -
  218.                      MAP_BLOCKSIZE/2)) >> SHFTPR))) ) {
  219.           kill_cannon( (ACannon *)map_points[mapp_y][mapp_x].objectptr );
  220.           KILL_PLAYER;
  221.           return;
  222.         }
  223.         break;
  224.       case BLOCK_CR:
  225.         CHECK_DEAD_CANNON;
  226.         if ( (point_x - map_points[mapp_y][mapp_x].edge_x) <
  227.              (CAN_HEIGHT - 
  228.                (((PRECS * CAN_HEIGHT)/(MAP_BLOCKSIZE/2) * 
  229.                  abs(point_y -
  230.                      map_points[mapp_y][mapp_x].edge_y -
  231.                      MAP_BLOCKSIZE/2)) >> SHFTPR)) ) {
  232.           kill_cannon( (ACannon *)map_points[mapp_y][mapp_x].objectptr );
  233.           KILL_PLAYER;
  234.           return;
  235.         }
  236.         break;
  237.       default:
  238.         break;
  239.     }
  240.   }
  241.  
  242.   if (!player->local) {
  243.     player->draw_it = FALSE;
  244.     bp_x = World.local_ship->pos.x-(SCR_WIDTH+MAP_BLOCKSIZE*2)/2;
  245.     bp_y = World.local_ship->pos.y-(SCR_HEIGHT+MAP_BLOCKSIZE*2)/2;
  246.     cu_x = player->pos.x-bp_x;
  247.     cu_y = player->pos.y-bp_y;
  248.  
  249.     if ( cu_x > MAP_BLOCKSIZE )
  250.       if ( cu_x < MAP_BLOCKSIZE+SCR_WIDTH )
  251.         if ( cu_y > MAP_BLOCKSIZE )
  252.           if ( cu_y < MAP_BLOCKSIZE+SCR_HEIGHT )
  253.             player->draw_it = TRUE;
  254.   }
  255. }
  256.  
  257. /*-------------------------------------------------------------------------*/
  258.  
  259. /*
  260.  * check_points -- Goes through every point and checks if it hit any
  261.  *                 stationary object like a cannon or a wall etc..
  262.  *                 Also checks if point inside display area and
  263.  *                 playing area.
  264.  */
  265. void
  266. check_points()
  267. {
  268.   int bp_x, bp_y;
  269.   int cu_x, cu_y;
  270.   int mapp_x, mapp_y;
  271.   int w_width, w_height;
  272.  
  273.   AShip      *current_player = World.local_ship;
  274.   APoint     *point          = World.points->next;  
  275.   MAP_Point **map_points     = World.map_points;
  276.  
  277.   bp_x     = current_player->pos.x-(SCR_WIDTH+MAP_BLOCKSIZE*2)/2;
  278.   bp_y     = current_player->pos.y-(SCR_HEIGHT+MAP_BLOCKSIZE*2)/2;
  279.   w_width  = World.Width;
  280.   w_height = World.Height;
  281.  
  282.   while (point->next != point) {
  283.   
  284.     if (point->life <= 0) {
  285.       point = point->next;
  286.       continue;
  287.     }
  288.   
  289.     mapp_x = point->pos.x / MAP_BLOCKSIZE;
  290.     mapp_y = point->pos.y / MAP_BLOCKSIZE;
  291.  
  292.     if (mapp_x >= w_width) {
  293.       point->draw_it = FALSE;
  294.       point->life    = 0;
  295.       point = point->next;
  296.       continue;
  297.     } else if (point->pos.x <= 0) {
  298.       point->draw_it = FALSE;
  299.       point->life    = 0;
  300.       point = point->next;
  301.       continue;
  302.     }
  303.  
  304.     if (mapp_y >= w_height) {
  305.       point->draw_it = FALSE;
  306.       point->life    = 0;
  307.       point = point->next;
  308.       continue;
  309.     } else if (point->pos.y <= 0) {
  310.       point->draw_it = FALSE;
  311.       point->life    = 0;
  312.       point = point->next;
  313.       continue;
  314.     }
  315.  
  316.     /*
  317.      * This should improve bullets->cannons collsion detection
  318.      * somewhat. Simply checks if the last square was a cannon square
  319.      * and if the bullet passed right 'through' the cannon then explode the
  320.      * cannon and kill the point..Should make the check the other
  321.      * way around too (if someone fires at the back of a cannon),
  322.      * but it is less probable...
  323.      */
  324.     if (point->lastmap != C_NONE) {
  325.       switch (point->lastmap) {
  326.         case C_UP:
  327.           if (mapp_y - point->lpos.y == 1 &&
  328.               mapp_x - point->lpos.x == 0) {
  329.             if( ((ACannon *) 
  330.                  map_points[mapp_y-1][mapp_x].objectptr)->cstate == DEAD )
  331.               break;
  332.             kill_cannon( (ACannon *)map_points[mapp_y-1][mapp_x].objectptr );
  333.             point->draw_it = FALSE;
  334.             point->life    = 0;
  335.             point = point->next;
  336.             continue;
  337.           }
  338.           break;
  339.         case C_DN:          
  340.           if (point->lpos.y - mapp_y == 1 &&
  341.               mapp_x - point->lpos.x == 0) {
  342.             if( ((ACannon *) 
  343.                  map_points[mapp_y+1][mapp_x].objectptr)->cstate == DEAD )
  344.               break;
  345.             kill_cannon( (ACannon *)map_points[mapp_y+1][mapp_x].objectptr );
  346.             point->draw_it = FALSE;
  347.             point->life    = 0;
  348.             point = point->next;
  349.             continue;
  350.           }
  351.           break;
  352.         case C_LF:
  353.           if (mapp_x - point->lpos.x == 1 &&
  354.               mapp_y - point->lpos.y == 0) {
  355.             if( ((ACannon *) 
  356.                  map_points[mapp_y][mapp_x-1].objectptr)->cstate == DEAD )
  357.               break;
  358.             kill_cannon( (ACannon *)map_points[mapp_y][mapp_x-1].objectptr );
  359.             point->draw_it = FALSE;
  360.             point->life    = 0;
  361.             point = point->next;
  362.             continue;
  363.           }
  364.           break;
  365.         case C_RG:
  366.           if (point->lpos.x - mapp_x == 1 &&
  367.               mapp_y - point->lpos.y == 0) {
  368.             if( ((ACannon *) 
  369.                  map_points[mapp_y][mapp_x+1].objectptr)->cstate == DEAD )
  370.               break;
  371.             kill_cannon( (ACannon *)map_points[mapp_y][mapp_x+1].objectptr );
  372.             point->draw_it = FALSE;
  373.             point->life    = 0;
  374.             point = point->next;
  375.             continue;
  376.           }
  377.           break;
  378.         default:
  379.           break;
  380.       }
  381.     }
  382.  
  383.     switch (map_points[mapp_y][mapp_x].blocktype) {
  384.       case BLOCK_EMPTY:
  385.         point->lastmap = C_NONE;
  386.         break;
  387.       case BLOCK_FILLED:
  388.       case BLOCK_FILLED_ND:
  389.       case BLOCK_FUEL:
  390.         point->draw_it = FALSE;
  391.         point->life    = 0;
  392.         point = point->next;
  393.         continue;
  394.         break;
  395.       case BLOCK_LU:
  396.         if ( (point->pos.x - map_points[mapp_y][mapp_x].edge_x) +
  397.              (point->pos.y - map_points[mapp_y][mapp_x].edge_y)
  398.               < MAP_BLOCKSIZE) {
  399.           point->draw_it = FALSE;
  400.           point->life    = 0;
  401.           point = point->next;
  402.           continue;
  403.         }
  404.         point->lastmap = C_NONE;
  405.         break;
  406.       case BLOCK_RD:
  407.         if ( (point->pos.x - map_points[mapp_y][mapp_x].edge_x) +
  408.              (point->pos.y - map_points[mapp_y][mapp_x].edge_y)
  409.               > MAP_BLOCKSIZE) {
  410.           point->draw_it = FALSE;
  411.           point->life    = 0;
  412.           point = point->next;
  413.           continue;
  414.         }
  415.         point->lastmap = C_NONE;
  416.         break;      
  417.       case BLOCK_RU:
  418.         if ( (point->pos.x - map_points[mapp_y][mapp_x].edge_x) +
  419.              (map_points[mapp_y][mapp_x].edge_y + MAP_BLOCKSIZE - point->pos.y) 
  420.               > MAP_BLOCKSIZE) {
  421.           point->draw_it = FALSE;
  422.           point->life    = 0;
  423.           point = point->next;
  424.           continue;
  425.         }
  426.         point->lastmap = C_NONE;
  427.         break;
  428.       case BLOCK_LD:
  429.         if ( (point->pos.x - map_points[mapp_y][mapp_x].edge_x) +
  430.              (map_points[mapp_y][mapp_x].edge_y + MAP_BLOCKSIZE - point->pos.y) 
  431.               < MAP_BLOCKSIZE) {
  432.           point->draw_it = FALSE;
  433.           point->life    = 0;
  434.           point = point->next;
  435.           continue;
  436.         }
  437.         point->lastmap = C_NONE;
  438.         break;
  439.       case BLOCK_CU:
  440.         CHECK_DEAD_CANNON;
  441.         if ( (point->pos.y - map_points[mapp_y][mapp_x].edge_y) >
  442.              (MAP_BLOCKSIZE-(CAN_HEIGHT - 
  443.                (((PRECS * CAN_HEIGHT)/(MAP_BLOCKSIZE/2) * 
  444.                  abs(point->pos.x -
  445.                      map_points[mapp_y][mapp_x].edge_x -
  446.                      MAP_BLOCKSIZE/2)) >> SHFTPR))) ) {
  447.           if (point->type == BULLET)
  448.             kill_cannon( (ACannon *)map_points[mapp_y][mapp_x].objectptr );
  449.           point->draw_it = FALSE;
  450.           point->life    = 0;
  451.           point = point->next;
  452.           continue;
  453.         } else {
  454.           if (point->type == BULLET) {
  455.             point->lastmap = C_UP;
  456.             point->lpos.x = mapp_x;
  457.             point->lpos.y = mapp_y;
  458.           }
  459.         }
  460.         break;
  461.       case BLOCK_CD:
  462.         CHECK_DEAD_CANNON;
  463.         if ( (point->pos.y - map_points[mapp_y][mapp_x].edge_y) <
  464.              (CAN_HEIGHT - 
  465.                (((PRECS * CAN_HEIGHT)/(MAP_BLOCKSIZE/2) * 
  466.                  abs(point->pos.x -
  467.                      map_points[mapp_y][mapp_x].edge_x -
  468.                      MAP_BLOCKSIZE/2)) >> SHFTPR)) ) {
  469.           if (point->type == BULLET)
  470.             kill_cannon( (ACannon *)map_points[mapp_y][mapp_x].objectptr );
  471.           point->draw_it = FALSE;
  472.           point->life    = 0;
  473.           point = point->next;
  474.           continue;
  475.         } else {
  476.           if (point->type == BULLET) {
  477.             point->lastmap = C_DN;
  478.             point->lpos.x = mapp_x;
  479.             point->lpos.y = mapp_y;
  480.           }
  481.         }
  482.         break;
  483.       case BLOCK_CL:
  484.         CHECK_DEAD_CANNON;
  485.         if ( (point->pos.x - map_points[mapp_y][mapp_x].edge_x) >
  486.              (MAP_BLOCKSIZE-(CAN_HEIGHT - 
  487.                (((PRECS * CAN_HEIGHT)/(MAP_BLOCKSIZE/2) * 
  488.                  abs(point->pos.y -
  489.                      map_points[mapp_y][mapp_x].edge_y -
  490.                      MAP_BLOCKSIZE/2)) >> SHFTPR))) ) {
  491.           if (point->type == BULLET)
  492.             kill_cannon( (ACannon *)map_points[mapp_y][mapp_x].objectptr );
  493.           point->draw_it = FALSE;
  494.           point->life    = 0;
  495.           point = point->next;
  496.           continue;
  497.         } else {
  498.           if (point->type == BULLET) {
  499.             point->lastmap = C_LF;
  500.             point->lpos.x = mapp_x;
  501.             point->lpos.y = mapp_y;
  502.           }
  503.         }
  504.         break;
  505.       case BLOCK_CR:
  506.         CHECK_DEAD_CANNON;
  507.         if ( (point->pos.x - map_points[mapp_y][mapp_x].edge_x) <
  508.              (CAN_HEIGHT - 
  509.                (((PRECS * CAN_HEIGHT)/(MAP_BLOCKSIZE/2) * 
  510.                  abs(point->pos.y -
  511.                      map_points[mapp_y][mapp_x].edge_y -
  512.                      MAP_BLOCKSIZE/2)) >> SHFTPR)) ) {
  513.           if (point->type == BULLET)
  514.             kill_cannon( (ACannon *)map_points[mapp_y][mapp_x].objectptr );
  515.           point->draw_it = FALSE;
  516.           point->life    = 0;
  517.           point = point->next;
  518.           continue;
  519.         } else {
  520.           if (point->type == BULLET) {
  521.             point->lastmap = C_RG;
  522.             point->lpos.x = mapp_x;
  523.             point->lpos.y = mapp_y;
  524.           }
  525.         }
  526.         break;
  527.       default:
  528.         break;
  529.     }
  530.     
  531.     /* 
  532.      * Check if point inside screen boudaries 
  533.      */
  534.     point->draw_it = FALSE;
  535.     cu_x = point->pos.x-bp_x;
  536.     cu_y = point->pos.y-bp_y;
  537.  
  538.     if ( cu_x > MAP_BLOCKSIZE )
  539.       if ( cu_x < MAP_BLOCKSIZE+SCR_WIDTH )
  540.         if ( cu_y > MAP_BLOCKSIZE )
  541.           if ( cu_y < MAP_BLOCKSIZE+SCR_HEIGHT )
  542.             point->draw_it = TRUE;
  543.  
  544.     point = point->next;
  545.   }
  546. }
  547.  
  548. /*-------------------------------------------------------------------------*/
  549.  
  550. /*
  551.  * check_player2points -- Checks if a player has been hit by a point and
  552.  *                        if hit acts accordingly.
  553.  */
  554. void
  555. check_player2points( AShip *player )
  556. {
  557.   int tot_mass;
  558.  
  559.   APoint *point = World.points->next;
  560.  
  561.   if (player->status > 0)
  562.     return;
  563.  
  564.   while (point->next != point) {
  565.  
  566.     if (point->life <= 0) {
  567.       point = point->next;
  568.       continue;
  569.     }
  570.  
  571.     if (IN_RANGE(player, point, SHL_SIZE-3)) {
  572.       switch (point->type) {
  573.         case EXHAUST:
  574.         case EXPLOSION:
  575.           point->life = 0;
  576.           point->draw_it = FALSE;
  577.           tot_mass = point->mass + player->mass;
  578.           player->xvel = (player->xvel * player->mass + 
  579.                           point->xvel * point->mass) / tot_mass;
  580.           player->yvel = (player->yvel * player->mass + 
  581.                           point->yvel * point->mass) / tot_mass;
  582.           break;
  583.         case BULLET:
  584.         case CANNON_SHOT:
  585.           point->life = 0;
  586.           point->draw_it = FALSE;
  587.           player->fuel -= 5;
  588.           if (!player->shields) {
  589.             KILL_PLAYER;
  590.             return;
  591.           }
  592.           break;
  593.         default:
  594.           break;
  595.       }
  596.     }
  597.     point = point->next;
  598.   }
  599. }
  600.  
  601.