static void doggy_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { collision (ElementPtr0, pPt0, ElementPtr1, pPt1); if ((ElementPtr1->state_flags & PLAYER_SHIP) && !elementsOfSamePlayer (ElementPtr0, ElementPtr1)) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr0, &StarShipPtr); ProcessSound (SetAbsSoundIndex ( /* DOGGY_STEALS_ENERGY */ StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), ElementPtr0); GetElementStarShip (ElementPtr1, &StarShipPtr); if (StarShipPtr->RaceDescPtr->ship_info.energy_level < ENERGY_DRAIN) DeltaEnergy (ElementPtr1, -StarShipPtr->RaceDescPtr->ship_info.energy_level); else DeltaEnergy (ElementPtr1, -ENERGY_DRAIN); } if (ElementPtr0->thrust_wait <= COLLISION_THRUST_WAIT) ElementPtr0->thrust_wait += COLLISION_THRUST_WAIT << 1; }
static void spawn_crew (ELEMENT *ElementPtr) { if (ElementPtr->state_flags & PLAYER_SHIP) { HELEMENT hCrew; hCrew = AllocElement (); if (hCrew != 0) { ELEMENT *CrewPtr; LockElement (hCrew, &CrewPtr); CrewPtr->next.location = ElementPtr->next.location; CrewPtr->playerNr = ElementPtr->playerNr; CrewPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE; CrewPtr->life_span = 0; CrewPtr->death_func = spawn_crew; CrewPtr->pParent = ElementPtr->pParent; CrewPtr->hTarget = 0; UnlockElement (hCrew); PutElement (hCrew); } } else { HELEMENT hElement, hNextElement; for (hElement = GetHeadElement (); hElement != 0; hElement = hNextElement) { ELEMENT *ObjPtr; LockElement (hElement, &ObjPtr); hNextElement = GetSuccElement (ObjPtr); if ((ObjPtr->state_flags & PLAYER_SHIP) && !elementsOfSamePlayer (ObjPtr, ElementPtr) && ObjPtr->crew_level > 1) { SIZE dx, dy; DWORD d_squared; dx = ObjPtr->next.location.x - ElementPtr->next.location.x; if (dx < 0) dx = -dx; dy = ObjPtr->next.location.y - ElementPtr->next.location.y; if (dy < 0) dy = -dy; dx = WORLD_TO_DISPLAY (dx); dy = WORLD_TO_DISPLAY (dy); #define ABANDONER_RANGE (208 << RESOLUTION_FACTOR) // JMS_GFX /* originally SPACE_HEIGHT */ if (dx <= ABANDONER_RANGE && dy <= ABANDONER_RANGE && (d_squared = (DWORD)((UWORD)dx * (UWORD)dx) + (DWORD)((UWORD)dy * (UWORD)dy)) <= (DWORD)((UWORD)ABANDONER_RANGE * (UWORD)ABANDONER_RANGE)) { #define MAX_ABANDONERS 8 COUNT crew_loss; crew_loss = ((MAX_ABANDONERS * (ABANDONER_RANGE - square_root (d_squared))) / ABANDONER_RANGE) + 1; if (crew_loss >= ObjPtr->crew_level) crew_loss = ObjPtr->crew_level - 1; AbandonShip (ObjPtr, ElementPtr, crew_loss); } } UnlockElement (hElement); } } }
static void confusion_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { if (ElementPtr1->state_flags & PLAYER_SHIP) { HELEMENT hConfusionElement, hNextElement; ELEMENT *ConfusionPtr; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr0, &StarShipPtr); for (hConfusionElement = GetHeadElement (); hConfusionElement; hConfusionElement = hNextElement) { LockElement (hConfusionElement, &ConfusionPtr); if (elementsOfSamePlayer (ConfusionPtr, ElementPtr0) && ConfusionPtr->current.image.farray == StarShipPtr->RaceDescPtr->ship_data.special && (ConfusionPtr->state_flags & NONSOLID)) { UnlockElement (hConfusionElement); break; } hNextElement = GetSuccElement (ConfusionPtr); UnlockElement (hConfusionElement); } if (hConfusionElement || (hConfusionElement = AllocElement ())) { LockElement (hConfusionElement, &ConfusionPtr); if (ConfusionPtr->state_flags == 0) /* not allocated before */ { InsertElement (hConfusionElement, GetHeadElement ()); ConfusionPtr->current = ElementPtr0->next; ConfusionPtr->current.image.frame = SetAbsFrameIndex ( ConfusionPtr->current.image.frame, 8 ); ConfusionPtr->next = ConfusionPtr->current; ConfusionPtr->playerNr = ElementPtr0->playerNr; ConfusionPtr->state_flags = FINITE_LIFE | NONSOLID | CHANGING; ConfusionPtr->preprocess_func = confuse_preprocess; SetPrimType ( &(GLOBAL (DisplayArray))[ConfusionPtr->PrimIndex], NO_PRIM ); SetElementStarShip (ConfusionPtr, StarShipPtr); GetElementStarShip (ElementPtr1, &StarShipPtr); ConfusionPtr->hTarget = StarShipPtr->hShip; } ConfusionPtr->life_span = 400; ConfusionPtr->turn_wait = (BYTE)(1 << ((BYTE)TFB_Random () & 1)); /* LEFT or RIGHT */ UnlockElement (hConfusionElement); } ElementPtr0->hit_points = 0; ElementPtr0->life_span = 0; ElementPtr0->state_flags |= DISAPPEARING | COLLISION | NONSOLID; } (void) pPt0; /* Satisfying compiler (unused parameter) */ (void) pPt1; /* Satisfying compiler (unused parameter) */ }
static void spawn_crew (ELEMENT *ElementPtr) { if (ElementPtr->state_flags & PLAYER_SHIP) { HELEMENT hCrew; hCrew = AllocElement (); if (hCrew != 0) { ELEMENT *CrewPtr; LockElement (hCrew, &CrewPtr); CrewPtr->next.location = ElementPtr->next.location; CrewPtr->playerNr = ElementPtr->playerNr; CrewPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE; CrewPtr->life_span = 0; CrewPtr->death_func = spawn_crew; CrewPtr->pParent = ElementPtr->pParent; CrewPtr->hTarget = 0; UnlockElement (hCrew); PutElement (hCrew); } } else { HELEMENT hElement, hNextElement; for (hElement = GetHeadElement (); hElement != 0; hElement = hNextElement) { ELEMENT *ObjPtr; STARSHIP *EnemyStarShipPtr; LockElement (hElement, &ObjPtr); GetElementStarShip (ObjPtr, &EnemyStarShipPtr); hNextElement = GetSuccElement (ObjPtr); if ((ObjPtr->state_flags & PLAYER_SHIP) && !elementsOfSamePlayer (ObjPtr, ElementPtr) && ObjPtr->crew_level > 1) { SIZE dx, dy; DWORD d_squared; dx = ObjPtr->next.location.x - ElementPtr->next.location.x; if (dx < 0) dx = -dx; dy = ObjPtr->next.location.y - ElementPtr->next.location.y; if (dy < 0) dy = -dy; dx = WORLD_TO_DISPLAY (dx); dy = WORLD_TO_DISPLAY (dy); if (dx <= ABANDONER_RANGE && dy <= ABANDONER_RANGE && (d_squared = (DWORD)((UWORD)dx * (UWORD)dx) + (DWORD)((UWORD)dy * (UWORD)dy)) <= (DWORD)((UWORD)ABANDONER_RANGE * (UWORD)ABANDONER_RANGE)) { COUNT crew_loss; if (EnemyStarShipPtr && EnemyStarShipPtr->SpeciesID == SYREEN_ID) { crew_loss = ((LIMITED_MAX_ABANDONERS * (ABANDONER_RANGE - square_root (d_squared))) / ABANDONER_RANGE) + 1; } else { crew_loss = ((MAX_ABANDONERS * (ABANDONER_RANGE - square_root (d_squared))) / ABANDONER_RANGE) + 1; } if (crew_loss >= ObjPtr->crew_level) crew_loss = ObjPtr->crew_level - 1; AbandonShip (ObjPtr, ElementPtr, crew_loss); } } UnlockElement (hElement); } } }
static void gas_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { STARSHIP *StarShipPtr; STARSHIP *EnemyStarShipPtr; BYTE enemyShipIsBaul = 0; BYTE enemyShipIsChmmr = 0; // This is the ship this gas cloud belongs to. GetElementStarShip (ElementPtr0, &StarShipPtr); // Check if the colliding element is a ship. If it is not, check if it's a projectile from Baul or Chmmr ship. if (!elementsOfSamePlayer(ElementPtr0, ElementPtr1) && !(ElementPtr1->state_flags & PLAYER_SHIP) && ElementPtr1->playerNr > -1) { GetElementStarShip (ElementPtr1, &EnemyStarShipPtr); if (EnemyStarShipPtr->SpeciesID == BAUL_ID) enemyShipIsBaul = 1; else if (EnemyStarShipPtr->SpeciesID == CHMMR_ID) enemyShipIsChmmr = 1; // This is important because the gas can stick to zapsats. } // If colliding with Baul's spray weapon or shockwave, EXPLODE!!! if (ElementPtr1->current.image.farray == StarShipPtr->RaceDescPtr->ship_data.weapon || (enemyShipIsBaul && ElementPtr1->current.image.farray == EnemyStarShipPtr->RaceDescPtr->ship_data.weapon)) { // Move to shockwave graphics. ElementPtr0->current.image.frame = SetAbsFrameIndex (ElementPtr0->current.image.frame, LAST_GAS_INDEX); ElementPtr0->next.image.frame = SetAbsFrameIndex (ElementPtr0->current.image.frame, LAST_GAS_INDEX); // Remove the lock on enemy ship and make the gas die on next turn. ElementPtr0->hTarget = 0; ElementPtr0->life_span = 1; // Don't do the gas dissolve anim now that the shockwave appears. ElementPtr0->death_func = NULL; // Generate the actual shockwave. generate_shockwave (ElementPtr0, -1); // XXX ElementPtr1->playerNr); } // If colliding with enemy ship, stick to the ship. // Also stick to Chmmr's zapsats. else if (ElementPtr0->state_flags & IGNORE_VELOCITY && ElementPtr1->playerNr != ElementPtr0->playerNr && (ElementPtr1->state_flags & PLAYER_SHIP || (enemyShipIsChmmr && ElementPtr1->mass_points == 10) )) { HELEMENT hGasElement; HELEMENT hTargetElement; ELEMENT *GasPtr; // Create a new gas element which is sticking to the enemy ship. if ((hGasElement = AllocElement ())) { LockElement (hGasElement, &GasPtr); if (GasPtr->state_flags == 0) /* not allocated before */ { InsertElement (hGasElement, GetHeadElement ()); GasPtr->current = ElementPtr0->next; GasPtr->next = GasPtr->current; GasPtr->playerNr = ElementPtr0->playerNr; GasPtr->state_flags = FINITE_LIFE | GASSY_SUBSTANCE | CHANGING; GasPtr->preprocess_func = gas_preprocess; GasPtr->collision_func = gas_collision; SetPrimType (&(GLOBAL (DisplayArray))[GasPtr->PrimIndex], NO_PRIM); SetElementStarShip (GasPtr, StarShipPtr); GetElementStarShip (ElementPtr1, &StarShipPtr); // Ships and Chmmr Zapsats require different ways of making them the target of the gas cloud. if (ElementPtr1->state_flags & PLAYER_SHIP) GasPtr->hTarget = StarShipPtr->hShip; else { GasPtr->life_span = 0; LockElement (ElementPtr1, &hTargetElement); GasPtr->hTarget = hTargetElement; } } GasPtr->hit_points = ElementPtr0->hit_points; GasPtr->life_span = ElementPtr0->life_span; GasPtr->thrust_wait = 1; GasPtr->weapon_element_index = ElementPtr0->weapon_element_index; GasPtr->turn_wait = (BYTE)(1 << ((BYTE)TFB_Random () & 1)); /* LEFT or RIGHT */ GasPtr->death_func = gas_death; UnlockElement (hGasElement); } // Erase the original gas element. ElementPtr0->hit_points = 0; ElementPtr0->life_span = 0; ElementPtr0->state_flags |= DISAPPEARING | COLLISION | NONSOLID; } (void) pPt0; /* Satisfying compiler (unused parameter) */ (void) pPt1; /* Satisfying compiler (unused parameter) */ }
static void chenjesu_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, COUNT ConcernCounter) { EVALUATE_DESC *lpEvalDesc; STARSHIP *StarShipPtr; GetElementStarShip (ShipPtr, &StarShipPtr); StarShipPtr->ship_input_state &= ~SPECIAL; lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; if (lpEvalDesc->ObjectPtr) { STARSHIP *EnemyStarShipPtr; GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); if ((lpEvalDesc->which_turn <= 16 && MANEUVERABILITY ( &EnemyStarShipPtr->RaceDescPtr->cyborg_control ) >= MEDIUM_SHIP) || (MANEUVERABILITY ( &EnemyStarShipPtr->RaceDescPtr->cyborg_control ) <= SLOW_SHIP && WEAPON_RANGE ( &EnemyStarShipPtr->RaceDescPtr->cyborg_control ) >= LONG_RANGE_WEAPON * 3 / 4 && (EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags & SEEKING_WEAPON))) lpEvalDesc->MoveState = PURSUE; } if (StarShipPtr->special_counter == 1 && ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr && ObjectsOfConcern[ENEMY_WEAPON_INDEX].MoveState == ENTICE && ObjectsOfConcern[ENEMY_WEAPON_INDEX].which_turn <= 8) { lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; } ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); if (lpEvalDesc->ObjectPtr) { HELEMENT h, hNext; ELEMENT *CrystalPtr; h = (StarShipPtr->old_status_flags & WEAPON) ? GetTailElement () : (HELEMENT)0; for (; h; h = hNext) { LockElement (h, &CrystalPtr); hNext = GetPredElement (CrystalPtr); if (!(CrystalPtr->state_flags & NONSOLID) && CrystalPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.weapon && CrystalPtr->preprocess_func && CrystalPtr->life_span > 0 && elementsOfSamePlayer (CrystalPtr, ShipPtr)) { if (ObjectsOfConcern[ENEMY_SHIP_INDEX].ObjectPtr) { COUNT which_turn; if ((which_turn = PlotIntercept (CrystalPtr, ObjectsOfConcern[ENEMY_SHIP_INDEX].ObjectPtr, CrystalPtr->life_span, FRAGMENT_RANGE / 2)) == 0 || (which_turn == 1 && PlotIntercept (CrystalPtr, ObjectsOfConcern[ENEMY_SHIP_INDEX].ObjectPtr, CrystalPtr->life_span, 0) == 0)) StarShipPtr->ship_input_state &= ~WEAPON; else if (StarShipPtr->weapon_counter == 0) { StarShipPtr->ship_input_state |= WEAPON; lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; } UnlockElement (h); break; } hNext = 0; } UnlockElement (h); } if (h == 0) { if (StarShipPtr->old_status_flags & WEAPON) { StarShipPtr->ship_input_state &= ~WEAPON; if (lpEvalDesc == &ObjectsOfConcern[ENEMY_WEAPON_INDEX]) StarShipPtr->weapon_counter = 3; } else if (StarShipPtr->weapon_counter == 0 && ship_weapons (ShipPtr, lpEvalDesc->ObjectPtr, FRAGMENT_RANGE / 2)) StarShipPtr->ship_input_state |= WEAPON; } } if (StarShipPtr->special_counter < MAX_DOGGIES) { if (lpEvalDesc->ObjectPtr && StarShipPtr->RaceDescPtr->ship_info.energy_level <= SPECIAL_ENERGY_COST && !(StarShipPtr->ship_input_state & WEAPON)) StarShipPtr->ship_input_state |= SPECIAL; } }