/* * control.c * * Handles all movement of both players, and collision dectection */ #include #include "pad.h" #include "defs.h" #include "sincos.h" #include "tank.h" #include "missile.h" #include "floor.h" #include "map.h" #define MISSILE_TIME_2 50 #define MISSILE_TIME_10 250 /* typedef struct { short angle; // direction long xmot, zmot; // movement long xpos, zpos; // position long xold, zold; // storage of ^^ long mtilt; // missile tilt angle long missiletime, hittime; // counters long misstime; // more counters u_long mode; // flags u_long vp; // viewpoint u_long keymask, keyhold; // temporary storage for pad buttons } player_str; */ // the player struct is now included #include "player.h" typedef struct { int map; // current map int plyrs; // number of players } game_str; #include "drone.h" player_str red, blue; // player info game_str game; void initPlayers(void) { blue.mode = MODE_TANK | MODE_MOVE; blue.angle = 0; blue.zmot = 1; blue.xmot = 1; blue.xpos = 0; blue.zpos = 0; blue.vp = 0; blue.mtilt = 0; blue.keymask = 0; blue.keyhold = 0; blue.hittime = 0; red.mode = MODE_DRONE | MODE_MOVE; red.angle = 2048; red.zmot = -1; red.xmot = -1; red.xpos = 8191; red.zpos = 4095; red.vp = 8; red.mtilt = 0; red.keymask = 0; red.keyhold = 0; red.hittime = 0; } void initGame(void) { game.map = 1; game.plyrs = 1; } void gameNext(void) { game.map ++; if(game.map == NUM_MAPS) game.map = 0; } extern long scores[2]; void missileTarget(player_str *tank, GsDOBJ2 *mobj) { long bx, bz, rx, rz, bmx, bmz; u_long dx, dz; SVECTOR bmp; VECTOR bmt; MATRIX ltw; bx = BTanks[0].coord2->coord.t[0]; bz = BTanks[0].coord2->coord.t[2]; rx = BTanks[1].coord2->coord.t[0]; rz = BTanks[1].coord2->coord.t[2]; bmx = mobj->coord2->coord.t[0]; bmz = mobj->coord2->coord.t[2]; GsGetLw(mobj->coord2, <w); setVector(&bmp, 0, 0, MISSILE_TIP); ApplyMatrix(<w, &bmp, &bmt); bmx += bmt.vx; bmz += bmt.vz; // FntPrint("\nMissile...\n"); // FntPrint(" Tip: %d, %d\n", bmx, bmz); // to detect missile collision, use a bounding circle around the tank // and the missile tip. // if the missile tip is within TANK_BOUNDC of the centre point // then it is a hit // dx = (double)(rx - bmx); // dz = (double)(rz - bmz);// x and z distances between red tank and blue missile // dt = hypot(dx, dz); // absolute distance // td = (u_long)dt; // integer // a bounding box may be faster... TANK_BOUNDC is the width dx = abs(rx - bmx); dz = abs(rz - bmz); // FntPrint(" To Red: %d, %d\n", dx, dz); if(dx < TANK_BOUNDC && dz < TANK_BOUNDC) { // printf("Missile hit Red Tank\n"); // tank->mode &= ~MODE_MISSILE; tank->mode |= MODE_SCORE; if((tank->vp & 0x07) > 3) tank->misstime = 25; red.mode |= MODE_HIT; red.xold = tank->xpos + (4 * tank->xmot); red.zold = tank->zpos + (4 * tank->zmot); if(blue.mode & MODE_SCORE) scores[0]++; // blue tank scores } dx = abs(bx - bmx); dz = abs(bz - bmz); // FntPrint(" To Blue: %d, %d\n", dx, dz); if(dx < TANK_BOUNDC && dz < TANK_BOUNDC) { // printf("Missile hit Blue Tank\n"); // tank->mode &= ~MODE_MISSILE; tank->mode |= MODE_SCORE; if((tank->vp & 0x07) > 3) tank->misstime = 25; blue.mode |= MODE_HIT; blue.xold = tank->xpos + (4 * tank->xmot); blue.zold = tank->zpos + (4 * tank->zmot); if(red.mode & MODE_SCORE) scores[1]++; } // detect missile - maze collisions if(bmx >= 0 && bmx < FLOOR_MAXX && bmz >= 0 && bmz < FLOOR_MAXZ) { // we are in the playing arena if(map_checkx(game.map, bmx, bmz) || map_checkz(game.map, bmx, bmz)) { // kaboom tank->mode &= ~MODE_MISSILE; tank->mode |= MODE_MISS; if((tank->vp & 0x07) > 3) tank->misstime = 25; } } } void moveTank(player_str *tank, u_long pad, int me, int op) { tank->keyhold &= pad; // still holding a button if(pad & tank->keymask) pad &= ~tank->keymask; // wait for the user to stop pressing else tank->keymask = 0; // reset tank->mtilt = 0; if(pad & PADLleft) { tank->angle -= 32; tank->mtilt = -64; } if(pad & PADLright) { tank->angle += 32; tank->mtilt = 64; } tank->angle &= 4095; if(tank->mode & MODE_HIT) { if((tank->vp & 0x07) > 3) tank->vp -= 4; tank->xpos = tank->xold; tank->zpos = tank->zold; tank->hittime = 50; tank->mode = MODE_MOVE | MODE_SPIN; } if(tank->mode & MODE_SCORE) { if((tank->vp & 0x07) > 3) tank->vp -= 4; tank->xpos = tank->xold; tank->zpos = tank->zold; tank->mode = MODE_TANK; tank->hittime = 50; // disable firing... } if(tank->mode == MODE_TANK) { if(pad & PADLup) { tank->xmot = rsin(tank->angle) >> 8; tank->zmot = rcos(tank->angle) >> 8; tank->mode |= MODE_MOVE; } if(pad & PADLdown) { tank->xmot = -rsin(tank->angle) >> 8; tank->zmot = -rcos(tank->angle) >> 8; tank->mode |= MODE_MOVE; } if(pad & PADRdown) { tank->mode |= MODE_MISSILE; tank->keymask |= PADRdown; tank->keyhold |= (pad & PADR2); pad &= ~PADRdown; tank->missiletime = MISSILE_TIME_10; tank->xold = tank->xpos; tank->zold = tank->zpos; } if(pad & PADRright && !tank->hittime) { tank->mode |= MODE_MISSILE; tank->mode |= MODE_HOME; tank->keymask |= PADRdown; tank->keyhold |= (pad & PADR2); pad &= ~PADRdown; tank->missiletime = MISSILE_TIME_2; tank->xold = tank->xpos; tank->zold = tank->zpos; tank->misstime = 1; // reset this counter tank->xpos += rsin(tank->angle) >> 8; tank->zpos += rcos(tank->angle) >> 8; } if(pad & PADRup) { tank->keymask |= PADRup; tank->vp++; if((tank->vp & 0x07) == 4) tank->vp &= 0x08; } } if(tank->mode & MODE_MISSILE) { if(tank->keyhold & PADR2) { if((tank->vp & 0x07) < 2) tank->vp += 4; } else { if((tank->vp & 0x07) > 3) tank->vp -= 4; } tank->missiletime--; if(!tank->missiletime || pad & PADRdown) { tank->mode = MODE_TANK; tank->keymask |= PADRdown; tank->xpos = tank->xold; tank->zpos = tank->zold; if((tank->vp & 0x07) > 3) tank->vp -= 4; } if(tank->mode & MODE_HOME) homeMissile(tank, me, op); tank->xmot = rsin(tank->angle) >> 6; tank->zmot = rcos(tank->angle) >> 6; } if(tank->hittime) tank->hittime--; if(tank->mode & MODE_SPIN) { tank->angle += 408; if(!tank->hittime) tank->mode &= ~MODE_SPIN; } if(tank->mode & MODE_MISS) { if((tank->vp & 0x07) > 3) tank->vp -= 4; tank->xpos = tank->xold; tank->zpos = tank->zold; tank->mode = MODE_TANK; } } void tankPos(player_str *tank, GsDOBJ2 *tobj, GsDOBJ2 *mobj) { SVECTOR rotate, bb[4]; VECTOR transform, hb[4]; MATRIX ltw; long testx, testz, mot; setVector(&rotate, 0, tank->angle, 0); RotMatrix(&rotate, &(tobj->coord2->coord)); if(tank->mode & MODE_MOVE) { // use collision detection to validate move testx = tank->xpos + (tank->xmot << 1); testz = tank->zpos + (tank->zmot << 1); if(testx < 0 || testx > FLOOR_MAXX) tank->xmot = 0; if(testz < 0 || testz > FLOOR_MAXZ) tank->zmot = 0; // re-evaluate the positions, this is to stop // an access violation in map bitmaps when on boundaries testx = tank->xpos + (tank->xmot << 1); testz = tank->zpos + (tank->zmot << 1); // test all four points of the tanks bounding box GsGetLw(tobj->coord2, <w); setVector(&bb[0], TANK_BOUNDW, 0, TANK_BOUNDF); setVector(&bb[1], TANK_BOUNDW, 0, -TANK_BOUNDB); setVector(&bb[2], -TANK_BOUNDW, 0, -TANK_BOUNDB); setVector(&bb[3], -TANK_BOUNDW, 0, TANK_BOUNDF); ApplyMatrix(<w, &bb[0], &hb[0]); ApplyMatrix(<w, &bb[1], &hb[1]); ApplyMatrix(<w, &bb[2], &hb[2]); ApplyMatrix(<w, &bb[3], &hb[3]); // FntPrint("%d, %d - %d, %d\n", testx, testz, hb[0].vx, hb[0].vz); mot = (tank->zmot < 0) ? -1 : 1; if(tank->angle > 1024 && tank->angle < 3072) mot = -mot; if(mot == 1) // only need to check the front of the tank { if(map_checkx(game.map, testx+hb[0].vx, testz+hb[0].vz)) tank->xmot = 0; if(map_checkz(game.map, testx+hb[0].vx, testz+hb[0].vz)) tank->zmot = 0; if(map_checkx(game.map, testx+hb[3].vx, testz+hb[3].vz)) tank->xmot = 0; if(map_checkz(game.map, testx+hb[3].vx, testz+hb[3].vz)) tank->zmot = 0; } else { if(map_checkx(game.map, testx+hb[1].vx, testz+hb[1].vz)) tank->xmot = 0; if(map_checkz(game.map, testx+hb[1].vx, testz+hb[1].vz)) tank->zmot = 0; if(map_checkx(game.map, testx+hb[2].vx, testz+hb[2].vz)) tank->xmot = 0; if(map_checkz(game.map, testx+hb[2].vx, testz+hb[2].vz)) tank->zmot = 0; } tank->xpos += tank->xmot << 1; tank->zpos += tank->zmot << 1; tank->xpos &= FLOOR_MAXX; tank->zpos &= FLOOR_MAXZ; setVector(&transform, tank->xpos, 0, tank->zpos); TransMatrix(&(tobj->coord2->coord), &transform); // if the x and z are within the 'maze' then we need to move the // tank, as all moves will be invalidated if(map_checkx(game.map, tank->xpos, tank->zpos)) { tank->xpos += 256; // a tile width } else if(map_checkz(game.map, tank->xpos, tank->zpos)) { tank->zpos += 256; // a tile } else tank->mode &= ~MODE_MOVE; // preserve the MODE_HIT flag } if(tank->mode & MODE_MISSILE) { tank->xpos += tank->xmot << 1; tank->zpos += tank->zmot << 1; setVector(&transform, tank->xpos, MISSILE_ALT, tank->zpos); RotMatrix(&rotate, &(mobj->coord2->coord)); TransMatrix(&(mobj->coord2->coord), &transform); } if(tank->mtilt) { setVector(&rotate, 0, tank->angle, tank->mtilt); RotMatrix(&rotate, &(mobj->coord2->coord)); } if(tank->mode & MODE_MISSILE) { missileTarget(tank, mobj); } } void moveBlue(u_long padl) { if(blue.mode & MODE_DRONE) droneMove(&blue, padl, 0, 1); else moveTank(&blue, padl, 0, 1); tankPos(&blue, &BTanks[0], &Bullets[0]); } void moveRed(u_long padr) { if(red.mode & MODE_DRONE) { // printf("Red mode: %lx\n", red.mode); droneMove(&red, padr, 1, 0); } else moveTank(&red, padr, 1, 0); tankPos(&red, &BTanks[1], &Bullets[1]); }