//Copyright Paul Reiche, Fred Ford. 1992-2002 /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "../ship.h" #include "orz.h" #include "resinst.h" #include "uqm/colors.h" #include "uqm/globdata.h" #include "libs/mathlib.h" // Core characteristics #define MAX_CREW 16 #define MAX_ENERGY 20 #define ENERGY_REGENERATION 1 #define ENERGY_WAIT 6 #define MAX_THRUST 35 #define THRUST_INCREMENT 5 #define THRUST_WAIT 0 #define TURN_WAIT 1 #define SHIP_MASS 4 // Howitzer #define WEAPON_ENERGY_COST (MAX_ENERGY / 3) #define WEAPON_WAIT 4 #define ORZ_OFFSET 9 #define MISSILE_SPEED DISPLAY_TO_WORLD (30) #define MISSILE_LIFE 12 #define MISSILE_HITS 2 #define MISSILE_DAMAGE 3 #define MISSILE_OFFSET 1 // Marine #define SPECIAL_ENERGY_COST 0 #define SPECIAL_WAIT 12 #define MARINE_MAX_THRUST 32 #define MARINE_THRUST_INCREMENT 8 #define MARINE_HIT_POINTS 3 #define MARINE_MASS_POINTS 1 #define MAX_MARINES 8 #define MARINE_WAIT 12 #define ION_LIFE 1 #define START_ION_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A) // Rotating Turret #define TURRET_OFFSET 14 #define TURRET_WAIT 3 static RACE_DESC orz_desc = { { /* SHIP_INFO */ FIRES_FORE | SEEKING_SPECIAL, 23, /* Super Melee cost */ MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, ORZ_RACE_STRINGS, ORZ_ICON_MASK_PMAP_ANIM, ORZ_MICON_MASK_PMAP_ANIM, NULL, NULL, NULL }, { /* FLEET_STUFF */ 333 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ { /* Known location (center of SoI) */ 3608, 2637, }, }, { MAX_THRUST, THRUST_INCREMENT, ENERGY_REGENERATION, WEAPON_ENERGY_COST, SPECIAL_ENERGY_COST, ENERGY_WAIT, TURN_WAIT, THRUST_WAIT, WEAPON_WAIT, SPECIAL_WAIT, SHIP_MASS, }, { { ORZ_BIG_MASK_PMAP_ANIM, ORZ_MED_MASK_PMAP_ANIM, ORZ_SML_MASK_PMAP_ANIM, }, { HOWITZER_BIG_MASK_PMAP_ANIM, HOWITZER_MED_MASK_PMAP_ANIM, HOWITZER_SML_MASK_PMAP_ANIM, }, { TURRET_BIG_MASK_PMAP_ANIM, TURRET_MED_MASK_PMAP_ANIM, TURRET_SML_MASK_PMAP_ANIM, }, { ORZ_CAPTAIN_MASK_PMAP_ANIM, NULL, NULL, NULL, NULL, NULL }, ORZ_VICTORY_SONG, ORZ_SHIP_SOUNDS, { NULL, NULL, NULL }, { NULL, NULL, NULL }, { NULL, NULL, NULL }, NULL, NULL }, { 0, MISSILE_SPEED * MISSILE_LIFE, NULL, }, (UNINIT_FUNC *) NULL, (PREPROCESS_FUNC *) NULL, (POSTPROCESS_FUNC *) NULL, (INIT_WEAPON_FUNC *) NULL, 0, 0, /* CodeRef */ }; static void howitzer_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { if (!elementsOfSamePlayer (ElementPtr0, ElementPtr1)) weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); } static COUNT initialize_turret_missile (ELEMENT *ShipPtr, HELEMENT MissileArray[]) { ELEMENT *TurretPtr; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; GetElementStarShip (ShipPtr, &StarShipPtr); MissileBlock.cx = ShipPtr->next.location.x; MissileBlock.cy = ShipPtr->next.location.y; MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; LockElement (GetSuccElement (ShipPtr), &TurretPtr); if (TurretPtr->turn_wait == 0 && (StarShipPtr->cur_status_flags & SPECIAL) && (StarShipPtr->cur_status_flags & (LEFT | RIGHT))) { if (StarShipPtr->cur_status_flags & RIGHT) ++TurretPtr->thrust_wait; else --TurretPtr->thrust_wait; TurretPtr->turn_wait = TURRET_WAIT + 1; } MissileBlock.face = MissileBlock.index = NORMALIZE_FACING (StarShipPtr->ShipFacing + TurretPtr->thrust_wait); UnlockElement (GetSuccElement (ShipPtr)); MissileBlock.sender = ShipPtr->playerNr; MissileBlock.flags = IGNORE_SIMILAR; MissileBlock.pixoffs = TURRET_OFFSET; MissileBlock.speed = MISSILE_SPEED; MissileBlock.hit_points = MISSILE_HITS; MissileBlock.damage = MISSILE_DAMAGE; MissileBlock.life = MISSILE_LIFE; MissileBlock.preprocess_func = NULL; MissileBlock.blast_offs = MISSILE_OFFSET; MissileArray[0] = initialize_missile (&MissileBlock); if (MissileArray[0]) { ELEMENT *HowitzerPtr; LockElement (MissileArray[0], &HowitzerPtr); HowitzerPtr->collision_func = howitzer_collision; UnlockElement (MissileArray[0]); } return (1); } static BYTE count_marines (STARSHIP *StarShipPtr, BOOLEAN FindSpot) { BYTE num_marines, id_use[MAX_MARINES]; HELEMENT hElement, hNextElement; num_marines = MAX_MARINES; while (num_marines--) id_use[num_marines] = 0; num_marines = 0; for (hElement = GetTailElement (); hElement; hElement = hNextElement) { ELEMENT *ElementPtr; LockElement (hElement, &ElementPtr); hNextElement = GetPredElement (ElementPtr); if (ElementPtr->current.image.farray == StarShipPtr->RaceDescPtr->ship_data.special && ElementPtr->life_span && !(ElementPtr->state_flags & (FINITE_LIFE | DISAPPEARING))) { if (ElementPtr->state_flags & NONSOLID) { id_use[ElementPtr->turn_wait] = 1; } if (++num_marines == MAX_MARINES) { UnlockElement (hElement); hNextElement = 0; } } UnlockElement (hElement); } if (FindSpot) { num_marines = 0; while (id_use[num_marines]) ++num_marines; } return (num_marines); } static void orz_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, COUNT ConcernCounter) { ELEMENT *TurretPtr; STARSHIP *StarShipPtr; EVALUATE_DESC *lpEvalDesc; LockElement (GetSuccElement (ShipPtr), &TurretPtr); ++TurretPtr->turn_wait; ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); --TurretPtr->turn_wait; GetElementStarShip (ShipPtr, &StarShipPtr); lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; if (lpEvalDesc->ObjectPtr == 0) StarShipPtr->ship_input_state &= ~SPECIAL; else if (StarShipPtr->special_counter != 1) { STARSHIP *EnemyStarShipPtr; if (ShipPtr->turn_wait == 0 && lpEvalDesc->MoveState == ENTICE && lpEvalDesc->which_turn < 24 && (StarShipPtr->cur_status_flags & (SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED)) && !(StarShipPtr->ship_input_state & THRUST) && NORMALIZE_ANGLE ( GetVelocityTravelAngle (&ShipPtr->velocity) - ARCTAN ( lpEvalDesc->ObjectPtr->next.location.x - ShipPtr->next.location.x, lpEvalDesc->ObjectPtr->next.location.y - ShipPtr->next.location.y ) + (QUADRANT - (OCTANT >> 1))) >= ((QUADRANT - (OCTANT >> 1)) << 1)) StarShipPtr->ship_input_state &= ~(LEFT | RIGHT); StarShipPtr->ship_input_state &= ~SPECIAL; if (ShipPtr->turn_wait == 0 && !(StarShipPtr->ship_input_state & (LEFT | RIGHT | WEAPON)) && TurretPtr->turn_wait == 0) { SIZE delta_facing; COUNT facing;//, orig_facing; facing = NORMALIZE_FACING (StarShipPtr->ShipFacing + TurretPtr->thrust_wait); if ((delta_facing = TrackShip (TurretPtr, &facing)) > 0) { StarShipPtr->ship_input_state |= SPECIAL; if (delta_facing == ANGLE_TO_FACING (HALF_CIRCLE)) delta_facing += (((BYTE)TFB_Random () & 1) << 1) - 1; if (delta_facing < ANGLE_TO_FACING (HALF_CIRCLE)) StarShipPtr->ship_input_state |= RIGHT; else StarShipPtr->ship_input_state |= LEFT; } } GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); if (StarShipPtr->special_counter == 0 && !(StarShipPtr->ship_input_state & WEAPON) && StarShipPtr->RaceDescPtr->ship_info.crew_level > (BYTE)(StarShipPtr->RaceDescPtr->ship_info.max_crew >> 2) && !(EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags & POINT_DEFENSE) && (MANEUVERABILITY ( &EnemyStarShipPtr->RaceDescPtr->cyborg_control ) < SLOW_SHIP || lpEvalDesc->which_turn <= 12 || count_marines (StarShipPtr, FALSE) < 2)) { StarShipPtr->ship_input_state |= WEAPON | SPECIAL; } } UnlockElement (GetSuccElement (ShipPtr)); } static void ion_preprocess (ELEMENT *ElementPtr) { /* Originally, this table also contained the now commented out * entries. It then used some if statements to skip over these. * The current behaviour is the same as the old behavior. */ static const Color colorTable[] = { BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x15, 0x00), 0x7a), //BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x11, 0x00), 0x7b), BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x0E, 0x00), 0x7c), //BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x0A, 0x00), 0x7d), //BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x07, 0x00), 0x7e), BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x03, 0x00), 0x7f), //BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x00, 0x00), 0x2a), BUILD_COLOR (MAKE_RGB15_INIT (0x1B, 0x00, 0x00), 0x2b), //BUILD_COLOR (MAKE_RGB15_INIT (0x17, 0x00, 0x00), 0x2c), BUILD_COLOR (MAKE_RGB15_INIT (0x13, 0x00, 0x00), 0x2d), //BUILD_COLOR (MAKE_RGB15_INIT (0x0F, 0x00, 0x00), 0x2e), //BUILD_COLOR (MAKE_RGB15_INIT (0x0B, 0x00, 0x00), 0x2f), }; const size_t colorTabCount = sizeof colorTable / sizeof colorTable[0]; ElementPtr->colorCycleIndex++; if (ElementPtr->colorCycleIndex != colorTabCount) { ElementPtr->life_span = ElementPtr->thrust_wait; SetPrimColor (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], colorTable[ElementPtr->colorCycleIndex]); ElementPtr->state_flags &= ~DISAPPEARING; ElementPtr->state_flags |= CHANGING; } } static void marine_preprocess (ELEMENT *ElementPtr); void intruder_preprocess (ELEMENT *ElementPtr) { HELEMENT hElement, hNextElement; ELEMENT *ShipPtr; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); LockElement (StarShipPtr->hShip, &ShipPtr); if (ShipPtr->crew_level == 0 && ShipPtr->life_span == 1 && (ShipPtr->state_flags & (FINITE_LIFE | NONSOLID)) == (FINITE_LIFE | NONSOLID)) { ElementPtr->life_span = 0; ElementPtr->state_flags |= DISAPPEARING; } UnlockElement (StarShipPtr->hShip); if (ElementPtr->thrust_wait) --ElementPtr->thrust_wait; for (hElement = GetHeadElement (); hElement; hElement = hNextElement) { LockElement (hElement, &ShipPtr); if ((ShipPtr->state_flags & PLAYER_SHIP) && !elementsOfSamePlayer (ShipPtr, ElementPtr)) { STAMP s; if (ElementPtr->thrust_wait == MARINE_WAIT) { --ElementPtr->thrust_wait; s.origin.x = 16 + (ElementPtr->turn_wait & 3) * 9; s.origin.y = 14 + (ElementPtr->turn_wait >> 2) * 11; s.frame = SetAbsFrameIndex (ElementPtr->next.image.farray[0], GetFrameCount (ElementPtr->next.image.farray[0]) - 2); ModifySilhouette (ShipPtr, &s, 0); } ElementPtr->next.location = ShipPtr->next.location; if (ShipPtr->crew_level == 0 || ElementPtr->life_span == 0) { UnlockElement (hElement); hElement = 0; LeftShip: s.origin.x = 16 + (ElementPtr->turn_wait & 3) * 9; s.origin.y = 14 + (ElementPtr->turn_wait >> 2) * 11; s.frame = ElementPtr->next.image.frame; ModifySilhouette (ShipPtr, &s, MODIFY_SWAP); } else if (ElementPtr->thrust_wait == 0) { BYTE randval; ElementPtr->thrust_wait = MARINE_WAIT; randval = (BYTE)TFB_Random (); if (randval < (0x0100 / 16)) { ElementPtr->life_span = 0; ElementPtr->state_flags |= DISAPPEARING; ProcessSound (SetAbsSoundIndex ( StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 4), ElementPtr); goto LeftShip; } else if (randval < (0x0100 / 2 + 0x0100 / 16)) { if (!DeltaCrew (ShipPtr, -1)) ShipPtr->life_span = 0; ++ElementPtr->thrust_wait; s.origin.x = 16 + (ElementPtr->turn_wait & 3) * 9; s.origin.y = 14 + (ElementPtr->turn_wait >> 2) * 11; s.frame = SetAbsFrameIndex (ElementPtr->next.image.farray[0], GetFrameCount (ElementPtr->next.image.farray[0]) - 1); ModifySilhouette (ShipPtr, &s, 0); ProcessSound (SetAbsSoundIndex ( StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 3), ElementPtr); } } UnlockElement (hElement); break; } hNextElement = GetSuccElement (ShipPtr); UnlockElement (hElement); } if (hElement == 0 && ElementPtr->life_span) { ElementPtr->state_flags &= ~NONSOLID; ElementPtr->state_flags |= CHANGING | CREW_OBJECT; SetPrimType (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], STAMP_PRIM); ElementPtr->current.image.frame = ElementPtr->next.image.frame = SetAbsFrameIndex ( StarShipPtr->RaceDescPtr->ship_data.special[0], 21); ElementPtr->thrust_wait = 0; ElementPtr->turn_wait = MAKE_BYTE (0, NORMALIZE_FACING ((BYTE)TFB_Random ())); ElementPtr->preprocess_func = marine_preprocess; } } // XXX: merge this with spawn_ion_trail from tactrans.c? static void spawn_marine_ion_trail (ELEMENT *ElementPtr, STARSHIP *StarShipPtr, COUNT facing) { HELEMENT hIonElement; hIonElement = AllocElement (); if (hIonElement) { COUNT angle; ELEMENT *IonElementPtr; angle = FACING_TO_ANGLE (facing) + HALF_CIRCLE; InsertElement (hIonElement, GetHeadElement ()); LockElement (hIonElement, &IonElementPtr); IonElementPtr->playerNr = NEUTRAL_PLAYER_NUM; IonElementPtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID; IonElementPtr->thrust_wait = ION_LIFE; IonElementPtr->life_span = IonElementPtr->thrust_wait; // When the element "dies", in the death_func // 'cycle_ion_trail', it is given new life a number of // times, by setting life_span to thrust_wait. SetPrimType (&(GLOBAL (DisplayArray))[IonElementPtr->PrimIndex], POINT_PRIM); SetPrimColor (&(GLOBAL (DisplayArray))[IonElementPtr->PrimIndex], START_ION_COLOR); IonElementPtr->colorCycleIndex = 0; IonElementPtr->current.location = ElementPtr->current.location; IonElementPtr->current.location.x += (COORD)COSINE (angle, DISPLAY_TO_WORLD (2)); IonElementPtr->current.location.y += (COORD)SINE (angle, DISPLAY_TO_WORLD (2)); IonElementPtr->death_func = ion_preprocess; SetElementStarShip (IonElementPtr, StarShipPtr); { /* normally done during preprocess, but because * object is being inserted at head rather than * appended after tail it may never get preprocessed. */ IonElementPtr->next = IonElementPtr->current; --IonElementPtr->life_span; IonElementPtr->state_flags |= PRE_PROCESS; } UnlockElement (hIonElement); } } static void marine_preprocess (ELEMENT *ElementPtr) { ELEMENT *ShipPtr; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); LockElement (StarShipPtr->hShip, &ShipPtr); if (ShipPtr->crew_level == 0 && ShipPtr->life_span == 1 && (ShipPtr->state_flags & (FINITE_LIFE | NONSOLID)) == (FINITE_LIFE | NONSOLID)) { ElementPtr->life_span = 0; ElementPtr->state_flags |= DISAPPEARING | NONSOLID; ElementPtr->turn_wait = 1; } UnlockElement (StarShipPtr->hShip); if (LONIBBLE (ElementPtr->turn_wait)) --ElementPtr->turn_wait; else { COUNT facing, pfacing = 0; SIZE delta_x, delta_y, delta_facing; HELEMENT hObject, hNextObject, hTarget; ELEMENT *ObjectPtr; // XXX: thrust_wait is abused to store marine speed and // gravity well flags ElementPtr->thrust_wait &= ~(SHIP_IN_GRAVITY_WELL >> 6); hTarget = 0; for (hObject = GetHeadElement (); hObject; hObject = hNextObject) { LockElement (hObject, &ObjectPtr); hNextObject = GetSuccElement (ObjectPtr); if (GRAVITY_MASS (ObjectPtr->mass_points)) { delta_x = ObjectPtr->current.location.x - ElementPtr->current.location.x; delta_x = WRAP_DELTA_X (delta_x); delta_y = ObjectPtr->current.location.y - ElementPtr->current.location.y; delta_y = WRAP_DELTA_Y (delta_y); if ((long)delta_x * delta_x + (long)delta_y * delta_y <= (long)(DISPLAY_TO_WORLD (GRAVITY_THRESHOLD) * DISPLAY_TO_WORLD (GRAVITY_THRESHOLD))) { pfacing = ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)); delta_facing = NORMALIZE_FACING ( pfacing - ANGLE_TO_FACING ( GetVelocityTravelAngle (&ElementPtr->velocity)) + ANGLE_TO_FACING (OCTANT)); if (delta_facing <= ANGLE_TO_FACING (QUADRANT)) { hTarget = hObject; hNextObject = 0; } ElementPtr->thrust_wait |= (SHIP_IN_GRAVITY_WELL >> 6); } } else if ((ObjectPtr->state_flags & PLAYER_SHIP) && ObjectPtr->crew_level && !OBJECT_CLOAKED (ObjectPtr)) { if (!elementsOfSamePlayer (ObjectPtr, ElementPtr)) { if (ElementPtr->state_flags & IGNORE_SIMILAR) hTarget = hObject; } else if (hTarget == 0) hTarget = hObject; } UnlockElement (hObject); } facing = HINIBBLE (ElementPtr->turn_wait); if (hTarget == 0) delta_facing = -1; else { LockElement (hTarget, &ObjectPtr); delta_x = ObjectPtr->current.location.x - ElementPtr->current.location.x; delta_x = WRAP_DELTA_X (delta_x); delta_y = ObjectPtr->current.location.y - ElementPtr->current.location.y; delta_y = WRAP_DELTA_Y (delta_y); if (GRAVITY_MASS (ObjectPtr->mass_points)) { delta_facing = NORMALIZE_FACING (pfacing - facing + ANGLE_TO_FACING (OCTANT)); if (delta_facing > ANGLE_TO_FACING (QUADRANT)) delta_facing = 0; else { if (delta_facing == ANGLE_TO_FACING (OCTANT)) facing += (((SIZE)TFB_Random () & 1) << 1) - 1; else if (delta_facing < ANGLE_TO_FACING (OCTANT)) ++facing; else --facing; } } else { COUNT num_frames; VELOCITY_DESC ShipVelocity; if (elementsOfSamePlayer (ObjectPtr, ElementPtr) && (ElementPtr->state_flags & IGNORE_SIMILAR)) { ElementPtr->next.image.frame = SetAbsFrameIndex ( StarShipPtr->RaceDescPtr->ship_data.special[0], 21); ElementPtr->state_flags &= ~IGNORE_SIMILAR; ElementPtr->state_flags |= CHANGING; } num_frames = WORLD_TO_TURN ( square_root ((long)delta_x * delta_x + (long)delta_y * delta_y)); if (num_frames == 0) num_frames = 1; ShipVelocity = ObjectPtr->velocity; GetNextVelocityComponents (&ShipVelocity, &delta_x, &delta_y, num_frames); delta_x = (ObjectPtr->current.location.x + delta_x) - ElementPtr->current.location.x; delta_y = (ObjectPtr->current.location.y + delta_y) - ElementPtr->current.location.y; delta_facing = NORMALIZE_FACING ( ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) - facing); if (delta_facing > 0) { if (delta_facing == ANGLE_TO_FACING (HALF_CIRCLE)) facing += (((BYTE)TFB_Random () & 1) << 1) - 1; else if (delta_facing < ANGLE_TO_FACING (HALF_CIRCLE)) ++facing; else --facing; } } UnlockElement (hTarget); } ElementPtr->turn_wait = MAKE_BYTE (0, NORMALIZE_FACING (facing)); if (delta_facing == 0 || ((ElementPtr->thrust_wait & (SHIP_BEYOND_MAX_SPEED >> 6)) && !(ElementPtr->thrust_wait & (SHIP_IN_GRAVITY_WELL >> 6)))) { STATUS_FLAGS thrust_status; COUNT OldFacing; STATUS_FLAGS OldStatus; COUNT OldIncrement, OldThrust; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); // XXX: Hack: abusing the primary STARSHIP struct in order // to call inertial_thrust() for a marine OldFacing = StarShipPtr->ShipFacing; OldStatus = StarShipPtr->cur_status_flags; OldIncrement = StarShipPtr->RaceDescPtr->characteristics. thrust_increment; OldThrust = StarShipPtr->RaceDescPtr->characteristics.max_thrust; StarShipPtr->ShipFacing = facing; // XXX: thrust_wait is abused to store marine speed and // gravity well flags StarShipPtr->cur_status_flags = ElementPtr->thrust_wait << 6; StarShipPtr->RaceDescPtr->characteristics.thrust_increment = MARINE_THRUST_INCREMENT; StarShipPtr->RaceDescPtr->characteristics.max_thrust = MARINE_MAX_THRUST; thrust_status = inertial_thrust (ElementPtr); StarShipPtr->RaceDescPtr->characteristics.max_thrust = OldThrust; StarShipPtr->RaceDescPtr->characteristics.thrust_increment = OldIncrement; StarShipPtr->cur_status_flags = OldStatus; StarShipPtr->ShipFacing = OldFacing; if ((ElementPtr->thrust_wait & (SHIP_IN_GRAVITY_WELL >> 6)) || delta_facing || !(thrust_status & (SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED))) { spawn_marine_ion_trail (ElementPtr, StarShipPtr, facing); } // XXX: thrust_wait is abused to store marine speed and // gravity well flags ElementPtr->thrust_wait = (BYTE)(thrust_status >> 6); } } } void marine_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { if (ElementPtr0->life_span && !(ElementPtr0->state_flags & (NONSOLID | COLLISION)) && !(ElementPtr1->state_flags & FINITE_LIFE)) { if (!elementsOfSamePlayer (ElementPtr0, ElementPtr1)) { ElementPtr0->turn_wait = MAKE_BYTE (5, HINIBBLE (ElementPtr0->turn_wait)); ElementPtr0->thrust_wait &= ~((SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED) >> 6); ElementPtr0->state_flags |= COLLISION; } if (GRAVITY_MASS (ElementPtr1->mass_points)) { ElementPtr0->state_flags |= NONSOLID | FINITE_LIFE; ElementPtr0->hit_points = 0; ElementPtr0->life_span = 0; } else if ((ElementPtr1->state_flags & PLAYER_SHIP) && ((ElementPtr1->state_flags & FINITE_LIFE) || ElementPtr1->life_span == NORMAL_LIFE)) { ElementPtr1->state_flags &= ~COLLISION; if (!(ElementPtr0->state_flags & COLLISION)) { DeltaCrew (ElementPtr1, 1); ElementPtr0->state_flags |= DISAPPEARING | NONSOLID | FINITE_LIFE; ElementPtr0->hit_points = 0; ElementPtr0->life_span = 0; } else if ((ElementPtr0->state_flags & IGNORE_SIMILAR) && ElementPtr1->crew_level #ifdef NEVER && (BYTE)TFB_Random () <= (0x0100 / 3) #endif /* NEVER */ ) { STAMP s; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr0, &StarShipPtr); if (!DeltaCrew (ElementPtr1, -1)) ElementPtr1->life_span = 0; else { ElementPtr0->turn_wait = count_marines (StarShipPtr, TRUE); ElementPtr0->thrust_wait = MARINE_WAIT; ElementPtr0->next.image.frame = SetAbsFrameIndex ( ElementPtr0->next.image.farray[0], 22 + ElementPtr0->turn_wait ); ElementPtr0->state_flags |= NONSOLID; ElementPtr0->state_flags &= ~CREW_OBJECT; SetPrimType (&(GLOBAL (DisplayArray))[ ElementPtr0->PrimIndex ], NO_PRIM); ElementPtr0->preprocess_func = intruder_preprocess; s.origin.x = 16 + (ElementPtr0->turn_wait & 3) * 9; s.origin.y = 14 + (ElementPtr0->turn_wait >> 2) * 11; s.frame = ElementPtr0->next.image.frame; ModifySilhouette (ElementPtr1, &s, 0); } ProcessSound (SetAbsSoundIndex ( StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), ElementPtr1); } ElementPtr0->state_flags &= ~COLLISION; } } (void) pPt0; /* Satisfying compiler (unused parameter) */ (void) pPt1; /* Satisfying compiler (unused parameter) */ } static void animate (ELEMENT *ElementPtr) { if (ElementPtr->turn_wait > 0) --ElementPtr->turn_wait; else { ElementPtr->next.image.frame = IncFrameIndex (ElementPtr->current.image.frame); ElementPtr->state_flags |= CHANGING; ElementPtr->turn_wait = ElementPtr->next_turn; } } static void turret_postprocess (ELEMENT *ElementPtr) { if (ElementPtr->life_span == 0) { STARSHIP *StarShipPtr; SetPrimType (&(GLOBAL (DisplayArray))[ ElementPtr->PrimIndex], NO_PRIM); GetElementStarShip (ElementPtr, &StarShipPtr); if (StarShipPtr->hShip) { COUNT facing; HELEMENT hTurret, hSpaceMarine; ELEMENT *ShipPtr; LockElement (StarShipPtr->hShip, &ShipPtr); hTurret = AllocElement (); if (hTurret) { ELEMENT *TurretPtr; LockElement (hTurret, &TurretPtr); TurretPtr->playerNr = ElementPtr->playerNr; TurretPtr->state_flags = FINITE_LIFE | NONSOLID | IGNORE_SIMILAR | CHANGING | PRE_PROCESS | POST_PROCESS; TurretPtr->life_span = 1; TurretPtr->current.image = ElementPtr->current.image; TurretPtr->current.location = ShipPtr->next.location; TurretPtr->turn_wait = ElementPtr->turn_wait; TurretPtr->thrust_wait = ElementPtr->thrust_wait; if (TurretPtr->turn_wait) --TurretPtr->turn_wait; else if ((StarShipPtr->cur_status_flags & SPECIAL) && (StarShipPtr->cur_status_flags & (LEFT | RIGHT))) { if (StarShipPtr->cur_status_flags & RIGHT) ++TurretPtr->thrust_wait; else --TurretPtr->thrust_wait; TurretPtr->turn_wait = TURRET_WAIT; } facing = NORMALIZE_FACING (StarShipPtr->ShipFacing + TurretPtr->thrust_wait); StarShipPtr->RaceDescPtr->ship_info.ship_flags &= ~(FIRES_FORE | FIRES_RIGHT | FIRES_AFT | FIRES_LEFT); StarShipPtr->RaceDescPtr->ship_info.ship_flags |= FIRES_FORE << (NORMALIZE_FACING (facing + ANGLE_TO_FACING (OCTANT)) / ANGLE_TO_FACING (QUADRANT)); TurretPtr->current.image.frame = SetAbsFrameIndex ( TurretPtr->current.image.frame, facing); facing = FACING_TO_ANGLE (facing); if (StarShipPtr->cur_status_flags & WEAPON) { HELEMENT hTurretEffect; ELEMENT *TurretEffectPtr; LockElement (GetTailElement (), &TurretEffectPtr); if (TurretEffectPtr != ElementPtr && elementsOfSamePlayer (TurretEffectPtr, ElementPtr) && (TurretEffectPtr->state_flags & APPEARING) && GetPrimType (&(GLOBAL (DisplayArray))[ TurretEffectPtr->PrimIndex ]) == STAMP_PRIM && (hTurretEffect = AllocElement ())) { TurretPtr->current.location.x -= COSINE (facing, DISPLAY_TO_WORLD (2)); TurretPtr->current.location.y -= SINE (facing, DISPLAY_TO_WORLD (2)); LockElement (hTurretEffect, &TurretEffectPtr); TurretEffectPtr->playerNr = ElementPtr->playerNr; TurretEffectPtr->state_flags = FINITE_LIFE | NONSOLID | IGNORE_SIMILAR | APPEARING; TurretEffectPtr->life_span = 4; TurretEffectPtr->current.location.x = TurretPtr->current.location.x + COSINE (facing, DISPLAY_TO_WORLD (TURRET_OFFSET)); TurretEffectPtr->current.location.y = TurretPtr->current.location.y + SINE (facing, DISPLAY_TO_WORLD (TURRET_OFFSET)); TurretEffectPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; TurretEffectPtr->current.image.frame = SetAbsFrameIndex ( StarShipPtr->RaceDescPtr->ship_data.special[0], ANGLE_TO_FACING (FULL_CIRCLE)); TurretEffectPtr->preprocess_func = animate; SetElementStarShip (TurretEffectPtr, StarShipPtr); SetPrimType (&(GLOBAL (DisplayArray))[ TurretEffectPtr->PrimIndex], STAMP_PRIM); UnlockElement (hTurretEffect); PutElement (hTurretEffect); } UnlockElement (GetTailElement ()); } TurretPtr->next = TurretPtr->current; SetPrimType (&(GLOBAL (DisplayArray))[ TurretPtr->PrimIndex], GetPrimType (&(GLOBAL (DisplayArray))[ ShipPtr->PrimIndex])); SetPrimColor (&(GLOBAL (DisplayArray))[ TurretPtr->PrimIndex], GetPrimColor (&(GLOBAL (DisplayArray))[ ShipPtr->PrimIndex])); TurretPtr->postprocess_func = ElementPtr->postprocess_func; SetElementStarShip (TurretPtr, StarShipPtr); UnlockElement (hTurret); InsertElement (hTurret, GetSuccElement (ElementPtr)); } if (StarShipPtr->special_counter == 0 && (StarShipPtr->cur_status_flags & SPECIAL) && (StarShipPtr->cur_status_flags & WEAPON) && ShipPtr->crew_level > 1 && count_marines (StarShipPtr, FALSE) < MAX_MARINES && TrackShip (ShipPtr, &facing) >= 0 && (hSpaceMarine = AllocElement ())) { ELEMENT *SpaceMarinePtr; LockElement (hSpaceMarine, &SpaceMarinePtr); SpaceMarinePtr->playerNr = ElementPtr->playerNr; SpaceMarinePtr->state_flags = IGNORE_SIMILAR | APPEARING | CREW_OBJECT; SpaceMarinePtr->life_span = NORMAL_LIFE; SpaceMarinePtr->hit_points = MARINE_HIT_POINTS; SpaceMarinePtr->mass_points = MARINE_MASS_POINTS; facing = FACING_TO_ANGLE (StarShipPtr->ShipFacing); SpaceMarinePtr->current.location.x = ShipPtr->current.location.x - COSINE (facing, DISPLAY_TO_WORLD (TURRET_OFFSET)); SpaceMarinePtr->current.location.y = ShipPtr->current.location.y - SINE (facing, DISPLAY_TO_WORLD (TURRET_OFFSET)); SpaceMarinePtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; SpaceMarinePtr->current.image.frame = SetAbsFrameIndex ( StarShipPtr->RaceDescPtr->ship_data.special[0], 20); SpaceMarinePtr->turn_wait = MAKE_BYTE (0, NORMALIZE_FACING ( ANGLE_TO_FACING (facing + HALF_CIRCLE))); SpaceMarinePtr->preprocess_func = marine_preprocess; SpaceMarinePtr->collision_func = marine_collision; SetElementStarShip (SpaceMarinePtr, StarShipPtr); SetPrimType (&(GLOBAL (DisplayArray))[ SpaceMarinePtr->PrimIndex], STAMP_PRIM); UnlockElement (hSpaceMarine); PutElement (hSpaceMarine); DeltaCrew (ShipPtr, -1); ProcessSound (SetAbsSoundIndex ( StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), SpaceMarinePtr); StarShipPtr->special_counter = StarShipPtr->RaceDescPtr->characteristics.special_wait; } UnlockElement (StarShipPtr->hShip); } } } static void orz_preprocess (ELEMENT *ElementPtr) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); if (!(ElementPtr->state_flags & APPEARING)) { if (((StarShipPtr->cur_status_flags | StarShipPtr->old_status_flags) & SPECIAL) && (StarShipPtr->cur_status_flags & (LEFT | RIGHT)) && ElementPtr->turn_wait == 0) { ++ElementPtr->turn_wait; } if ((StarShipPtr->cur_status_flags & SPECIAL) && (StarShipPtr->cur_status_flags & WEAPON) && StarShipPtr->weapon_counter == 0) { ++StarShipPtr->weapon_counter; } } else { HELEMENT hTurret; hTurret = AllocElement (); if (hTurret) { ELEMENT *TurretPtr; LockElement (hTurret, &TurretPtr); TurretPtr->playerNr = ElementPtr->playerNr; TurretPtr->state_flags = FINITE_LIFE | NONSOLID | IGNORE_SIMILAR; TurretPtr->life_span = 1; TurretPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; TurretPtr->current.image.frame = SetAbsFrameIndex ( StarShipPtr->RaceDescPtr->ship_data.special[0], StarShipPtr->ShipFacing); TurretPtr->postprocess_func = turret_postprocess; SetElementStarShip (TurretPtr, StarShipPtr); UnlockElement (hTurret); InsertElement (hTurret, GetSuccElement (ElementPtr)); } } } RACE_DESC* init_orz (void) { RACE_DESC *RaceDescPtr; orz_desc.preprocess_func = orz_preprocess; orz_desc.init_weapon_func = initialize_turret_missile; orz_desc.cyborg_control.intelligence_func = orz_intelligence; RaceDescPtr = &orz_desc; return (RaceDescPtr); }