#include "Enemies.h" #include "WorldManager.h" #include "SoundManager.h" #include #define EnemySpeed 0.001 static void EnemyCheckCollisions(VEnemy * e, VWorld * w) { VObjectWrapper * objectList; VObject * object; float shields; Vector wall; Boolean wasHit = 0; for (objectList = w->Objects; objectList != NULL; objectList = objectList->next) { if (objectList->Type != VENEMY && objectList->Type != VOBJECT) continue; if (objectList->Type == VENEMY && e == objectList->e) continue; WObjectObject(objectList, &object); if (object != NULL && fabs(((e->Object.Position.x - object->Position.x) * (e->Object.Position.x - object->Position.x)) + ((e->Object.Position.y - object->Position.y) * (e->Object.Position.y - object->Position.y)) + ((e->Object.Position.z - object->Position.z) * (e->Object.Position.z - object->Position.z))) <= (e->Object.Radius + object->Radius)) { wasHit = 1; if (objectList->Type == VENEMY) { shields = objectList->e->Shields; HitEnemy(objectList->e, e->Shields); HitEnemy(e, shields); if (objectList->e->Shields <= 0) { objectList->taggedForRemoval = true; objectList->exploded = 1; } else { objectList->exploded = 2; } } else { shields = objectList->o->Durability; objectList->o->Durability -= e->Shields; e->Shields -= shields; if (objectList->o->Durability <= 0) { objectList->taggedForRemoval = true; objectList->exploded = 1; } else { objectList->exploded = 2; } } break; } } if (fabs(((e->Object.Position.x - w->Camera.Position.x) * (e->Object.Position.x - w->Camera.Position.x)) + ((e->Object.Position.y - w->Camera.Position.y) * (e->Object.Position.y - w->Camera.Position.y)) + ((e->Object.Position.z - w->Camera.Position.z) * (e->Object.Position.z - w->Camera.Position.z))) <= (e->Object.Radius + PLAYERSHIPRADIUS) && w->Player.Shields > 0) { wasHit = 1; shields = w->Player.Shields; DamagePlayer(w, e->Shields); HitEnemy(e, shields); } if (!InBounds(w, &e->Object.Position, sqrt(e->Object.Radius), &wall)) { if (wall.x) { e->Physics.Momentum.x = -e->Physics.Momentum.x; e->Object.Front.x = -e->Object.Front.x; } else if (wall.y) { e->Physics.Momentum.y = -e->Physics.Momentum.y; e->Object.Front.y = -e->Object.Front.y; } else if (wall.z) { e->Physics.Momentum.z = -e->Physics.Momentum.z; e->Object.Front.z = -e->Object.Front.z; } CrossProduct(&e->Object.Front, &e->Object.Right, &e->Object.Up); CrossProduct(&e->Object.Up, &e->Object.Front, &e->Object.Right); NormalizeVector(&e->Object.Right); NormalizeVector(&e->Object.Up); PlaySound(GetSoundManager(), IMPACTSOUND); wasHit = 1; HitEnemy(e, VectorMagnitude(&e->Physics.Momentum) * 1000); } if (wasHit) { VObjectWrapper * anotherObject; anotherObject = GetWrapperByEnemy(w->Objects, e); if (anotherObject != NULL) { if (e->Shields <= 0) { anotherObject->exploded = 1; anotherObject->taggedForRemoval = 1; } else { anotherObject->exploded = 2; } } } } static void RepelEnemy(VEnemy * e, void * world, float Speed) { VObjectWrapper * objectList; VObject * object; VWorld * w; Vector Angle; int RoomPosX, RoomPosY, RoomPosZ; w = (VWorld *)world; for (objectList = w->Objects; objectList != NULL; objectList = objectList->next) { if (objectList->Type != VENEMY || e == objectList->e) continue; WObjectObject(objectList, &object); if ((((object->Position.x - e->Object.Position.x) * (object->Position.x - e->Object.Position.x)) + ((object->Position.y - e->Object.Position.y) * (object->Position.y - e->Object.Position.y)) + ((object->Position.z - e->Object.Position.z) * (object->Position.z - e->Object.Position.z))) < (ENEMYAVOIDRADIUS + e->Object.Radius)) { e->Object.Front.x += object->Front.x * Speed; e->Object.Front.y += object->Front.y * Speed; e->Object.Front.z += object->Front.z * Speed; SubtractVector(&e->Object.Position, &object->Position, &Angle); NormalizeVector(&Angle); Angle.x *= Speed; Angle.y *= Speed; Angle.z *= Speed; AddVector(&Angle, &e->Object.Front, &e->Object.Front); NormalizeVector(&e->Object.Front); CrossProduct(&e->Object.Front, &e->Object.Right, &e->Object.Up); CrossProduct(&e->Object.Up, &e->Object.Front, &e->Object.Right); NormalizeVector(&e->Object.Right); NormalizeVector(&e->Object.Up); } } RoomPosX = (e->Object.Position.x / 40); RoomPosY = (e->Object.Position.y / 40); RoomPosZ = (e->Object.Position.z / 40); Angle.x = Angle.y = Angle.z = 0.0; if ((RoomPosX >= (w->Level.SizeX - 1) || !w->Level.Cells[((RoomPosY * (w->Level.SizeX * w->Level.SizeZ)) + (RoomPosZ * w->Level.SizeX) + (RoomPosX + 1))]) && (((int) e->Object.Position.x % 40) * ((int) e->Object.Position.x % 40) > ((40 * 40) - (ENEMYAVOIDRADIUS + e->Object.Radius)))) { if (e->Object.Front.z < 0.0) Angle.z -= 1.0; else Angle.z += 1.0; Angle.x -= 1.5; } else if ((RoomPosX <= 0 || !w->Level.Cells[((RoomPosY * (w->Level.SizeX * w->Level.SizeZ)) + (RoomPosZ * w->Level.SizeX) + (RoomPosX - 1))]) && (((int) e->Object.Position.x % 40) * ((int) e->Object.Position.x % 40) < (ENEMYAVOIDRADIUS + e->Object.Radius))) { if (e->Object.Front.z < 0.0) Angle.z -= 1.0; else Angle.z += 1.0; Angle.x += 1.5; } if ((RoomPosZ >= (w->Level.SizeZ - 1) || !w->Level.Cells[((RoomPosY * (w->Level.SizeX * w->Level.SizeZ)) + ((RoomPosZ + 1) * w->Level.SizeX) + RoomPosX)]) && (((int) e->Object.Position.z % 40) * ((int) e->Object.Position.z % 40) > ((40 * 40) - (ENEMYAVOIDRADIUS + e->Object.Radius)))) { if (e->Object.Front.x < 0.0) Angle.x -= 1.0; else Angle.x += 1.0; Angle.z -= 1.5; } else if ((RoomPosZ <= 0 || !w->Level.Cells[((RoomPosY * (w->Level.SizeX * w->Level.SizeZ)) + ((RoomPosZ - 1) * w->Level.SizeX) + RoomPosX)]) && (((int) e->Object.Position.z % 40) * ((int) e->Object.Position.z % 40) < (ENEMYAVOIDRADIUS + e->Object.Radius))) { if (e->Object.Front.x < 0.0) Angle.x -= 1.0; else Angle.x += 1.0; Angle.z += 1.5; } if ((RoomPosY >= (w->Level.SizeY - 1) || !w->Level.Cells[(((RoomPosY + 1) * (w->Level.SizeX * w->Level.SizeZ)) + (RoomPosZ * w->Level.SizeX) + RoomPosX)]) && (((int) e->Object.Position.y % 40) * ((int) e->Object.Position.y % 40) > ((40 * 40) - (ENEMYAVOIDRADIUS + e->Object.Radius)))) { if (e->Object.Front.z < 0.0) Angle.z -= 1.0; else Angle.z += 1.0; Angle.y -= 1.5; } else if ((RoomPosY <= 0 || !w->Level.Cells[(((RoomPosY - 1) * (w->Level.SizeX * w->Level.SizeZ)) + (RoomPosZ * w->Level.SizeX) + RoomPosX)]) && (((int) e->Object.Position.y % 40) * ((int) e->Object.Position.y % 40) < (ENEMYAVOIDRADIUS + e->Object.Radius))) { if (e->Object.Front.z < 0.0) Angle.z -= 1.0; else Angle.z += 1.0; Angle.y += 1.5; } //NormalizeVector(&Angle); //Angle.x *= Speed; //Angle.y *= Speed; //Angle.z *= Speed; AddVector(&Angle, &e->Object.Front, &e->Object.Front); NormalizeVector(&e->Object.Front); CrossProduct(&e->Object.Front, &e->Object.Right, &e->Object.Up); CrossProduct(&e->Object.Up, &e->Object.Front, &e->Object.Right); NormalizeVector(&e->Object.Right); NormalizeVector(&e->Object.Up); } void DumbShooterAI(void * Enemy, AIEvent Event, float interval) { VEnemy * e; VWorld * w; Vector Angle; e = (VEnemy *) Enemy; switch (Event) { case AIEventRun: break; case AIEventCopyData: e->next->Data = e->Data; return; default: return; } w = (VWorld *) e->Data; if (fabs( ((e->Object.Position.x - w->Camera.Position.x) * (e->Object.Position.x - w->Camera.Position.x) + (e->Object.Position.y - w->Camera.Position.y) * (e->Object.Position.y - w->Camera.Position.y) + (e->Object.Position.z - w->Camera.Position.z) * (e->Object.Position.z - w->Camera.Position.z)) < DUMBSHOOTERACTIVATIONRANGE)) { SubtractVector(&w->Camera.Position, &e->Object.Position, &Angle); NormalizeVector(&Angle); Angle.x *= DUMBSHOOTERROTSPEED / interval; Angle.y *= DUMBSHOOTERROTSPEED / interval; Angle.z *= DUMBSHOOTERROTSPEED / interval; AddVector(&e->Object.Front, &Angle, &e->Object.Front); NormalizeVector(&e->Object.Front); CrossProduct(&e->Object.Front, &e->Object.Right, &e->Object.Up); CrossProduct(&e->Object.Up, &e->Object.Front, &e->Object.Right); NormalizeVector(&e->Object.Right); NormalizeVector(&e->Object.Up); if(fabs( ((e->Object.Position.x - w->Camera.Position.x) * (e->Object.Position.x - w->Camera.Position.x) + (e->Object.Position.y - w->Camera.Position.y) * (e->Object.Position.y - w->Camera.Position.y) + (e->Object.Position.z - w->Camera.Position.z) * (e->Object.Position.z - w->Camera.Position.z)) > DUMBSHOOTERSHOOTRANGE)) { RepelEnemy(e, w, DUMBSHOOTERROTSPEED / interval); Angle = e->Object.Front; NormalizeVector(&Angle); Angle.x *= DUMBSHOOTERMOVESPEED / interval; Angle.y *= DUMBSHOOTERMOVESPEED / interval; Angle.z *= DUMBSHOOTERMOVESPEED / interval; AddVector(&e->Object.Position, &Angle, &e->Object.Position); } else { e->Idle += (1.0 / interval); if(e->Idle > DUMBSHOOTERSHOOTSPEED) { VWeapon * theWeapon; VObjectWrapper * theWObject; e->Idle = 0; theWeapon = (VWeapon *) NewPtr(sizeof(VWeapon)); if (theWeapon != NULL) { PlaySound(GetSoundManager(), ENEMYSHOTSOUND); InitWeapon(theWeapon, WEAPONTYPEBULLET, 0); AllocateWObject(&theWObject); theWObject->w = theWeapon; theWObject->Type = VWEAPON; theWObject->next = w->Objects; if (w->Objects != NULL) w->Objects->previous = theWObject; w->Objects = theWObject; StartWeapon(theWeapon, &e->Object.Position, 0.0, &e->Object.Front, &e->Object.Up); theWeapon->Speed = BULLETSPEED / 2; } } } } EnemyCheckCollisions(e, w); } void KamikazeAI(void * Enemy, AIEvent Event, float interval) { VEnemy * e; VWorld * w; Vector Angle, Axis; float acceleration; Quaternion Quat; e = (VEnemy *) Enemy; switch (Event) { case AIEventRun: break; case AIEventCopyData: e->next->Data = e->Data; return; default: return; } w = (VWorld *) e->Data; SubtractVector(&w->Camera.Position, &e->Object.Position, &Angle); NormalizeVector(&Angle); /* The more directly the enemy faces the player, the more they accelerate. */ acceleration = ((e->Object.Front.x * Angle.x) + (e->Object.Front.y * Angle.y) + (e->Object.Front.z * Angle.z)); if (acceleration < 0.0) acceleration = 0.0; /* Cube acceleration */ acceleration *= (acceleration * acceleration); CrossProduct(&e->Object.Front, &Angle, &Axis); QuaternionRotateVector(KAMIKAZEROTSPEED, interval, &Axis, &e->Object.Front, &Quat); e->Object.Front.x = Quat.v.x; e->Object.Front.y = Quat.v.y; e->Object.Front.z = Quat.v.z; NormalizeVector(&e->Object.Front); CrossProduct(&e->Object.Front, &e->Object.Right, &e->Object.Up); CrossProduct(&e->Object.Up, &e->Object.Front, &e->Object.Right); NormalizeVector(&e->Object.Right); NormalizeVector(&e->Object.Up); if (fabs( ((e->Object.Position.x - w->Camera.Position.x) * (e->Object.Position.x - w->Camera.Position.x) + (e->Object.Position.y - w->Camera.Position.y) * (e->Object.Position.y - w->Camera.Position.y) + (e->Object.Position.z - w->Camera.Position.z) * (e->Object.Position.z - w->Camera.Position.z)) < KAMIKAZERANGE)) { RepelEnemy(e, w, KAMIKAZEROTSPEED / interval); Angle = e->Object.Front; NormalizeVector(&Angle); Angle.x *= ((SHIPACCELERATION / interval) * acceleration); Angle.y *= ((SHIPACCELERATION / interval) * acceleration); Angle.z *= ((SHIPACCELERATION / interval) * acceleration); PushShip(&e->Physics, &Angle); } e->Shields *= 5; /* Kamikaze ships do 5 times the damage as they have shield */ EnemyCheckCollisions(e, w); if (e->Shields >= 5) e->Shields /= 5; } void SmartShooterAI(void * Enemy, AIEvent Event, float interval) { VEnemy * e; VWorld * w = NULL; SmartShooterData * data; Vector Angle, Axis; float acceleration; Quaternion Quat; switch (Event) { case AIEventInit: e = (VEnemy *) Enemy; w = (VWorld *) e->Data; /* Allocate a SmartShooterData and link it into Enemy->Data */ data = (SmartShooterData *) NewPtr(sizeof(SmartShooterData)); data->Data = e->Data; e->Data = data; /* Initialize the SmartShooterData */ data->State = SMARTSHOOTERSTATEFLY; data->Idle2 = 0.0; SubtractVector(&w->Camera.Position, &e->Object.Position, &Angle); NormalizeVector(&Angle); CrossProduct(&w->Camera.Up, &Angle, &data->Angle); if (Random() % 2) { /* Turn data->Angle from a right vector into an up vector */ NormalizeVector(&data->Angle); CrossProduct(&Angle, &data->Angle, &data->Angle); } if (Random() % 2) { data->Angle.x *= -1; data->Angle.y *= -1; data->Angle.z *= -1; } NormalizeVector(&data->Angle); break; case AIEventCleanUp: /* Dispose and unlink SmartShooterData */ e = (VEnemy *) Enemy; data = (SmartShooterData *) e->Data; DisposePtr(e->Data); e->Data = w; break; case AIEventCopyData: e = (VEnemy *) Enemy; /* Copy SmartShooterData to next->Data */ data = (SmartShooterData *) NewPtr(sizeof(SmartShooterData)); BlockMove(e->Data, data, sizeof(SmartShooterData)); e->next->Data = data; break; case AIEventRun: e = (VEnemy *) Enemy; data = (SmartShooterData *) e->Data; w = (VWorld *) data->Data; switch (data->State) { case SMARTSHOOTERSTATEFLY: data->Idle2 += (1.0 / interval); acceleration = ((e->Object.Front.x * data->Angle.x) + (e->Object.Front.y * data->Angle.y) + (e->Object.Front.z * data->Angle.z)); if (acceleration < 0.0) acceleration = 0.0; /* Cube acceleration */ acceleration *= (acceleration * acceleration); Angle = data->Angle; Angle.x *= (SMARTSHOOTERROTSPEED / interval); Angle.y *= (SMARTSHOOTERROTSPEED / interval); Angle.z *= (SMARTSHOOTERROTSPEED / interval); AddVector(&e->Object.Front, &Angle, &e->Object.Front); NormalizeVector(&e->Object.Front); CrossProduct(&e->Object.Front, &e->Object.Right, &e->Object.Up); CrossProduct(&e->Object.Up, &e->Object.Front, &e->Object.Right); NormalizeVector(&e->Object.Right); NormalizeVector(&e->Object.Up); RepelEnemy(e, w, SMARTSHOOTERROTSPEED); Angle = e->Object.Front; Angle.x *= ((SHIPACCELERATION / interval) * acceleration); Angle.y *= ((SHIPACCELERATION / interval) * acceleration); Angle.z *= ((SHIPACCELERATION / interval) * acceleration); PushShip(&e->Physics, &Angle); if (data->Idle2 > SMARTSHOOTERFLYTIME) { data->State = SMARTSHOOTERSTATESHOOT; data->Idle2 = 0.0; e->Idle = 0; } break; case SMARTSHOOTERSTATESHOOT: SubtractVector(&w->Camera.Position, &e->Object.Position, &Angle); NormalizeVector(&Angle); CrossProduct(&e->Object.Front, &Angle, &Axis); QuaternionRotateVector(KAMIKAZEROTSPEED, interval, &Axis, &e->Object.Front, &Quat); e->Object.Front.x = Quat.v.x; e->Object.Front.y = Quat.v.y; e->Object.Front.z = Quat.v.z; NormalizeVector(&e->Object.Front); CrossProduct(&e->Object.Front, &e->Object.Right, &e->Object.Up); CrossProduct(&e->Object.Up, &e->Object.Front, &e->Object.Right); NormalizeVector(&e->Object.Right); NormalizeVector(&e->Object.Up); StopShip(&e->Physics, ((SHIPACCELERATION / 2) / interval)); if (fabs( ((e->Object.Position.x - w->Camera.Position.x) * (e->Object.Position.x - w->Camera.Position.x) + (e->Object.Position.y - w->Camera.Position.y) * (e->Object.Position.y - w->Camera.Position.y) + (e->Object.Position.z - w->Camera.Position.z) * (e->Object.Position.z - w->Camera.Position.z)) < SMARTSHOOTERRANGE)) { e->Idle += (1.0 / interval); data->Idle2 += (1.0 / interval); } if (e->Idle > SMARTSHOOTERSHOOTSPEED) { VWeapon * theWeapon; VObjectWrapper * theWObject; e->Idle = 0; theWeapon = (VWeapon *) NewPtr(sizeof(VWeapon)); if (theWeapon != NULL) { PlaySound(GetSoundManager(), ENEMYSHOTSOUND); InitWeapon(theWeapon, WEAPONTYPEBULLET, 0); AllocateWObject(&theWObject); theWObject->w = theWeapon; theWObject->Type = VWEAPON; theWObject->next = w->Objects; if (w->Objects != NULL) w->Objects->previous = theWObject; w->Objects = theWObject; StartWeapon(theWeapon, &e->Object.Position, 0.0, &e->Object.Front, &e->Object.Up); theWeapon->Speed = BULLETSPEED / 2; } } if (data->Idle2 > SMARTSHOOTERSHOOTTIME) { data->State = SMARTSHOOTERSTATEFLY; data->Idle2 = 0.0; SubtractVector(&w->Camera.Position, &e->Object.Position, &Angle); NormalizeVector(&Angle); CrossProduct(&w->Camera.Up, &Angle, &data->Angle); if (Random() % 2) { /* Turn data->Angle from a right vector into an up vector */ NormalizeVector(&data->Angle); CrossProduct(&Angle, &data->Angle, &data->Angle); } if (Random() % 2) { data->Angle.x *= -1; data->Angle.y *= -1; data->Angle.z *= -1; } NormalizeVector(&data->Angle); } break; } EnemyCheckCollisions(e, w); break; } } void StationaryAI(void * Enemy, AIEvent Event, float interval) { VEnemy * e; VWorld * w; Vector Angle; e = (VEnemy *) Enemy; switch (Event) { case AIEventRun: break; case AIEventCopyData: e->next->Data = e->Data; return; default: return; } w = (VWorld *) e->Data; SubtractVector(&w->Camera.Position, &e->Object.Position, &Angle); NormalizeVector(&Angle); Angle.x *= STATIONARYSHOOTERROTSPEED / interval; Angle.y *= STATIONARYSHOOTERROTSPEED / interval; Angle.z *= STATIONARYSHOOTERROTSPEED / interval; AddVector(&e->Object.Front, &Angle, &e->Object.Front); NormalizeVector(&e->Object.Front); CrossProduct(&e->Object.Front, &e->Object.Right, &e->Object.Up); CrossProduct(&e->Object.Up, &e->Object.Front, &e->Object.Right); NormalizeVector(&e->Object.Right); NormalizeVector(&e->Object.Up); if(fabs( ((e->Object.Position.x - w->Camera.Position.x) * (e->Object.Position.x - w->Camera.Position.x) + (e->Object.Position.y - w->Camera.Position.y) * (e->Object.Position.y - w->Camera.Position.y) + (e->Object.Position.z - w->Camera.Position.z) * (e->Object.Position.z - w->Camera.Position.z)) < STATIONARYSHOOTERRANGE)) { e->Idle += (1.0 / interval); if(e->Idle > STATIONARYSHOOTERSHOOTSPEED) { VWeapon * theWeapon; VObjectWrapper * theWObject; e->Idle = 0; theWeapon = (VWeapon *) NewPtr(sizeof(VWeapon)); if (theWeapon != NULL) { PlaySound(GetSoundManager(), ENEMYSHOTSOUND); InitWeapon(theWeapon, WEAPONTYPEBULLET, 1); AllocateWObject(&theWObject); theWObject->w = theWeapon; theWObject->Type = VWEAPON; theWObject->next = w->Objects; if (w->Objects != NULL) w->Objects->previous = theWObject; w->Objects = theWObject; StartWeapon(theWeapon, &e->Object.Position, 0.0, &e->Object.Front, &e->Object.Up); theWeapon->Speed = BULLETSPEED / 2; } } } EnemyCheckCollisions(e, w); } void HitEnemy(VEnemy * e, int Damage) { e->Shields -= Damage; } void InitEnemy(VEnemy * e, void * Data) { e->Callback = DumbShooterAI; e->Data = Data; e->Idle = 0.0; e->next = NULL; e->taggedForRemoval = false; InitObject(&e->Object); BuildEnemyModel(&e->Object.Model); CalculateRadius(&e->Object); e->Object.Front.z = -1.0; e->Object.Position.z = -10.0; e->Object.Position.x = -2.0; e->Object.Position.y = -2.0; e->Shields = 5; InitPhysics(&e->Physics); e->Callback(e, AIEventInit, 1.0); } void SetEnemyAI(VEnemy * e, EnemyAIModule aiMod) { e->Callback(e, AIEventCleanUp, 1.0); e->Callback = aiMod; e->Callback(e, AIEventInit, 1.0); } void CleanUpEnemy(VEnemy * e) { e->Callback(e, AIEventCleanUp, 1.0); CleanUpObject(&e->Object); } void DrawEnemy(VEnemy * e) { DrawObject(&e->Object); } void RunEnemy(VEnemy * e, float interval) { e->Callback(e, AIEventRun, interval); RunPhysics(&e->Physics, &e->Object.Position, &e->Object.Front, &e->Object.Up, &e->Object.Right, interval); } void CopyEnemy(VEnemy * src, VEnemy * dest) { VEnemy * oldNext; oldNext = src->next; src->next = dest; src->Callback(src, AIEventCopyData, 1.0); src->next = oldNext; dest->Callback = src->Callback; CopyObject(&src->Object, &dest->Object); dest->Idle = src->Idle; dest->next = NULL; /* Setting up this list is up to the caller */ dest->taggedForRemoval = src->taggedForRemoval; dest->Physics = src->Physics; dest->Shields = src->Shields; } #pragma mark - #pragma mark (Bosses) #pragma mark - int NumBossShots(VBoss * b, Vector * Positions) { int Count = 0; struct VBossPart * ThePart; Positions = malloc(sizeof(Vector) * 10); for(ThePart = b->Parts; ThePart; ThePart = ThePart->next) if(ThePart->Functionality == Shoot) { Positions[Count] = ThePart->Object.Position; Count++; } realloc(Positions, sizeof(Vector) * Count); return Count; } Boolean BossCanMove(VBoss * b) { struct VBossPart * ThePart; for(ThePart = b->Parts; ThePart; ThePart = ThePart->next) if(ThePart->Functionality == BossMove) return true; return false; } Boolean IsBossAlive(VBoss * b) { struct VBossPart * ThePart; for(ThePart = b->Parts; ThePart; ThePart = ThePart->next) if(ThePart->Functionality == Live) return true; return false; } void RunBoss(VBoss * b) { VWorld * w; w = (VWorld *)b->Data; if(!IsBossAlive(b)) w->Finished = true; } void CleanUpBoss(VBoss * b) { struct VBossPart * next; while(b->Parts) { next = b->Parts->next; DisposePtr((Ptr)b->Parts); b->Parts = next; } } void InitBoss(VBoss * b, void * Data) { b->Level = -1; b->Shields = 0; b->Parts = NULL; b->Data = Data; } void RemoveBossObject(VBoss * b, VObject * o) { struct VBossPart * ThePart; struct VBossPart * Previous; ThePart = b->Parts; Previous = NULL; while(ThePart) { if(&ThePart->Object == o) { if(Previous) Previous->next = ThePart->next; else b->Parts = NULL; DisposePtr((Ptr)ThePart); ThePart = NULL; return; } Previous = ThePart; ThePart = ThePart->next; } } void LoadBoss(VBoss * b, int Level) { VWorld * w; w = (VWorld *)b->Data; if(b->Parts) CleanUpBoss(b); b->Level = Level; switch(Level) { case 1: /* b->Shields = 10; b->Parts = (struct VBossPart *)NewPtr(sizeof(struct VBossPart) * 4); InitObject(&b->Parts->Object); BuildEnemyModel(&b->Parts->Object.Model); b->Parts->Object.Position.x = 100; b->Parts->Object.Position.y = 60; b->Parts->Object.Position.z = 100; AllocateWObject(&w->Objects); w->Objects->Type = VOBJECT; w->Objects->o = &b->Parts->Object; b->Parts->next = NULL; b->Parts->Functionality = Live; */ b->Shields = 10; b->Parts = (struct VBossPart *)NewPtr(sizeof(struct VBossPart)); InitObject(&b->Parts->Object); BuildEnemyModel(&b->Parts->Object.Model); CalculateRadius(&b->Parts->Object); b->Parts->Object.Position.x = 100; b->Parts->Object.Position.y = 60; b->Parts->Object.Position.z = 100; AllocateWObject(&w->Objects); w->Objects->Type = VOBJECT; w->Objects->o = &b->Parts->Object; b->Parts->Functionality = Live; b->Parts->next = (struct VBossPart *)NewPtr(sizeof(struct VBossPart)); InitObject(&b->Parts->next->Object); BuildEnemyModel(&b->Parts->next->Object.Model); CalculateRadius(&b->Parts->next->Object); b->Parts->next->Object.Position.x = 100; b->Parts->next->Object.Position.y = 50; b->Parts->next->Object.Position.z = 100; AllocateWObject(&w->Objects->next); w->Objects->next->Type = VOBJECT; w->Objects->next->o = &b->Parts->next->Object; b->Parts->next->Functionality = Shoot; b->Parts->next->next = (struct VBossPart *)NewPtr(sizeof(struct VBossPart)); InitObject(&b->Parts->next->next->Object); BuildEnemyModel(&b->Parts->next->next->Object.Model); CalculateRadius(&b->Parts->next->next->Object); b->Parts->next->next->Object.Position.x = 100; b->Parts->next->next->Object.Position.y = 40; b->Parts->next->next->Object.Position.z = 100; AllocateWObject(&w->Objects->next->next); w->Objects->next->next->Type = VOBJECT; w->Objects->next->next->o = &b->Parts->next->next->Object; b->Parts->next->next->Functionality = BossMove; b->Parts->next->next->next = (struct VBossPart *)NewPtr(sizeof(struct VBossPart)); InitObject(&b->Parts->next->next->next->Object); BuildEnemyModel(&b->Parts->next->next->next->Object.Model); CalculateRadius(&b->Parts->next->next->next->Object); b->Parts->next->next->next->Object.Position.x = 100; b->Parts->next->next->next->Object.Position.y = 30; b->Parts->next->next->next->Object.Position.z = 100; AllocateWObject(&w->Objects->next->next->next); w->Objects->next->next->next->Type = VOBJECT; w->Objects->next->next->next->o = &b->Parts->next->next->next->Object; b->Parts->next->next->next->Functionality = None; b->Parts->next->next->next->next = NULL; break; case 2: b->Shields = 20; break; } }