//*********************************************************** // // TANX2.0a by Stuart Macdonald // Codewarrior Version // object.c 1.0b op // //*********************************************************** //#include #include #include "header.h" // *********************************************************** // variables // *********************************************************** // extern stuff... extern int PLAYING; extern int INGAME; //extern char worldGroundData[MAX_Z][MAX_X]; extern char BldgWorldData[MAX_Z][MAX_X]; extern int LumWorldData[MAX_Z][MAX_X]; extern SpriteStructType0 theSprites[MAX_NO_OF_SPRITES]; extern LineStructType0 theLines[MAX_NO_OF_LINES]; extern BoxStructType0 theBoxes[MAX_NO_OF_BOXES]; extern ObjectStructType0 theTank[2]; extern ObjectStructType0 theTurret[2]; extern ObjectStructType0 theObjects[MAX_NO_OF_OBJECTS]; extern WorldStructType0 theWorld[2]; extern WorldStructType0 theBldgs[2]; extern voice_data bang,pickup,missile,missile2,shell2, shell, bang2, ping, alarm; // sound effects extern counter; // global variables ------------------------------------------- int PowerupCounter; int MAX_NO_OF_POWERUPS; int MAX_NO_OF_KILLS; extern int setVictory; extern int whoWon; PowerupHandlerType0 TankPowerups[2]; // *********************************************************** // object structure functions // eg. initialisation, updating, etc. // *********************************************************** // *********************************************************** // UpdateAllObjects check all objects & update // *********************************************************** // do you need all that outcommented code in this function? // is the case optimized? or why is the 1 coming after all the other values? void UpdateAllObjects (void) { int n; int error; int type; unsigned char collision; int pX; int pZ; //check if new powerups are needed if (counter == 99) { if (PowerupCounter < MAX_NO_OF_POWERUPS) { CreateObject(BEAM,0,0); } } for (n = 0; n < MAX_NO_OF_OBJECTS; n++) { if (theObjects[n].id != 0) { type = theObjects[n].id; switch (type) { case EXPLOSION: theObjects[n].frame++; if (theObjects[n].frame>=theObjects[n].lifespan) // check for next frame { SVECTOR TempRotation; TempRotation = theObjects[n].rotation; pX = theObjects[n].gsObjectCoord.coord.t[0]; pZ = theObjects[n].gsObjectCoord.coord.t[2]; theObjects[n].subtype--; // next animation stage theObjects[n].frame = 0; // reset counter switch (theObjects[n].subtype) { case 3: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)EXPLODE2_TMD); break; case 2: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)EXPLODE3_TMD); break; case 1: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)EXPLODE4_TMD); break; } MakeSemiTrans(&theObjects[n]); theObjects[n].rotation = TempRotation; RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 0, 0); theObjects[n].gsObjectCoord.flg = 0; } if (theObjects[n].subtype <= 0) { theObjects[n].id = EMPTY; } error = 0; break; case TRAIL: theObjects[n].frame++; //RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 0, 341); if (theObjects[n].frame>=theObjects[n].lifespan) // check for next frame { SVECTOR TempRotation; TempRotation = theObjects[n].rotation; pX = theObjects[n].gsObjectCoord.coord.t[0]; pZ = theObjects[n].gsObjectCoord.coord.t[2]; theObjects[n].subtype--; // next animation stage theObjects[n].frame = 0; // reset counter if(theObjects[n].subtype == 2){ AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)TRAIL2_TMD); } else { AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)TRAIL3_TMD); } MakeSemiTrans(&theObjects[n]); theObjects[n].rotation = TempRotation; RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 0, 0); theObjects[n].gsObjectCoord.flg = 0; } if (theObjects[n].subtype <= 0) { theObjects[n].id = EMPTY; } error = 0; break; case SM_RING: theObjects[n].frame++; if (theObjects[n].frame>=theObjects[n].lifespan) // check for next frame { SVECTOR TempRotation; TempRotation = theObjects[n].rotation; pX = theObjects[n].gsObjectCoord.coord.t[0]; pZ = theObjects[n].gsObjectCoord.coord.t[2]; theObjects[n].subtype--; // next animation stage theObjects[n].frame = 0; // reset counter switch (theObjects[n].subtype) { case 3: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)RING2_TMD); break; case 2: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)RING3_TMD); break; case 1: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)RING4_TMD); break; } MakeSemiTrans(&theObjects[n]); theObjects[n].rotation = TempRotation; RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 0, 0); theObjects[n].gsObjectCoord.flg = 0; } if (theObjects[n].subtype <= 0) { theObjects[n].id = EMPTY; } error = 0; break; case LG_RING: theObjects[n].frame++; if (theObjects[n].frame>=theObjects[n].lifespan) // check for next frame { SVECTOR TempRotation; TempRotation = theObjects[n].rotation; pX = theObjects[n].gsObjectCoord.coord.t[0]; pZ = theObjects[n].gsObjectCoord.coord.t[2]; theObjects[n].subtype--; // next animation stage theObjects[n].frame = 0; // reset counter switch (theObjects[n].subtype) { case 5: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)RING2_TMD); break; case 4: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)RING3_TMD); break; case 3: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)RING4_TMD); break; case 2: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)RING5_TMD); break; case 1: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)RING6_TMD); break; } MakeSemiTrans(&theObjects[n]); theObjects[n].rotation = TempRotation; RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 0, 0); theObjects[n].gsObjectCoord.flg = 0; } if (theObjects[n].subtype <= 0) { theObjects[n].id = EMPTY; } error = 0; break; case SHRAPNEL: theObjects[n].frame++; if (theObjects[n].frame>=theObjects[n].lifespan) // check for next frame { SVECTOR TempRotation; TempRotation = theObjects[n].rotation; pX = theObjects[n].gsObjectCoord.coord.t[0]; pZ = theObjects[n].gsObjectCoord.coord.t[2]; theObjects[n].subtype--; // next animation stage theObjects[n].frame = 0; // reset counter switch (theObjects[n].subtype) { case 5: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)SHRAPNL2_TMD); break; case 4: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)SHRAPNL3_TMD); break; case 3: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)SHRAPNL4_TMD); break; case 2: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)SHRAPNL5_TMD); break; case 1: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)SHRAPNL6_TMD); break; } MakeSemiTrans(&theObjects[n]); theObjects[n].rotation = TempRotation; RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 0, 0); theObjects[n].gsObjectCoord.flg = 0; } if (theObjects[n].subtype <= 0) { theObjects[n].id = EMPTY; } error = 0; break; case MISSILE: theObjects[n].frame -= theObjects[n].speed; if( theObjects[n].frame <= 0 ) { CreateObject(TRAIL,n,0); theObjects[n].frame = 800; } RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 0, 64); AdvanceModel(&theObjects[n],&theObjects[n].gsObjectCoord, &theObjects[n].rotation, theObjects[n].speed); FindTilePosition(&theObjects[n]); MakeLightPool(theObjects[n].tileposx, theObjects[n].tileposz); TestObjectCollision(&theObjects[n]); collision = theObjects[n].collision; if (collision) // check for collision (1) { theObjects[n].id = EMPTY; //clear object by removing its id } else theObjects[n].lifespan--; if (theObjects[n].lifespan <= 0) theObjects[n].id = EMPTY; error = 0; break; case SHELL: AdvanceModel(&theObjects[n], &theObjects[n].gsObjectCoord, &theObjects[n].rotation, theObjects[n].speed); FindTilePosition(&theObjects[n]); TestObjectCollision(&theObjects[n]); collision = theObjects[n].collision; if (collision) // check for collision (1) { //CreateObject(EXPLOSION, n, 0); //blow-up projectile. Later set according to type theObjects[n].id = EMPTY; //clear object by removing its id } else theObjects[n].lifespan--; if (theObjects[n].lifespan <= 0) theObjects[n].id = EMPTY; error = 0; break; case RAIL_RING: theObjects[n].frame++; if (theObjects[n].frame >= theObjects[n].lifespan) // check for next frame { SVECTOR TempRotation; TempRotation = theObjects[n].rotation; pX = theObjects[n].gsObjectCoord.coord.t[0]; pZ = theObjects[n].gsObjectCoord.coord.t[2]; theObjects[n].subtype--; //next animation stage theObjects[n].frame = 0; //reset counter switch (theObjects[n].subtype) { case 4: AddModelToObject(&theObjects[n], pX, -200, pZ,(unsigned long *)RAILGLO2_TMD); break; case 3: AddModelToObject(&theObjects[n], pX, -200, pZ,(unsigned long *)RAILGLO3_TMD); break; case 2: AddModelToObject(&theObjects[n], pX, -200, pZ,(unsigned long *)RAILGLO4_TMD); break; case 1: AddModelToObject(&theObjects[n], pX, -200, pZ,(unsigned long *)RAILGLO5_TMD); break; } MakeSemiTrans(&theObjects[n]); theObjects[n].rotation = TempRotation; RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 0, 0); theObjects[n].gsObjectCoord.flg = 0; } if (theObjects[n].subtype <= 0) { theObjects[n].id = EMPTY; } error = 0; break; case LASER_BOLT: theObjects[n].frame++; if (theObjects[n].frame >= theObjects[n].lifespan) // check for next frame { theObjects[n].id = EMPTY; } else { FindTilePosition(&theObjects[n]); MakeLightPool(theObjects[n].tileposx, theObjects[n].tileposz); } error = 0; break; case BEAM: theObjects[n].frame++; if (theObjects[n].frame >= theObjects[n].lifespan) // check for next frame { SVECTOR TempRotation; TempRotation = theObjects[n].rotation; pX = theObjects[n].gsObjectCoord.coord.t[0]; pZ = theObjects[n].gsObjectCoord.coord.t[2]; theObjects[n].subtype--; //next animation stage theObjects[n].frame = 0; //reset counter switch (theObjects[n].subtype) { case 3: AddModelToObject(&theObjects[n], pX, -200, pZ,(unsigned long *)BEAM2_TMD); break; case 2: AddModelToObject(&theObjects[n], pX, -200, pZ,(unsigned long *)BEAM3_TMD); break; case 1: AddModelToObject(&theObjects[n], pX, -200, pZ,(unsigned long *)BEAM4_TMD); break; } MakeSemiTrans(&theObjects[n]); theObjects[n].rotation = TempRotation; RotateModel (&theObjects[n].gsObjectCoord, &theObjects[n].rotation, 0, 0, 0); theObjects[n].gsObjectCoord.flg = 0; } RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, -64, 0); if (theObjects[n].subtype <= 0) { //once beam effect is finished, drop a random powerup into map position if (theObjects[n].flag == BEAM){ FindTilePosition(&theObjects[n]); DropItemOnMap(theObjects[n].tileposx, theObjects[n].tileposz); } theObjects[n].id = EMPTY; } error = 0; break; case FLAME: theObjects[n].frame++; if (theObjects[n].frame >= theObjects[n].lifespan) // check for next frame { SVECTOR TempRotation; TempRotation = theObjects[n].rotation; pX = theObjects[n].gsObjectCoord.coord.t[0]; pZ = theObjects[n].gsObjectCoord.coord.t[2]; theObjects[n].subtype--; //next animation stage theObjects[n].frame = 0; //reset counter switch (theObjects[n].subtype) { case 4: AddModelToObject(&theObjects[n], pX, -150, pZ,(unsigned long *)FLAME2_TMD); theObjects[n].size = 150; break; case 3: AddModelToObject(&theObjects[n], pX, -100, pZ,(unsigned long *)FLAME3_TMD); theObjects[n].size = 200; break; case 2: AddModelToObject(&theObjects[n], pX, -50, pZ,(unsigned long *)FLAME4_TMD); theObjects[n].size = 250; break; case 1: AddModelToObject(&theObjects[n], pX, 0, pZ,(unsigned long *)FLAME5_TMD); theObjects[n].size = 300; break; } MakeSemiTrans(&theObjects[n]); theObjects[n].rotation = TempRotation; RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 0, 0); theObjects[n].gsObjectCoord.flg = 0; } AdvanceModel(&theObjects[n], &theObjects[n].gsObjectCoord, &theObjects[n].rotation, theObjects[n].speed); TestObjectCollision(&theObjects[n]); if ((theObjects[n].subtype <= 0)||(theObjects[n].collision == 1)) { theObjects[n].id = EMPTY; } error = 0; break; case SHOCK: theObjects[n].frame++; pX = theTank[theObjects[n].flag].gsObjectCoord.coord.t[0]; pZ = theTank[theObjects[n].flag].gsObjectCoord.coord.t[2]; theObjects[n].gsObjectCoord.coord.t[0] = pX; theObjects[n].gsObjectCoord.coord.t[2] = pZ; if (theObjects[n].frame >= theObjects[n].lifespan) // check for next frame { SVECTOR TempRotation; TempRotation = theObjects[n].rotation; theObjects[n].subtype--; //next animation stage theObjects[n].frame = 0; //reset counter switch (theObjects[n].subtype) { case 7: AddModelToObject(&theObjects[n], pX, -106, pZ,(unsigned long *)SHOCK1_TMD); theObjects[n].size = 0; break; case 6: AddModelToObject(&theObjects[n], pX, -106, pZ,(unsigned long *)SHOCK2_TMD); theObjects[n].size = 0; break; case 5: AddModelToObject(&theObjects[n], pX, -106, pZ,(unsigned long *)SHOCK1_TMD); theObjects[n].size = 0; break; case 4: AddModelToObject(&theObjects[n], pX, -106, pZ,(unsigned long *)SHOCK2_TMD); theObjects[n].size = 0; break; case 3: AddModelToObject(&theObjects[n], pX, -106, pZ,(unsigned long *)SHOCK1_TMD); theObjects[n].size = 0; break; case 2: AddModelToObject(&theObjects[n], pX, -106, pZ,(unsigned long *)SHOCK2_TMD); theObjects[n].size = 0; break; case 1: AddModelToObject(&theObjects[n], pX, -106, pZ,(unsigned long *)SHOCK1_TMD); theObjects[n].size = 0; break; } MakeSemiTrans(&theObjects[n]); theObjects[n].rotation = TempRotation; RotateModel (&theObjects[n].gsObjectCoord,&theObjects[n].rotation, 0, 64, 0); } theObjects[n].gsObjectCoord.flg = 0; if (theObjects[n].subtype <= 0) { theObjects[n].id = EMPTY; theObjects[n].gsObjectHandler.attribute & (!(1 << 30)); } error = 0; break; case LIGHTNING: theObjects[n].frame++; if (theObjects[n].frame >= theObjects[n].lifespan) // check for next frame { theObjects[n].id = EMPTY; } else { FindTilePosition(&theObjects[n]); MakeLightPool(theObjects[n].tileposx, theObjects[n].tileposz); } error = 0; break; } //end of switch if (error) { printf("update ERROR! Invalid object type!!"); return; } } // if (...) } // for (...) } //*********************************************************** // DropItemOnMap drops random powerup onto map //*********************************************************** void DropItemOnMap (int tilex, int tilez) { int num; char powerups[30] = { 'X','2','3','A','W','2','3','4','S','3', '4','5','X','4','A','6','Z','5','6','5', 'S','2','3','Y','4','2','W','Y','Z','3' }; num = rand() % 30; BldgWorldData[tilex][tilez] = powerups[num]; PowerupCounter++; if(PowerupCounter > MAX_NO_OF_POWERUPS)//check whether too many powerups { BldgWorldData[tilex][tilez] = '0'; PowerupCounter--; } } //*********************************************************** // FindFreeObject check all objects & return next free //*********************************************************** int FindFreeObject (void) { int n; for (n = 0; n < MAX_NO_OF_OBJECTS; n++) if (theObjects[n].id == 0) return (n); return (-1); } //*********************************************************** // InitialiseAllObjects sets all object's id to 0 //*********************************************************** void InitialiseAllObjects (void) { int n; for (n = 0; n < MAX_NO_OF_OBJECTS; n++) theObjects[n].id = 0; } //*********************************************************** // InitialiseObject sets up object 'n' (use FindFreeObject first) //*********************************************************** void InitialiseObject(ObjectStructType0 *theObject,int id, int display, int depth,int size,int speed, int armour, int maxarmour, int subtype, int lifespan, int allegance, int shotpower, int reloadtime) { theObject->id = id; theObject->display = display; theObject->depth = depth; theObject->size = size; theObject->rotation.vx = theObject->rotation.vy = theObject->rotation.vz = 0; theObject->speed = speed; theObject->collision = false; theObject->dx = 0; theObject->dy = 0; theObject->dz = 0; theObject->armour = armour; theObject->maxarmour = maxarmour; theObject->subtype = subtype; theObject->lifespan = lifespan; theObject->alive = true; theObject->allegance = allegance; theObject->shotPower = shotpower; theObject->reloadTime = reloadtime; theObject->frame = 0; theObject->startposx = 0; theObject->startposz = 0; theObject->restart = 0; if( id == 0 ) { TankPowerups[allegance].powerup[0] = 0; TankPowerups[allegance].powerup[1] = 0; TankPowerups[allegance].powerup[2] = 0; TankPowerups[allegance].poweruptype[0] = 0; TankPowerups[allegance].poweruptype[1] = 0; TankPowerups[allegance].poweruptype[2] = 0; TankPowerups[allegance].poweruplist[0] = 0; TankPowerups[allegance].poweruplist[1] = 0; TankPowerups[allegance].poweruplist[2] = 0; TankPowerups[allegance].powerupcounter = 0; } theObject->flag = 0; theObject->score = 0; theObject->dir = 0; theObject->damage = 0; theObject->damagedBy = 0; } //*********************************************************** // FindTilePosition does exactly as it says on the tin! //*********************************************************** void FindTilePosition (ObjectStructType0 *theObject) { theObject->tileposx = ((theObject->gsObjectCoord.coord.t[0] + (SEPERATION / 2)) / SEPERATION); theObject->tileposz = ((theObject->gsObjectCoord.coord.t[2] + (SEPERATION / 2)) / SEPERATION); } //*********************************************************** // CreateObject makes object according to type then returns // its number in array so its values can be altered by calling // function. //*********************************************************** int CreateObject (int type, int flag, int flag2) { int num; // int error; int n; int pX; int pZ; n = 0; // error = 1; // num = 0; <--- you don't need that, do you? // code definetly crahs when FindFreeObject fails.. // when you try to access theObjects[num] with num = -1 returned from // the FindFreeObject function (but i think that can't happen, as you're creating only a new object // when one got destroyed num = FindFreeObject(); switch (type) { case EXPLOSION: { pX = flag; pZ = flag2; InitialiseObject(&theObjects[num],EXPLOSION, 3, 3, 1, 1, 0, 0, 4, 1, 1, 0, 0); AddModelToObject(&theObjects[num], pX, 0, pZ,(unsigned long *)EXPLODE1_TMD); theObjects[num].frame = 0; MakeSemiTrans(&theObjects[num]); RotateModel (&theObjects[num].gsObjectCoord,&theObjects[num].rotation,0,0,-0); theObjects[num].gsObjectCoord.flg = 0; // error = 0; break; } case SM_RING: { pX = flag; pZ = flag2; InitialiseObject(&theObjects[num],SM_RING, 3, 3, 1, 1, 0, 0, 4, 1, 1, 0, 0); AddModelToObject(&theObjects[num], pX, 0, pZ,(unsigned long *)RING1_TMD); theObjects[num].frame = 0; MakeSemiTrans(&theObjects[num]); RotateModel (&theObjects[num].gsObjectCoord,&theObjects[num].rotation,0,0,-0); theObjects[num].gsObjectCoord.flg = 0; // error = 0; break; } case LG_RING: { pX = flag; pZ = flag2; InitialiseObject(&theObjects[num],LG_RING, 3, 3, 1, 1, 0, 0, 6, 1, 1, 0, 0); AddModelToObject(&theObjects[num], pX, 0, pZ,(unsigned long *)RING1_TMD); theObjects[num].frame = 0; MakeSemiTrans(&theObjects[num]); RotateModel (&theObjects[num].gsObjectCoord,&theObjects[num].rotation,0,0,-0); theObjects[num].gsObjectCoord.flg = 0; // error = 0; break; } case SHRAPNEL: { int rot; pX = flag; pZ = flag2; InitialiseObject(&theObjects[num],SHRAPNEL, 3, 3, 1, 1, 0, 0, 6, 1, 1, 0, 0); AddModelToObject(&theObjects[num], pX, 0, pZ,(unsigned long *)SHRAPNL1_TMD); theObjects[num].frame = 0; MakeSemiTrans(&theObjects[num]); rot = rand() % 4095; RotateModel (&theObjects[num].gsObjectCoord,&theObjects[num].rotation,0,rot,-0); theObjects[num].gsObjectCoord.flg = 0; // error = 0; break; } case MISSILE: { SetupShot( num, flag, (unsigned long *)MISSILE_TMD); PlaySFX(&missile2); theObjects[num].gsObjectHandler.attribute = theObjects[num].gsObjectHandler.attribute ^ (1 << 30); theObjects[num].frame = 800; // error = 0; break; } case TRAIL: { pX = theObjects[flag].gsObjectCoord.coord.t[0]; pZ = theObjects[flag].gsObjectCoord.coord.t[2]; theObjects[num].frame = 0; // reset counter InitialiseObject(&theObjects[num],TRAIL, 3, 3, 1, 1, 0, 0, 3, 20, 1, 0, 0); AddModelToObject(&theObjects[num], pX, 0, pZ,(unsigned long *)TRAIL_TMD); MakeSemiTrans(&theObjects[num]); theObjects[num].rotation = theObjects[flag].rotation; theObjects[num].rotation.vz = 0; RotateModel (&theObjects[num].gsObjectCoord,&theObjects[num].rotation,0,0,-0); theObjects[num].gsObjectCoord.flg = 0; // error = 0; break; } case SHELL: { SetupShot( num, flag, (unsigned long *)SHELL_TMD); PlaySFX(&shell); theObjects[num].subtype = 1000; theObjects[num].gsObjectHandler.attribute = theObjects[num].gsObjectHandler.attribute ^ (1 << 30); // error = 0; break; } case RAIL_RING: { SetupShot( num, flag, (unsigned long *)RAILGLO1_TMD); theObjects[num].subtype = 5; theObjects[num].frame = 10; theObjects[num].size = 200; MakeSemiTrans(&theObjects[num]); PlaySFX(&shell2); for (n = 0; n < 10; n++) { theTurret[flag].speed = (600*(n+1)); num = FindFreeObject(); SetupShot( num, flag, (unsigned long *)RAILGLO1_TMD); theObjects[num].frame = 10 - (n * 4); theObjects[num].subtype = 5; theObjects[num].size = 200; MakeSemiTrans(&theObjects[num]); AdvanceModel(&theObjects[num], &theObjects[num].gsObjectCoord, &theObjects[num].rotation, theObjects[num].speed); TestObjectCollision(&theObjects[num]); if (theObjects[num].collision == true) { break; } } if (theObjects[num].collision == true) { CreateObject(EXPLOSION, num, 0); } // error = 0; break; } case LASER_BOLT: { SetupShot( num, flag, (unsigned long *)LASER_TMD); AdvanceModel(&theObjects[num], &theObjects[num].gsObjectCoord, &theObjects[num].rotation, 600); PlaySFX(&missile); theObjects[num].frame = 10; theObjects[num].size = 150; MakeSemiTrans(&theObjects[num]); for (n = 0; n < 10; n++) { theTurret[flag].speed = (1200 * n); num = FindFreeObject(); SetupShot( num, flag, (unsigned long *)LASER_TMD); theObjects[num].frame = 10 - n; theObjects[num].size = 150; MakeSemiTrans(&theObjects[num]); AdvanceModel(&theObjects[num], &theObjects[num].gsObjectCoord, &theObjects[num].rotation, theObjects[num].speed); TestObjectCollision(&theObjects[num]); if(theObjects[num].collision == true) { break; } } if(theObjects[num].collision == true) { CreateObject(EXPLOSION, num, 0); } // error = 0; break; } case BEAM: { int pX; int pZ; FindFreeTilePos(&theObjects[num]); pX = theObjects[num].gsObjectCoord.coord.t[0]; pZ = theObjects[num].gsObjectCoord.coord.t[2]; InitialiseObject(&theObjects[num],BEAM, 3, 3, 1, 0, 0, 0, 4, 10, 99, 0, 0); AddModelToObject(&theObjects[num], pX, 0, pZ,(unsigned long *)BEAM1_TMD); MakeSemiTrans(&theObjects[num]); theObjects[num].frame = 0; theObjects[num].flag = BEAM; // error = 0; break; } case TELEPORT: { int pX; int pZ; pX = theTank[flag].gsObjectCoord.coord.t[0]; pZ = theTank[flag].gsObjectCoord.coord.t[2]; InitialiseObject(&theObjects[num],BEAM, 3, 3, 1, 0, 0, 0, 4, 10, 99, 0, 0); AddModelToObject(&theObjects[num], pX, 0, pZ,(unsigned long *)BEAM1_TMD); MakeSemiTrans(&theObjects[num]); theObjects[num].frame = 0; theObjects[num].lifespan = 10; theObjects[num].flag = TELEPORT; // error = 0; break; } case FLAME: { SetupShot( num, flag, (unsigned long *)FLAME1_TMD); AdvanceModel(&theObjects[num],&theObjects[num].gsObjectCoord,&theObjects[num].rotation,-300); theObjects[num].subtype = 5; theObjects[num].frame = 0; theObjects[num].size = 50; MakeSemiTrans(&theObjects[num]); // error = 0; break; } case SHOCK: { int pX; int pZ; pX = theTank[flag].gsObjectCoord.coord.t[0]; pZ = theTank[flag].gsObjectCoord.coord.t[2]; InitialiseObject(&theObjects[num],SHOCK, 3, 3, 1, 0, 0, 0, 8, 5, 99, 0, 0); AddModelToObject(&theObjects[num], pX, -106, pZ,(unsigned long *)SHOCK1_TMD); theObjects[num].subtype = 8; theObjects[num].frame = 0; theObjects[num].lifespan = 1; theObjects[num].flag = flag; MakeSemiTrans(&theObjects[num]); // error = 0; break; } case LIGHTNING: { for (n = 0; n < 10; n++) { theTurret[flag].speed = (900 * n); num = FindFreeObject(); theObjects[num].subtype = rand() % 4; switch(theObjects[num].subtype) { case 0: SetupShot( num, flag, (unsigned long *)LIGHTNG1_TMD); break; case 1: SetupShot( num, flag, (unsigned long *)LIGHTNG2_TMD); break; case 2: SetupShot( num, flag, (unsigned long *)LIGHTNG3_TMD); break; case 3: SetupShot( num, flag, (unsigned long *)LIGHTNG4_TMD); break; case 4: SetupShot( num, flag, (unsigned long *)LIGHTNG1_TMD); break; } theObjects[num].frame = 0; theObjects[num].size = 400; MakeSemiTrans(&theObjects[num]); AdvanceModel(&theObjects[num], &theObjects[num].gsObjectCoord, &theObjects[num].rotation, theObjects[num].speed); TestObjectCollision(&theObjects[num]); if(theObjects[num].collision == true) { break; } } if(theObjects[num].collision == true) { //CreateObject(EXPLOSION, num, 0); } // error = 0; break; } default: printf("create ERROR! Invalid object type!!"); return (-1); break; } return (num); /* if (!error) { return(num); } else { printf("create ERROR! Invalid object type!!"); return(-1); }*/ } //*********************************************************** // SetupShot // Assigns shot variables from turret values // //*********************************************************** void SetupShot (int num, int flag, unsigned long *modeltype) { int id = theTurret[flag].subtype; int speed = theTurret[flag].speed; int power = theTurret[flag].shotPower; int life = theTurret[flag].lifespan; int pX; int pZ; theObjects[num].tileposx = theTank[flag].tileposx; theObjects[num].tileposz = theTank[flag].tileposz; theObjects[num].allegance = flag; SetShotDirection (&theTurret[flag].gsObjectCoord, &theTurret[flag].rotation, speed, flag); // set turret vectors pX = theObjects[num].gsObjectCoord.coord.t[0]=theTurret[flag].gsObjectCoord.coord.t[0]; pZ = theObjects[num].gsObjectCoord.coord.t[2]=theTurret[flag].gsObjectCoord.coord.t[2]; theObjects[num].gsObjectCoord.coord.t[1] = -200; InitialiseObject(&theObjects[num],id, 3, 3, 50, speed, 0, 0, 0, life, flag, power, 0); AddModelToObject(&theObjects[num], pX, -200, pZ,(unsigned long *)modeltype); theObjects[num].rotation = theTurret[flag].rotation; RotateModel (&theObjects[num].gsObjectCoord,&theObjects[num].rotation, 0, 0, 0); AdvanceModel(&theObjects[num], &theObjects[num].gsObjectCoord,&theObjects[num].rotation, 600); } //*********************************************************** // AddModelToObject // Assigns passed model address to structure // //*********************************************************** void AddModelToObject (ObjectStructType0 *theObject, int nX, int nY, int nZ, unsigned long *lModelAddress) { //increment the pointer to move past the model id. (weird huh?) lModelAddress++; // map tmd data to its actual address GsMapModelingData((unsigned long *)lModelAddress); // initialise the players coordinate system - set to be that of the world GsInitCoordinate2(WORLD, &theObject->gsObjectCoord); // increment pointer twice more - to point to top of model data (beats me!) lModelAddress++; lModelAddress++; // link the model (tmd) with the players object handler GsLinkObject4((u_long )lModelAddress, &theObject->gsObjectHandler,0); // Assign the coordinates of the object model to the Object Handler theObject->gsObjectHandler.coord2 = &theObject->gsObjectCoord; // setting the players gsObjectCoord.flg to 0 indicates it is to be drawn // Set the initial position of the object theObject->gsObjectCoord.coord.t[0]=nX; // X theObject->gsObjectCoord.coord.t[1]=nY; // Y theObject->gsObjectCoord.coord.t[2]=nZ; // Z // setting the players gsObjectCoord.flg to 0 indicates it is to be drawn theObject->gsObjectCoord.flg = 0; } //*********************************************************** // ResetMatrix // Not quite sure what this does... <--- creates an identity matrix in m // //*********************************************************** void ResetMatrix (short m[3][3]) { m[0][0]=m[1][1]=m[2][2]=ONE; m[0][1]=m[0][2]=m[1][0]=m[1][2]=m[2][0]=m[2][1]=0; } //*********************************************************** // RotateModel // Rotates any given model by Rx,Ry and Rz units out of 4096(ONE) // //*********************************************************** void RotateModel (GsCOORDINATE2 *gsObjectCoord,SVECTOR *rotateVector , int nRX, int nRY, int nRZ ) { MATRIX matTmp; // the reset the players coord system to the identity matrix ResetMatrix(gsObjectCoord->coord.m ); // Add the new rotation factors into the players rotation vector // and then set them to the remainder of division by ONE (4096) rotateVector->vx = (rotateVector->vx+nRX) % ONE; rotateVector->vy = (rotateVector->vy+nRY) % ONE; rotateVector->vz = (rotateVector->vz+nRZ) % ONE; // RotMatrix sets up the matrix coefficients for rotation RotMatrix(rotateVector, &matTmp); // Concatenate the existing objects matrix with the rotation matrix MulMatrix0(&gsObjectCoord->coord, &matTmp, &gsObjectCoord->coord); // set the flag to redraw the object gsObjectCoord->flg = 0; } //*********************************************************** // AdvanceModel // Moves any given model by 'speed' units // n is for identifying a tank, so the turret can be kept // with the tank and its vector can be saved in dx,dy,dz // for firing. //*********************************************************** void AdvanceModel (ObjectStructType0 *theObject, GsCOORDINATE2 *gsObjectCoord, SVECTOR *rotateVector, int speed) { int num; // Moves the model nD units in the direction of its rotation vector MATRIX matTmp; SVECTOR startVector; SVECTOR currentDirection; num = 0; // if nD = 0 there is no movement and we need to avois the // main body of the function which will cause a divide by zero error // set up original vector, pointing down the positive z axis startVector.vx = 0; startVector.vy = 0; startVector.vz = ONE; // RotMatrix sets up the matrix coefficients for rotation RotMatrix(rotateVector, &matTmp); // multiply startVector by mattmp and put the result in currentDirection // which is the vector defining the direction the player is pointing ApplyMatrixSV(&matTmp, &startVector, ¤tDirection); // currentDirection components have a maximum value of 4096 so we // scale nD to 4096 /nD then when we add the amount of // translation we divide by nD. This ensures that we will translate // the number of units originally specified by nD // nD = 4096 /nD ; if (theObject->id == TANK) { //Few extra bits and pieces to cover if object is tank num = theObject->allegance; // this bit to do with bullets theObject->dx=(currentDirection.vx * (theTurret[num].speed)) / 4096; theObject->dy=(currentDirection.vy * (theTurret[num].speed)) / 4096; theObject->dz=(currentDirection.vz * (theTurret[num].speed)) / 4096; //if(theObject->subtype != 4) //{ theObject->sx = (currentDirection.vx * speed) / 4096; theObject->sz = (currentDirection.vz * speed) / 4096; //} //else //old hovercraft chassis handling code from original tanx //{ // if the chassis is a hovercraft the thrust vector needs taken into consideration // theObject->sx += (currentDirection.vx * speed)/4096; // theObject->sz += (currentDirection.vz * speed)/4096; // need to limit top thrust speed // if (((theObject->sx * theObject->sx)+(theObject->sz * theObject->sz)) > 33000) // { // theObject->sx -= (currentDirection.vx * speed) / 4096; // theObject->sz -= (currentDirection.vz * speed) / 4096; // } //} theObject->gsObjectCoord.coord.t[0] += theObject->sx; // theObject->gsObjectCoord.coord.t[1] += 0; <-- not necessary !? theObject->gsObjectCoord.coord.t[2] += theObject->sz; } else { //if not a tank, move normally theObject->gsObjectCoord.coord.t[0] +=(currentDirection.vx * speed) / 4096; theObject->gsObjectCoord.coord.t[1] +=(currentDirection.vy * speed) / 4096; theObject->gsObjectCoord.coord.t[2] +=(currentDirection.vz * speed) / 4096; } // Because It Has Changed, 0 Means that we will redraw it theObject->gsObjectCoord.flg = 0; } //*********************************************************** // SetShotDirection // Scarily similar to AdvanceModel // rather than having a shared function, I figured it was // clearer to keep them seperate // Sets bullet direction for firing dx,dy & dz, held in theTurret struct //*********************************************************** void SetShotDirection (GsCOORDINATE2 *gsObjectCoord, SVECTOR *rotateVector, int speed, int n) { MATRIX matTmp; SVECTOR startVector; SVECTOR currentDirection; startVector.vx = 0; startVector.vy = 0; startVector.vz = ONE; RotMatrix(rotateVector, &matTmp); ApplyMatrixSV(&matTmp, &startVector, ¤tDirection); theTurret[n].dx=(currentDirection.vx * (theTurret[n].speed)) / 4096; theTurret[n].dy=(currentDirection.vy * (theTurret[n].speed)) / 4096; theTurret[n].dz=(currentDirection.vz * (theTurret[n].speed)) / 4096; } //*********************************************************** // RestartPlayer // Respawns player in one of six restart points chosen at // random. RestartPoints array holds tile positions of // these respawn points //*********************************************************** void RestartPlayer (ObjectStructType0 *thePlayer,ObjectStructType0 *thePlayersTurret) { int pX; int pY; int pZ; FindFreeTilePos(thePlayer);//choose random restart point updateScores(); while (thePlayer->id == 99) { thePlayer->id = TANK; FindFreeTilePos (thePlayer); //choose random restart point printf("no free tile found for player"); } pX = thePlayer->gsObjectCoord.coord.t[0]; pY = 0; pZ = thePlayer->gsObjectCoord.coord.t[2]; InitialiseObject(thePlayer,TANK, 3, 3, 400, 120, 200, 200, 1, 0,thePlayer->allegance, 0, 10); AddModelToObject(thePlayer, pX, pY, pZ,(unsigned long *)CHASSIS1_TMD); InitialiseObject(thePlayersTurret,TURRET, 3, 3, 400,220, 0, 0, SHELL, 1400,thePlayer->allegance, 20, 10); AddModelToObject(thePlayersTurret, pX, pY-20, pZ,(unsigned long *)TURRET1_TMD); InitialiseSprite(CANNON_TIM, &theSprites[thePlayer->allegance].sprite, 70, 70); // 200, -32 theSprites[thePlayer->allegance].depth = 2; theSprites[thePlayer->allegance].id = CANNON; theSprites[thePlayer->allegance].display = thePlayer->allegance; thePlayer->display = 3;//show on both screens //health stuff SetHealthbar(&theBoxes[thePlayer->allegance], 200); // Set healthbar to full theBoxes[thePlayer->allegance].id = HEALTHBAR; theBoxes[thePlayer->allegance].display = thePlayer->allegance; FindTilePosition(thePlayer); //colour identifier theBoxes[thePlayer->allegance + 2].gsBoxHandler.x = 112 - (thePlayer->allegance * 241); theBoxes[thePlayer->allegance + 2].gsBoxHandler.y = -48; theBoxes[thePlayer->allegance + 2].gsBoxHandler.w = 16; theBoxes[thePlayer->allegance + 2].gsBoxHandler.h = 24; theBoxes[thePlayer->allegance + 2].gsBoxHandler.r = 128 - (thePlayer->allegance * 127); theBoxes[thePlayer->allegance + 2].gsBoxHandler.g = 1; theBoxes[thePlayer->allegance + 2].gsBoxHandler.b = 1 + (thePlayer->allegance * 127); theBoxes[thePlayer->allegance + 2].depth = 1; theBoxes[thePlayer->allegance + 2].id = 99; theBoxes[thePlayer->allegance + 2].display = thePlayer->allegance; thePlayer->gsObjectCoord.coord.t[0] = pX; // X thePlayer->gsObjectCoord.coord.t[1] = pY; // Y thePlayer->gsObjectCoord.coord.t[2] = pZ; // Z thePlayersTurret->gsObjectCoord.coord.t[0]= pX; // X thePlayersTurret->gsObjectCoord.coord.t[1]= pY - 20;// Y thePlayersTurret->gsObjectCoord.coord.t[2]= pZ; // Z SetMinimap(); InitialiseSprite(MINIMAP_TIM, &theSprites[2].sprite, -119, -119); // 200, -32 theSprites[2].depth = 2; theSprites[2].id = MINIMAP; theSprites[2].display = 3; } //*********************************************************** // FindFreeTilePos // Finds random free tile position //*********************************************************** void FindFreeTilePos (ObjectStructType0 *theObject) { int stx; int stz; int n; int CheckCounter; int pX; int pY; int pZ; int check; //char world; char bldgs; check = 1; CheckCounter = 0; while (check == 1) { check = 0; stx = (rand() % 30) + 1; stz = (rand() % 30) + 1; //world = worldGroundData[stx][stz]; bldgs = BldgWorldData[stx][stz]; if (bldgs != '0') check = 1; // check no other tanks are on restart tile // if so call check = 1 for (n = 0; n < (2+NO_OF_BOTS); n++) { FindTilePosition (&theTank[n]); if(theTank[n].tileposx == stx) { if(theTank[n].tileposz == stz) { check = 1; } } } CheckCounter++; if (CheckCounter > 10) check = 99; } if (check == 99) { theObject->id = 99; return ; } pX = stx * 1200; pY = 0; pZ = stz * 1200; theObject->gsObjectCoord.coord.t[0] = pX; // X theObject->gsObjectCoord.coord.t[1] = pY; // Y theObject->gsObjectCoord.coord.t[2] = pZ; // Z return; } //*********************************************************** // UpdatePlayer // Keeps turret & chassis together // Also update any player-centric effects eg. smoke, muzzle flash // shields, upgrade effect, etc. //*********************************************************** void UpdatePlayer (ObjectStructType0 *thePlayer,ObjectStructType0 *thePlayersTurret) { int temp,n; int type; int num; int player; player = thePlayer->allegance; thePlayersTurret->gsObjectCoord.coord.t[0]=thePlayer->gsObjectCoord.coord.t[0]; // X thePlayersTurret->gsObjectCoord.coord.t[1]=thePlayer->gsObjectCoord.coord.t[1]; // Y thePlayersTurret->gsObjectCoord.coord.t[2]=thePlayer->gsObjectCoord.coord.t[2]; // Z thePlayersTurret->gsObjectCoord.flg = 0; //check powerup specials for(n = 0;n < 3;n++) { if (TankPowerups[player].poweruptype[n] > 0) { temp = TankPowerups[player].powerup[n]; type = TankPowerups[player].poweruptype[n]; //update types if(type == SHIELD) { thePlayer->damage = 0;// no damage with shield on } else { if(type == EMP_SHOCK) { num = 9+player;//find static sprite number (#9->p1, #10->p2) if(theSprites[num].id == STATIC1) { InitialiseSprite(STATIC2_TIM, &theSprites[num].sprite, -119, -119); // load static theSprites[num].id = STATIC2; } else { InitialiseSprite(STATIC1_TIM, &theSprites[num].sprite, -119, -119); // load static theSprites[num].id = STATIC1; } theSprites[num].display = 1-player; theSprites[num].depth = 0; } else { if(type == INVISIBILITY) { thePlayer->display = player;// no display in enemy's screen } else { if(type == SPEEDUP) { thePlayer->speed = 200;// increase player's speed } } } } temp--; if (temp <= 0) { TankPowerups[player].poweruptype[n] = 0; temp = 0; num = 9+(player);//find sprite number (#9->p1, #10->p2) thePlayer->display = 3;// reset screen display to show tank in both screens ( for invisibility ) thePlayersTurret->display = 3; thePlayer->speed = 120; theSprites[num].id = 0;// turns off static sprite } TankPowerups[player].powerup[n] = temp; } } //check damage if (thePlayer->damage != 0) // check if tank has been damaged, using damage to keep total of damage done { thePlayer->armour -= thePlayer->damage; if(thePlayer->armour > 0) { SetHealthbar(&theBoxes[player], thePlayer->armour); // Update healthbar if((thePlayer->armour)<(thePlayer->maxarmour/4))//health below 25% of max? { theBoxes[player].gsBoxHandler.r = 154;//turn healthbar red theBoxes[player].gsBoxHandler.g = 10; theBoxes[player].gsBoxHandler.b = 0; } } if(thePlayer->armour <= 0)// if no health, player dies ( duh! ) { CreateObject(EXPLOSION, thePlayer->gsObjectCoord.coord.t[0], thePlayer->gsObjectCoord.coord.t[2]); CreateObject(SHRAPNEL, thePlayer->gsObjectCoord.coord.t[0], thePlayer->gsObjectCoord.coord.t[2]); CreateObject(LG_RING, thePlayer->gsObjectCoord.coord.t[0], thePlayer->gsObjectCoord.coord.t[2]); PlaySFX(&bang2); theTank[thePlayer->damagedBy].score ++; theSprites[13].display = thePlayer->damagedBy; theSprites[13].id = 70; InitialiseSprite(KILLTXT_TIM, &theSprites[13].sprite, -40, -48); //theSprites[13].sprite.u = 0; theSprites[13].sprite.v = 32; if(theTank[thePlayer->damagedBy].armour == theTank[thePlayer->damagedBy].maxarmour) { theSprites[14].display = thePlayer->damagedBy; theSprites[14].id = 90; InitialiseSprite(PERFECT_TIM, &theSprites[14].sprite, -40, 0); theSprites[14].sprite.u = 0; theSprites[14].sprite.v = 72; PlaySFX(&ping); } RestartPlayer(thePlayer,thePlayersTurret); } thePlayer->damage = 0; } if(theSprites[13].id > 0) CheckAwardText(&theSprites[13]); if(theSprites[14].id > 0) CheckAwardText(&theSprites[14]); if((thePlayer->score >= MAX_NO_OF_KILLS)&&(theSprites[13].id == 0)&&(theSprites[14].id == 0)) { setVictory = 1; whoWon = player; } if(counter % 2) { SetMinimap(); InitialiseSprite(MINIMAP_TIM, &theSprites[2].sprite, -119, -119); // 200, -32 } } //*********************************************************** // CheckAwardText // Checks incidental text sprites eg. victory, perfect, etc. // //*********************************************************** void CheckAwardText (SpriteStructType0 *theSprite) { if(theSprite->id > 20) { //InitialiseSprite(KILLTXT_TIM, &theSprites[13].sprite, -40, -20); //theSprites[13].sprite.u = 32; //theSprite->sprite.v = 32; theSprite->sprite.attribute = theSprite->sprite.attribute | (1 << 28); theSprite->sprite.attribute = theSprite->sprite.attribute ^ (1 << 28); theSprite->sprite.attribute = theSprite->sprite.attribute | (1 << 29); theSprite->sprite.attribute = theSprite->sprite.attribute ^ (1 << 29); theSprite->sprite.attribute = theSprite->sprite.attribute | (1 << 30); theSprite->sprite.attribute = theSprite->sprite.attribute ^ (1 << 30); } else { if(theSprite->id > 10) { //InitialiseSprite(KILLTXT_TIM, &theSprites[13].sprite, -40, -20); //theSprites[13].sprite.u = 0; //theSprite->sprite.v = 32; theSprite->sprite.attribute = theSprite->sprite.attribute | (1 << 30); } else { if(theSprite->id > 0) { //InitialiseSprite(KILLTXT_TIM, &theSprites[13].sprite, -40, -20); //theSprites[13].sprite.u = 0; //theSprite->sprite.v = 32; theSprite->sprite.attribute = theSprite->sprite.attribute | (1 << 28); theSprite->sprite.attribute = theSprite->sprite.attribute | (1 << 29); theSprite->sprite.attribute = theSprite->sprite.attribute | (1 << 30); } } } theSprite->id --; } //*********************************************************** // FireBullet // Initialises a bullet for the player // subtype in theTurret holds the type of projectile //*********************************************************** void FireBullet (int creator) { int type; type = theTurret[creator].subtype; CreateObject(type, creator, 0); } //*********************************************************** // MakeSemiTrans // Sets the semi-transparent bit of a model //*********************************************************** void MakeSemiTrans (ObjectStructType0 *theObject) { theObject->gsObjectHandler.attribute = theObject->gsObjectHandler.attribute | (1 << 30); } //*********************************************************** // TestObjectCollision // Tests whether object collides with an occupied cell in the // buildings array and sets theObject->collision to // false - no collision or true - collision //*********************************************************** void TestObjectCollision (ObjectStructType0 *theObject) { int tx; int tz; int n; //char world; char bldgs; long dist; int check; int type; int x2; int z2; int x1 = theObject->gsObjectCoord.coord.t[0]; int z1 = theObject->gsObjectCoord.coord.t[2]; FindTilePosition(theObject); tx = theObject->tileposx; tz = theObject->tileposz; type = theObject->id; //world = worldGroundData[tx][tz]; bldgs = BldgWorldData[tx][tz]; // Tank collision check // Check collision with a tank of other allegiance than the object for (n = 0; n < (2+NO_OF_BOTS); n++) { x2 = theTank[n].gsObjectCoord.coord.t[0]; z2 = theTank[n].gsObjectCoord.coord.t[2]; if (theTank[n].allegance != theObject->allegance) { if (theTank[n].alive) { dist = FINDRANGE(x1,z1,x2,z2);// findrange between object & tank //printf("range: %d \n",dist); check = CheckInRange(dist, 400, theObject->size); if (check)// less than 900 squared, removes need for slow sqrt { theTank[n].damage += theObject->shotPower; //give damage theTank[n].damagedBy = theObject->allegance; //flag who damaged who theObject->collision = true; if(type == LIGHTNING) { CreateObject(SHOCK,n,0); CreateObject(SHRAPNEL,x1,z1); } if((type == LASER_BOLT) || (type == RAIL_RING)) { CreateObject(SM_RING,x1,z1); } if((type == LASER_BOLT) || (type == MISSILE)) { CreateObject(EXPLOSION,x1,z1); PlaySFX(&bang2); } if((type == RAIL_RING) || (type == LIGHTNING)|| (type == SHELL)) { CreateObject(SHRAPNEL,x1,z1); PlaySFX(&bang2); } return; } } } } if ((tx > MAX_X) || (tx < 0) || (tz > MAX_Z) || (tz < 0)) { theObject->collision = true; return; } if (bldgs != '0') { x2 = tx * SEPERATION; // work out center of tile on x axis z2 = tz * SEPERATION; // work out center of tile on z axis dist = FINDRANGE(x1,z1,x2,z2);// findrange between object & bldg //Call CheckBuildingCollision which returns a 1(collision) or 0(none) theObject->collision = CheckBuildingCollision(theObject, bldgs, dist, theObject->size); // make buildings indestructible for now, so collision is 1 if(theObject->collision == 1) { if((type == RAIL_RING) || (type == LIGHTNING) || (type == LASER_BOLT) || (type == MISSILE)) { CreateObject(SHRAPNEL,x1,z1); CreateObject(EXPLOSION,x1,z1); } } return; } // if clear ground and no buildings set collision to 0 theObject->collision = false; return; } //*********************************************************** // CheckInRange // returns a collision in a radius //*********************************************************** unsigned char CheckInRange (int Range,int TargetRange, int ObjectRange) { long TempTargetRange;// use a local variable, faster & use a long for safety TempTargetRange = TargetRange; TempTargetRange += ObjectRange; TempTargetRange = (TempTargetRange * TempTargetRange); if (Range < TempTargetRange) return true; return false; } //*********************************************************** // CheckBuildingCollision // Checks more detailed collision in object's grid cell // Sets size of bldg according to type then calls range check //*********************************************************** unsigned char CheckBuildingCollision (ObjectStructType0 *theObject, char BuildingType, int Range, int ObjectRange) { int CollisionFlag; int BldgSize; CollisionFlag = 0; BldgSize = 0; switch (BuildingType) { //Buildings case 'b': //bunker BldgSize = 450; break; case 'R': //radar dish BldgSize = 300; break; case 'l': //light pole BldgSize = 25; break; /*case 'T'://trees { BldgSize = 200; break; }*/ case 'C': //coms center BldgSize = 400; break; case 'P': //power station BldgSize = 400; break; //Objects case 'A': //Armour if (theObject->id == TANK) { if (theObject->armour < (theObject->maxarmour - 40)) theObject->damage -= 40; else theObject->damage -= (theObject->maxarmour - theObject->armour); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; PlaySFX(&pickup); } CollisionFlag = 0; return CollisionFlag; break; case '2': //Railgun if (theObject->id == TANK) { SetTurretType (&theTurret[theObject->allegance], RAILGUN); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; InitialiseSprite (RAILGUN_TIM, &theSprites[theObject->allegance].sprite, 70, 70); theSprites[theObject->allegance].id = RAILGUN; PlaySFX(&pickup); } BldgSize = 1; break; case '3': //Laser cannon if (theObject->id == TANK) { SetTurretType(&theTurret[theObject->allegance], LASER_CANNON); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; InitialiseSprite(LASERGUN_TIM, &theSprites[theObject->allegance].sprite, 70, 70); theSprites[theObject->allegance].id = LASER_CANNON; PlaySFX(&pickup); } BldgSize = 1; break; case '4': //Flamethrower if (theObject->id == TANK) { SetTurretType(&theTurret[theObject->allegance], FLAMETHROWER); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; InitialiseSprite(FLAMER_TIM, &theSprites[theObject->allegance].sprite, 70, 70); theSprites[theObject->allegance].id = FLAMETHROWER; } BldgSize = 1; break; case '5': //Tazer cannon if (theObject->id == TANK) { SetTurretType(&theTurret[theObject->allegance], TAZER_CANNON); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; InitialiseSprite(TAZERGUN_TIM, &theSprites[theObject->allegance].sprite, 70, 70); theSprites[theObject->allegance].id = TAZER_CANNON; PlaySFX(&pickup); } BldgSize = 1; break; case '6': //Missile Launcher if (theObject->id == TANK) { SetTurretType(&theTurret[theObject->allegance], MISSILE_LAUNCHER); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; InitialiseSprite(MISLCHR_TIM, &theSprites[theObject->allegance].sprite, 70, 70); theSprites[theObject->allegance].id = MISSILE_LAUNCHER; PlaySFX(&pickup); } BldgSize = 1; break; case 'W': //teleport if (theObject->id == TANK) { AddPowerup(theObject, TELEPORT); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; UpdatePowerup(theObject); PlaySFX(&ping); } BldgSize = 1; break; case 'X': //shield if (theObject->id == TANK) { AddPowerup(theObject, SHIELD); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; UpdatePowerup(theObject); PlaySFX(&ping); } BldgSize = 1; break; case 'Y': //emp-shock if (theObject->id == TANK) { AddPowerup(theObject, EMP_SHOCK); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; UpdatePowerup(theObject); PlaySFX(&ping); } BldgSize = 1; break; case 'Z': //invisibility if (theObject->id == TANK) { AddPowerup(theObject, INVISIBILITY); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; UpdatePowerup(theObject); PlaySFX(&ping); } BldgSize = 1; break; case 'S': //speedup if (theObject->id == TANK) { AddPowerup(theObject, SPEEDUP); PowerupCounter--; BldgWorldData[theObject->tileposx][theObject->tileposz] = '0'; UpdatePowerup(theObject); PlaySFX(&ping); } BldgSize = 1; break; } //end of switch CollisionFlag = CheckInRange(Range, BldgSize, ObjectRange); return CollisionFlag; } //*********************************************************** // SetTurretType // Initialises new turret type //*********************************************************** void SetTurretType (ObjectStructType0 *theObject,int type) { SVECTOR TempRotate; TempRotate = theObject->rotation; switch (type) { case RAILGUN: InitialiseObject(theObject,TURRET, 3, 3, 60,400, 0, 0, RAIL_RING, 10,theObject->allegance, 40, 20); AddModelToObject(theObject, theObject->gsObjectCoord.coord.t[0], -20, theObject->gsObjectCoord.coord.t[2],(unsigned long *)TURRET2_TMD); theObject->rotation = TempRotate; RotateModel (&theObject->gsObjectCoord,&theObject->rotation, 0, 0, 0); InitialiseSprite(RAILGUN_TIM, &theSprites[theObject->allegance].sprite, 70, 70); // 200, -32 theSprites[theObject->allegance].depth = 2; theSprites[theObject->allegance].id = RAILGUN; break; case LASER_CANNON: InitialiseObject(theObject,TURRET, 3, 3, 30, 900, 0, 0, LASER_BOLT, 15,theObject->allegance, 25, 10); AddModelToObject(theObject, theObject->gsObjectCoord.coord.t[0], -20, theObject->gsObjectCoord.coord.t[2],(unsigned long *)TURRET3_TMD); theObject->rotation = TempRotate; RotateModel (&theObject->gsObjectCoord,&theObject->rotation, 0, 0, 0); InitialiseSprite(LASERGUN_TIM, &theSprites[theObject->allegance].sprite, 70, 70); // 200, -32 theSprites[theObject->allegance].depth = 2; theSprites[theObject->allegance].id = LASER_CANNON; break; case FLAMETHROWER: InitialiseObject(theObject,TURRET, 3, 3, 50, 140, 0, 0, FLAME, 6,theObject->allegance, 4, 2); AddModelToObject(theObject, theObject->gsObjectCoord.coord.t[0], -20, theObject->gsObjectCoord.coord.t[2],(unsigned long *)TURRET4_TMD); theObject->rotation = TempRotate; RotateModel (&theObject->gsObjectCoord,&theObject->rotation, 0, 0, 0); InitialiseSprite(FLAMER_TIM, &theSprites[theObject->allegance].sprite, 70, 70); // 200, -32 //theSprites[theObject->allegance].sprite.attribute & (1<<30); //theSprites[theObject->allegance].sprite.attribute ^ (1<<30); theSprites[theObject->allegance].depth = 2; theSprites[theObject->allegance].id = FLAMETHROWER; break; case TAZER_CANNON: InitialiseObject(theObject,TURRET, 3, 3, 50, 900, 0, 0, LIGHTNING, 5,theObject->allegance, 10, 6); AddModelToObject(theObject, theObject->gsObjectCoord.coord.t[0], -20, theObject->gsObjectCoord.coord.t[2],(unsigned long *)TAZERTUR_TMD); theObject->rotation = TempRotate; RotateModel (&theObject->gsObjectCoord,&theObject->rotation, 0, 0, 0); InitialiseSprite(LASERGUN_TIM, &theSprites[theObject->allegance].sprite, 70, 70); // 200, -32 theSprites[theObject->allegance].depth = 2; theSprites[theObject->allegance].id = TAZER_CANNON; break; case MISSILE_LAUNCHER: InitialiseObject(theObject,TURRET, 3, 3, 50, 400, 0, 0, MISSILE, 1600,theObject->allegance, 30, 15); AddModelToObject(theObject, theObject->gsObjectCoord.coord.t[0], -20, theObject->gsObjectCoord.coord.t[2],(unsigned long *)MISLCHR_TMD); theObject->rotation = TempRotate; RotateModel (&theObject->gsObjectCoord,&theObject->rotation, 0, 0, 0); InitialiseSprite(MISLCHR_TIM, &theSprites[theObject->allegance].sprite, 70, 70); // 200, -32 theSprites[theObject->allegance].depth = 2; theSprites[theObject->allegance].id = MISSILE_LAUNCHER; break; } } //*********************************************************** // SetChassisType // Initialises new turret type // currently unused in the game //*********************************************************** void SetChassisType (ObjectStructType0 *theObject, int type) { SVECTOR TempRotate; TempRotate = theObject->rotation; switch (type) { case WHEELED: //InitialiseObject(theObject,TANK, 3, 3, 100,400, 0, 0, RAIL_RING, 10,theObject->allegance, 0, 20); //AddModelToObject(theObject, theObject->gsObjectCoord.coord.t[0], -20, // theObject->gsObjectCoord.coord.t[2],(unsigned long *)TURRET2_TMD); //theObject->rotation = TempRotate; //RotateModel (&theObject->gsObjectCoord,&theObject->rotation,0,0,-0); break; case HOVERCRAFT: //InitialiseObject(theObject,TANK, 3, 3, 50, 900, 0, 0, LASER_BOLT, 15,theObject->allegance, 0, 10); //AddModelToObject(theObject, theObject->gsObjectCoord.coord.t[0], -20, // theObject->gsObjectCoord.coord.t[2],(unsigned long *)TURRET3_TMD); //theObject->rotation = TempRotate; //RotateModel (&theObject->gsObjectCoord,&theObject->rotation,0,0,-0); break; } } //*********************************************************** // SetHealthbar // Initialises box type healthbar //*********************************************************** void SetHealthbar(BoxStructType0 *theBox, int length) { theBox->gsBoxHandler.x = -115; theBox->gsBoxHandler.y = 110; theBox->gsBoxHandler.w = length; theBox->gsBoxHandler.h = 4; theBox->gsBoxHandler.r = 154; //set to that dull orange colour of the icons theBox->gsBoxHandler.g = 100; theBox->gsBoxHandler.b = 0; theBox->depth = 2; theBox->gsBoxHandler.attribute = theBox->gsBoxHandler.attribute & (1<<30); //make semi-transparent } //*********************************************************** // AddPowerup // Initialises box type healthbar //*********************************************************** void AddPowerup(ObjectStructType0 *theObject, int type) { int n; int player; player = theObject->allegance; n = 0; //for(n = 0;n < 3;n++) //{ if(TankPowerups[player].powerupcounter < 3)// check for empty slot for special { TankPowerups[player].poweruplist[TankPowerups[player].powerupcounter] = type; type = 0; TankPowerups[player].powerupcounter++; } //} if(type != 0)//dump special #3 and relplace with collected special { TankPowerups[player].poweruplist[2] = type; } } //*********************************************************** // UsePowerup // Initialises box type healthbar //*********************************************************** void UsePowerup(ObjectStructType0 *theObject) { int n; int type; int player; int place; place = 99; player = theObject->allegance; for(n=0;n<3;n++)//find free active powerup space { if((TankPowerups[player].poweruptype[n] == 0) && (place == 99))// find free active powerup type { place = n; } } if(place == 99) return;// if 3 specials active then can't use one now so return type = TankPowerups[player].poweruplist[0]; switch(type) { case TELEPORT: //jumps player to random position, leaving and creating a beam effect CreateObject(TELEPORT, player, 0); FindFreeTilePos(theObject);//choose random teleport point theTurret[player].gsObjectCoord.coord.t[0] = theObject->gsObjectCoord.coord.t[0]; theTurret[player].gsObjectCoord.coord.t[1] = theObject->gsObjectCoord.coord.t[1]; theTurret[player].gsObjectCoord.coord.t[2] = theObject->gsObjectCoord.coord.t[2]; theTurret[player].gsObjectCoord.flg = 0; theTank[player].gsObjectCoord.flg = 0; CreateObject(TELEPORT, player, 0); CreateObject(LG_RING, theObject->gsObjectCoord.coord.t[0], theObject->gsObjectCoord.coord.t[2]); break; case SHIELD: //need shield semi-trans object over tank TankPowerups[player].powerup[place] = 150; TankPowerups[player].poweruptype[place] = type; CreateObject(SM_RING, theObject->gsObjectCoord.coord.t[0], theObject->gsObjectCoord.coord.t[2]); break; case EMP_SHOCK: //need some sort of blast effect, possibly brighten both screens up & down CreateObject(SHOCK, 1-player, 0); TankPowerups[player].powerup[place] = 150; TankPowerups[player].poweruptype[place] = type; CreateObject(LG_RING, theObject->gsObjectCoord.coord.t[0], theObject->gsObjectCoord.coord.t[2]); break; case INVISIBILITY: theObject->display = player; TankPowerups[player].powerup[place] = 150; TankPowerups[player].poweruptype[place] = type; CreateObject(SM_RING, theObject->gsObjectCoord.coord.t[0], theObject->gsObjectCoord.coord.t[2]); break; case SPEEDUP: theObject->display = player; TankPowerups[player].powerup[place] = 200; TankPowerups[player].poweruptype[place] = type; CreateObject(SM_RING, theObject->gsObjectCoord.coord.t[0], theObject->gsObjectCoord.coord.t[2]); break; }// end of switch TankPowerups[player].poweruplist[0] = TankPowerups[player].poweruplist[1];// shunt powerups down TankPowerups[player].poweruplist[1] = TankPowerups[player].poweruplist[2]; TankPowerups[player].poweruplist[2] = 0; TankPowerups[player].powerupcounter--; if(TankPowerups[player].powerupcounter < 0) TankPowerups[player].powerupcounter = 0;// to catch a -1 value error UpdatePowerup(theObject); } //*********************************************************** // UpdatePowerup // Initialises box type healthbar //*********************************************************** void UpdatePowerup(ObjectStructType0 *theObject) { int n; int pos; int sppos; //int alleg; int player; n = 0; pos = 0; sppos = 0; player = theObject->allegance; for(n = 0;n < 3;n++) { pos = 3 + (player*3) + n; if(TankPowerups[player].poweruplist[n] > 0) { sppos = 70-(n*40); //TELEPORT: if(TankPowerups[player].poweruplist[n] == TELEPORT){ InitialiseSprite(TELEPICN_TIM, &theSprites[pos].sprite, -119, sppos); } else { //SHIELD: if(TankPowerups[player].poweruplist[n] == SHIELD){ InitialiseSprite(SHLDICN_TIM, &theSprites[pos].sprite, -119, sppos); } else { //EMP_SHOCK: if(TankPowerups[player].poweruplist[n] == EMP_SHOCK){ InitialiseSprite(EMPSICN_TIM, &theSprites[pos].sprite, -119, sppos); } else { //INVISIBILITY: if(TankPowerups[player].poweruplist[n] == INVISIBILITY){ InitialiseSprite(INVISICN_TIM, &theSprites[pos].sprite, -119, sppos); } else { //SPEEDUP: if(TankPowerups[player].poweruplist[n] == SPEEDUP){ InitialiseSprite(SPEEDUP_TIM, &theSprites[pos].sprite, -119, sppos); theSprites[pos].sprite.u = 32; } }// close else statement }// close else statement }// close else statement }// close else statement theSprites[pos].id = TankPowerups[player].poweruplist[n]; theSprites[pos].display = player; theSprites[pos].depth = 2; } else theSprites[pos].id = 0; } }