//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 "lastbat.h" #include "resinst.h" #include "uqm/colors.h" #include "uqm/globdata.h" #include "uqm/battle.h" // For BATTLE_FRAME_RATE #include "libs/mathlib.h" #include "libs/timelib.h" #define num_generators characteristics.max_thrust // Core characteristics #define MAX_CREW 1 #define MAX_ENERGY MAX_ENERGY_SIZE #define ENERGY_REGENERATION 1 #define ENERGY_WAIT 6 #define MAX_THRUST 0 #define THRUST_INCREMENT 0 #define TURN_WAIT 0 #define THRUST_WAIT 0 #define SHIP_MASS (MAX_SHIP_MASS * 10) #define TURRET_WAIT 0 /* Controls animation of the Sa-Matra's central * 'furnace', a new frame is displayed once every * TURRET_WAIT frames. */ // Yellow comet #define WEAPON_WAIT ((ONE_SECOND / BATTLE_FRAME_RATE) * 10) #define COMET_DAMAGE 2 #define COMET_OFFSET 0 #define COMET_HITS 12 #define COMET_SPEED DISPLAY_TO_WORLD (12) #define COMET_LIFE 2 #define COMET_TURN_WAIT 3 #define MAX_COMETS 3 #define WEAPON_ENERGY_COST 2 /* Used for samatra_desc.weapon_energy_cost, but the value isn't * actually used. */ // Green sentinel #define SPECIAL_WAIT ((ONE_SECOND / BATTLE_FRAME_RATE) * 3) #define SENTINEL_SPEED DISPLAY_TO_WORLD (8) #define SENTINEL_LIFE 2 #define SENTINEL_OFFSET 0 #define SENTINEL_HITS 10 #define SENTINEL_DAMAGE 1 #define TRACK_WAIT 1 #define ANIMATION_WAIT 1 #define RECOIL_VELOCITY WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (10)) #define MAX_RECOIL_VELOCITY (RECOIL_VELOCITY * 4) #define MAX_SENTINELS 4 #define SPECIAL_ENERGY_COST 3 /* Used for samatra_desc.special_energy_cost, but the value isn't * actually used. */ // Blue force field #define GATE_DAMAGE 1 #define GATE_HITS 100 // Red generators #define GENERATOR_HITS 15 #define MAX_GENERATORS 8 static RACE_DESC samatra_desc = { { /* SHIP_INFO */ /* FIRES_FORE | */ IMMEDIATE_WEAPON | CREW_IMMUNE, 16, /* Super Melee cost */ MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, NULL_RESOURCE, NULL_RESOURCE, NULL_RESOURCE, NULL, NULL, NULL }, { /* FLEET_STUFF */ 0, /* Initial sphere of influence radius */ { /* Known location (center of SoI) */ 0, 0, }, }, { MAX_THRUST, THRUST_INCREMENT, ENERGY_REGENERATION, WEAPON_ENERGY_COST, SPECIAL_ENERGY_COST, ENERGY_WAIT, TURN_WAIT, THRUST_WAIT, WEAPON_WAIT, SPECIAL_WAIT, SHIP_MASS, }, { { SAMATRA_BIG_MASK_ANIM, SAMATRA_MED_MASK_PMAP_ANIM, SAMATRA_SML_MASK_PMAP_ANIM, }, { SENTINEL_BIG_MASK_ANIM, SENTINEL_MED_MASK_PMAP_ANIM, SENTINEL_SML_MASK_PMAP_ANIM, }, { GENERATOR_BIG_MASK_ANIM, GENERATOR_MED_MASK_PMAP_ANIM, GENERATOR_SML_MASK_PMAP_ANIM, }, { SAMATRA_CAPTAIN_MASK_PMAP_ANIM, NULL, NULL, NULL, NULL, NULL }, NULL_RESOURCE, SAMATRA_SHIP_SOUNDS, { NULL, NULL, NULL }, { NULL, NULL, NULL }, { NULL, NULL, NULL }, NULL, NULL }, { 0, 0, NULL, }, (UNINIT_FUNC *) NULL, (PREPROCESS_FUNC *) NULL, (POSTPROCESS_FUNC *) NULL, (INIT_WEAPON_FUNC *) NULL, 0, 0, /* CodeRef */ }; static HELEMENT spawn_comet (ELEMENT *ElementPtr); static void comet_preprocess (ELEMENT *ElementPtr) { COUNT frame_index; frame_index = GetFrameIndex (ElementPtr->current.image.frame) + 1; if (frame_index < 29) { if (frame_index == 25) { SIZE cur_delta_x, cur_delta_y; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); ++StarShipPtr->RaceDescPtr->characteristics.weapon_wait; spawn_comet (ElementPtr); ElementPtr->state_flags |= NONSOLID; GetCurrentVelocityComponents (&ElementPtr->velocity, &cur_delta_x, &cur_delta_y); SetVelocityComponents (&ElementPtr->velocity, cur_delta_x / 2, cur_delta_y / 2); } ++ElementPtr->life_span; } ElementPtr->next.image.frame = SetAbsFrameIndex ( ElementPtr->current.image.frame, frame_index ); ElementPtr->state_flags |= CHANGING; } static void comet_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { if (ElementPtr1->playerNr == RPG_PLAYER_NUM) { BYTE old_hits; COUNT old_life; HELEMENT hBlastElement; if (ElementPtr1->state_flags & PLAYER_SHIP) ElementPtr0->mass_points = COMET_DAMAGE; else ElementPtr0->mass_points = 50; old_hits = ElementPtr0->hit_points; old_life = ElementPtr0->life_span; hBlastElement = weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); if (ElementPtr1->state_flags & PLAYER_SHIP) { ElementPtr0->hit_points = old_hits; ElementPtr0->life_span = old_life; ElementPtr0->state_flags &= ~(DISAPPEARING | NONSOLID | COLLISION); if (hBlastElement) { RemoveElement (hBlastElement); FreeElement (hBlastElement); } } if (ElementPtr0->state_flags & DISAPPEARING) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr0, &StarShipPtr); --StarShipPtr->RaceDescPtr->characteristics.weapon_wait; } } } static HELEMENT spawn_comet (ELEMENT *ElementPtr) { MISSILE_BLOCK MissileBlock; HELEMENT hComet; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); MissileBlock.cx = ElementPtr->next.location.x; MissileBlock.cy = ElementPtr->next.location.y; MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; MissileBlock.face = 0; MissileBlock.index = 24; MissileBlock.sender = ElementPtr->playerNr; MissileBlock.flags = IGNORE_SIMILAR; MissileBlock.pixoffs = 0; MissileBlock.speed = 0; MissileBlock.hit_points = COMET_HITS; MissileBlock.damage = COMET_DAMAGE; MissileBlock.life = COMET_LIFE; MissileBlock.preprocess_func = comet_preprocess; MissileBlock.blast_offs = COMET_OFFSET; hComet = initialize_missile (&MissileBlock); if (hComet) { ELEMENT *CometPtr; PutElement (hComet); LockElement (hComet, &CometPtr); CometPtr->collision_func = comet_collision; SetElementStarShip (CometPtr, StarShipPtr); { COUNT facing; CometPtr->turn_wait = ElementPtr->turn_wait; CometPtr->hTarget = ElementPtr->hTarget; if (ElementPtr->state_flags & PLAYER_SHIP) { CometPtr->turn_wait = 0; facing = (COUNT)TFB_Random (); SetVelocityVector (&CometPtr->velocity, COMET_SPEED, facing); } else { CometPtr->velocity = ElementPtr->velocity; CometPtr->hit_points = ElementPtr->hit_points; facing = ANGLE_TO_FACING ( GetVelocityTravelAngle (&CometPtr->velocity) ); } if (CometPtr->turn_wait) --CometPtr->turn_wait; else { facing = NORMALIZE_FACING (facing); if (TrackShip (CometPtr, &facing) > 0) SetVelocityVector (&CometPtr->velocity, COMET_SPEED, facing); CometPtr->turn_wait = COMET_TURN_WAIT; } } UnlockElement (hComet); } return (hComet); } static void turret_preprocess (ELEMENT *ElementPtr) { if (ElementPtr->turn_wait > 0) --ElementPtr->turn_wait; else { ElementPtr->next.image.frame = SetAbsFrameIndex (ElementPtr->current.image.frame, (GetFrameIndex (ElementPtr->current.image.frame) % 10) + 1); ElementPtr->state_flags |= CHANGING; ElementPtr->turn_wait = TURRET_WAIT; } } static void gate_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { if (ElementPtr1->playerNr == RPG_PLAYER_NUM) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr0, &StarShipPtr); if (StarShipPtr->RaceDescPtr->num_generators == 0) { if (!(ElementPtr1->state_flags & FINITE_LIFE)) ElementPtr0->state_flags |= COLLISION; if ((ElementPtr1->state_flags & PLAYER_SHIP) && GetPrimType ( &GLOBAL (DisplayArray[ElementPtr0->PrimIndex]) ) == STAMPFILL_PRIM && GET_GAME_STATE (BOMB_CARRIER)) { GLOBAL (CurrentActivity) &= ~IN_BATTLE; } } else { HELEMENT hBlastElement; if (ElementPtr1->state_flags & PLAYER_SHIP) ElementPtr0->mass_points = GATE_DAMAGE; else ElementPtr0->mass_points = 50; ElementPtr0->hit_points = GATE_HITS; hBlastElement = weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); ElementPtr0->state_flags &= ~(DISAPPEARING | NONSOLID | COLLISION); ElementPtr0->life_span = NORMAL_LIFE; if (hBlastElement) { RemoveElement (hBlastElement); FreeElement (hBlastElement); } } } } static void gate_preprocess (ELEMENT *ElementPtr) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); if (StarShipPtr->RaceDescPtr->num_generators == 0) { ElementPtr->mass_points = SHIP_MASS; ElementPtr->state_flags &= ~FINITE_LIFE; ElementPtr->life_span = NORMAL_LIFE + 1; ElementPtr->preprocess_func = 0; SetPrimColor ( &GLOBAL (DisplayArray[ElementPtr->PrimIndex]), BLACK_COLOR ); SetPrimType ( &GLOBAL (DisplayArray[ElementPtr->PrimIndex]), STAMPFILL_PRIM ); } else { ++ElementPtr->life_span; ElementPtr->next.image.frame = IncFrameIndex (ElementPtr->current.image.frame); if (GetFrameIndex (ElementPtr->next.image.frame) == 0) ElementPtr->next.image.frame = SetAbsFrameIndex ( ElementPtr->next.image.frame, 11 ); ElementPtr->state_flags |= CHANGING; } } static void generator_death (ELEMENT *ElementPtr) { if (!(ElementPtr->state_flags & FINITE_LIFE)) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); --StarShipPtr->RaceDescPtr->num_generators; ElementPtr->state_flags |= FINITE_LIFE | NONSOLID; ElementPtr->preprocess_func = 0; ElementPtr->turn_wait = 12; ElementPtr->thrust_wait = 0; ElementPtr->current.image.frame = SetAbsFrameIndex (ElementPtr->current.image.frame, 10 - 1); } if (ElementPtr->thrust_wait) { --ElementPtr->thrust_wait; ElementPtr->state_flags &= ~DISAPPEARING; ElementPtr->state_flags |= CHANGING; ++ElementPtr->life_span; } else if (ElementPtr->turn_wait--) { ElementPtr->state_flags &= ~DISAPPEARING; ElementPtr->state_flags |= CHANGING; ++ElementPtr->life_span; ElementPtr->next.image.frame = IncFrameIndex ( ElementPtr->current.image.frame ); ElementPtr->thrust_wait = 1; } } static void generator_preprocess (ELEMENT *ElementPtr) { if (ElementPtr->turn_wait > 0) --ElementPtr->turn_wait; else if ((ElementPtr->turn_wait = (BYTE)((GENERATOR_HITS - ElementPtr->hit_points) / 5)) < 3) { ElementPtr->next.image.frame = SetAbsFrameIndex (ElementPtr->current.image.frame, (GetFrameIndex (ElementPtr->current.image.frame) + 1) % 10); ElementPtr->state_flags |= CHANGING; } } static void generator_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { if (!(ElementPtr1->state_flags & FINITE_LIFE)) { ElementPtr0->state_flags |= COLLISION; } (void) pPt0; /* Satisfying compiler (unused parameter) */ (void) pPt1; /* Satisfying compiler (unused parameter) */ } static void sentinel_preprocess (ELEMENT *ElementPtr) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); ++StarShipPtr->RaceDescPtr->characteristics.special_wait; ++ElementPtr->life_span; if (ElementPtr->thrust_wait) --ElementPtr->thrust_wait; else { ElementPtr->next.image.frame = SetAbsFrameIndex (ElementPtr->current.image.frame, (GetFrameIndex (ElementPtr->current.image.frame) + 1) % 6); ElementPtr->state_flags |= CHANGING; ElementPtr->thrust_wait = ANIMATION_WAIT; } if (ElementPtr->turn_wait > 0) --ElementPtr->turn_wait; else { COUNT facing; HELEMENT hTarget; if (!(ElementPtr->state_flags & NONSOLID)) facing = ANGLE_TO_FACING ( GetVelocityTravelAngle (&ElementPtr->velocity) ); else { ElementPtr->state_flags &= ~NONSOLID; facing = (COUNT)TFB_Random (); SetVelocityVector (&ElementPtr->velocity, SENTINEL_SPEED, facing); } facing = NORMALIZE_FACING (facing); if (ElementPtr->hTarget == 0) { COUNT f; f = facing; TrackShip (ElementPtr, &f); } if (ElementPtr->hTarget == 0) hTarget = StarShipPtr->hShip; else if (StarShipPtr->hShip == 0) hTarget = ElementPtr->hTarget; else { SIZE delta_x0, delta_y0, delta_x1, delta_y1; ELEMENT *ShipPtr; ELEMENT *EnemyShipPtr; LockElement (ElementPtr->hTarget, &EnemyShipPtr); LockElement (StarShipPtr->hShip, &ShipPtr); delta_x0 = ShipPtr->current.location.x - ElementPtr->current.location.x; delta_y0 = ShipPtr->current.location.y - ElementPtr->current.location.y; delta_x1 = ShipPtr->current.location.x - EnemyShipPtr->current.location.x; delta_y1 = ShipPtr->current.location.y - EnemyShipPtr->current.location.y; UnlockElement (StarShipPtr->hShip); if ((long)delta_x0 * delta_x0 + (long)delta_y0 * delta_y0 > (long)delta_x1 * delta_x1 + (long)delta_y1 * delta_y1) hTarget = StarShipPtr->hShip; else hTarget = ElementPtr->hTarget; UnlockElement (ElementPtr->hTarget); } if (hTarget) { COUNT num_frames; SIZE delta_x, delta_y; ELEMENT *TargetPtr; VELOCITY_DESC TargetVelocity; LockElement (hTarget, &TargetPtr); delta_x = TargetPtr->current.location.x - ElementPtr->current.location.x; delta_x = WRAP_DELTA_X (delta_x); delta_y = TargetPtr->current.location.y - ElementPtr->current.location.y; delta_y = WRAP_DELTA_Y (delta_y); if ((num_frames = WORLD_TO_TURN ( square_root ((long)delta_x * delta_x + (long)delta_y * delta_y) )) == 0) num_frames = 1; TargetVelocity = TargetPtr->velocity; GetNextVelocityComponents (&TargetVelocity, &delta_x, &delta_y, num_frames); delta_x = (TargetPtr->current.location.x + delta_x) - ElementPtr->current.location.x; delta_x = WRAP_DELTA_X (delta_x); delta_y = (TargetPtr->current.location.y + delta_y) - ElementPtr->current.location.y; delta_y = WRAP_DELTA_Y (delta_y); UnlockElement (hTarget); delta_x = NORMALIZE_FACING ( ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) - facing ); if (delta_x > 0) { if (delta_x <= ANGLE_TO_FACING (HALF_CIRCLE)) ++facing; else --facing; } SetVelocityVector (&ElementPtr->velocity, SENTINEL_SPEED, facing); } ElementPtr->turn_wait = TRACK_WAIT; } } static void sentinel_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { COUNT angle; STARSHIP *StarShipPtr; if (ElementPtr1->playerNr == NPC_PLAYER_NUM) { if (ElementPtr0->preprocess_func == ElementPtr1->preprocess_func && !(ElementPtr0->state_flags & DEFY_PHYSICS) && (pPt0->x != ElementPtr0->IntersectControl.IntersectStamp.origin.x || pPt0->y != ElementPtr0->IntersectControl.IntersectStamp.origin.y)) { angle = ARCTAN (pPt0->x - pPt1->x, pPt0->y - pPt1->y); SetVelocityComponents (&ElementPtr0->velocity, COSINE (angle, WORLD_TO_VELOCITY (SENTINEL_SPEED)), SINE (angle, WORLD_TO_VELOCITY (SENTINEL_SPEED))); ElementPtr0->turn_wait = TRACK_WAIT; ElementPtr0->state_flags |= COLLISION | DEFY_PHYSICS; } } else { BYTE old_hits; COUNT old_life; HELEMENT hBlastElement; old_hits = ElementPtr0->hit_points; old_life = ElementPtr0->life_span; ElementPtr0->blast_offset = 0; hBlastElement = weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); ElementPtr0->thrust_wait = 0; if ((ElementPtr1->state_flags & PLAYER_SHIP) && ElementPtr1->crew_level && !GRAVITY_MASS (ElementPtr1->mass_points + 1)) { SIZE cur_delta_x, cur_delta_y; ElementPtr0->life_span = old_life; ElementPtr0->hit_points = old_hits; ElementPtr0->state_flags &= ~DISAPPEARING; ElementPtr0->state_flags |= DEFY_PHYSICS; ElementPtr0->turn_wait = (ONE_SECOND / BATTLE_FRAME_RATE) >> 1; GetElementStarShip (ElementPtr1, &StarShipPtr); StarShipPtr->cur_status_flags &= ~(SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED); if (ElementPtr1->turn_wait < COLLISION_TURN_WAIT) ElementPtr1->turn_wait += COLLISION_TURN_WAIT; if (ElementPtr1->thrust_wait < COLLISION_THRUST_WAIT) ElementPtr1->thrust_wait += COLLISION_THRUST_WAIT; angle = GetVelocityTravelAngle (&ElementPtr0->velocity); DeltaVelocityComponents (&ElementPtr1->velocity, COSINE (angle, RECOIL_VELOCITY), SINE (angle, RECOIL_VELOCITY)); GetCurrentVelocityComponents (&ElementPtr1->velocity, &cur_delta_x, &cur_delta_y); if ((long)cur_delta_x * (long)cur_delta_x + (long)cur_delta_y * (long)cur_delta_y > (long)MAX_RECOIL_VELOCITY * (long)MAX_RECOIL_VELOCITY) { angle = ARCTAN (cur_delta_x, cur_delta_y); SetVelocityComponents (&ElementPtr1->velocity, COSINE (angle, MAX_RECOIL_VELOCITY), SINE (angle, MAX_RECOIL_VELOCITY)); } ZeroVelocityComponents (&ElementPtr0->velocity); } if (ElementPtr0->state_flags & DISAPPEARING) { GetElementStarShip (ElementPtr0, &StarShipPtr); --StarShipPtr->RaceDescPtr->characteristics.special_wait; if (hBlastElement) { ELEMENT *BlastElementPtr; LockElement (hBlastElement, &BlastElementPtr); BlastElementPtr->life_span = 6; BlastElementPtr->current.image.frame = SetAbsFrameIndex ( BlastElementPtr->current.image.farray[0], 6 ); UnlockElement (hBlastElement); } } } } static void samatra_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, COUNT ConcernCounter) { ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); } static void samatra_postprocess (ELEMENT *ElementPtr) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); if (StarShipPtr->RaceDescPtr->num_generators) { if (StarShipPtr->weapon_counter == 0 && StarShipPtr->RaceDescPtr->characteristics.weapon_wait < MAX_COMETS && spawn_comet (ElementPtr)) { StarShipPtr->weapon_counter = WEAPON_WAIT; } if (StarShipPtr->special_counter == 0 && StarShipPtr->RaceDescPtr->characteristics.special_wait < MAX_SENTINELS) { MISSILE_BLOCK MissileBlock; HELEMENT hSentinel; MissileBlock.cx = ElementPtr->next.location.x; MissileBlock.cy = ElementPtr->next.location.y; MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; MissileBlock.face = 0; MissileBlock.index = 0; MissileBlock.sender = ElementPtr->playerNr; MissileBlock.flags = 0; MissileBlock.pixoffs = 0; MissileBlock.speed = SENTINEL_SPEED; MissileBlock.hit_points = SENTINEL_HITS; MissileBlock.damage = SENTINEL_DAMAGE; MissileBlock.life = SENTINEL_LIFE; MissileBlock.preprocess_func = sentinel_preprocess; MissileBlock.blast_offs = SENTINEL_OFFSET; hSentinel = initialize_missile (&MissileBlock); if (hSentinel) { ELEMENT *SentinelPtr; LockElement (hSentinel, &SentinelPtr); SentinelPtr->collision_func = sentinel_collision; SentinelPtr->turn_wait = TRACK_WAIT + 2; SetElementStarShip (SentinelPtr, StarShipPtr); UnlockElement (hSentinel); StarShipPtr->special_counter = SPECIAL_WAIT; PutElement (hSentinel); } } } } static void samatra_preprocess (ELEMENT *ElementPtr) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); StarShipPtr->RaceDescPtr->characteristics.weapon_wait = 0; StarShipPtr->RaceDescPtr->characteristics.special_wait = 0; if (!(ElementPtr->state_flags & APPEARING)) { ++ElementPtr->turn_wait; ++ElementPtr->thrust_wait; } else { POINT offs[] = { {-127-9, -53+18}, { -38-9, -88+18}, { 44-9, -85+18}, { 127-9, -60+18}, { 124-9, 28+18}, { 73-9, 61+18}, { -87-9, 58+18}, {-136-9, 29+18}, }; for (StarShipPtr->RaceDescPtr->num_generators = 0; StarShipPtr->RaceDescPtr->num_generators < MAX_GENERATORS; ++StarShipPtr->RaceDescPtr->num_generators) { HELEMENT hGenerator; hGenerator = AllocElement (); if (hGenerator) { ELEMENT *GeneratorPtr; LockElement (hGenerator, &GeneratorPtr); GeneratorPtr->hit_points = GENERATOR_HITS; GeneratorPtr->mass_points = MAX_SHIP_MASS * 10; GeneratorPtr->life_span = NORMAL_LIFE; GeneratorPtr->playerNr = ElementPtr->playerNr; GeneratorPtr->state_flags = APPEARING | IGNORE_SIMILAR; SetPrimType ( &GLOBAL (DisplayArray[GeneratorPtr->PrimIndex]), STAMP_PRIM ); GeneratorPtr->current.location.x = ((LOG_SPACE_WIDTH >> 1) + DISPLAY_TO_WORLD (offs[StarShipPtr->RaceDescPtr->num_generators].x)) & ~((SCALED_ONE << MAX_VIS_REDUCTION) - 1); GeneratorPtr->current.location.y = ((LOG_SPACE_HEIGHT >> 1) + DISPLAY_TO_WORLD (offs[StarShipPtr->RaceDescPtr->num_generators].y)) & ~((SCALED_ONE << MAX_VIS_REDUCTION) - 1); GeneratorPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; GeneratorPtr->current.image.frame = SetAbsFrameIndex ( StarShipPtr->RaceDescPtr->ship_data.special[0], (BYTE)TFB_Random () % 10 ); GeneratorPtr->preprocess_func = generator_preprocess; GeneratorPtr->collision_func = generator_collision; GeneratorPtr->death_func = generator_death; SetElementStarShip (GeneratorPtr, StarShipPtr); UnlockElement (hGenerator); InsertElement (hGenerator, GetHeadElement ()); } } { HELEMENT hTurret; hTurret = AllocElement (); if (hTurret) { ELEMENT *TurretPtr; LockElement (hTurret, &TurretPtr); TurretPtr->hit_points = 1; TurretPtr->life_span = NORMAL_LIFE; TurretPtr->playerNr = ElementPtr->playerNr; TurretPtr->state_flags = APPEARING | IGNORE_SIMILAR | NONSOLID; SetPrimType ( &GLOBAL (DisplayArray[TurretPtr->PrimIndex]), STAMP_PRIM ); TurretPtr->current.location.x = LOG_SPACE_WIDTH >> 1; TurretPtr->current.location.y = LOG_SPACE_HEIGHT >> 1; TurretPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.ship; TurretPtr->current.image.frame = SetAbsFrameIndex ( StarShipPtr->RaceDescPtr->ship_data.ship[0], 1 ); TurretPtr->preprocess_func = turret_preprocess; SetElementStarShip (TurretPtr, StarShipPtr); UnlockElement (hTurret); InsertElement (hTurret, GetSuccElement (ElementPtr)); } } { HELEMENT hGate; hGate = AllocElement (); if (hGate) { ELEMENT *GatePtr; LockElement (hGate, &GatePtr); GatePtr->hit_points = GATE_HITS; GatePtr->mass_points = GATE_DAMAGE; GatePtr->life_span = 2; GatePtr->playerNr = ElementPtr->playerNr; GatePtr->state_flags = APPEARING | FINITE_LIFE | IGNORE_SIMILAR; SetPrimType ( &GLOBAL (DisplayArray[GatePtr->PrimIndex]), STAMP_PRIM ); GatePtr->current.location.x = LOG_SPACE_WIDTH >> 1; GatePtr->current.location.y = LOG_SPACE_HEIGHT >> 1; GatePtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.ship; GatePtr->current.image.frame = SetAbsFrameIndex ( StarShipPtr->RaceDescPtr->ship_data.ship[0], 11 ); GatePtr->preprocess_func = gate_preprocess; GatePtr->collision_func = gate_collision; SetElementStarShip (GatePtr, StarShipPtr); UnlockElement (hGate); InsertElement (hGate, GetSuccElement (ElementPtr)); } } StarShipPtr->weapon_counter = WEAPON_WAIT >> 1; StarShipPtr->special_counter = SPECIAL_WAIT >> 1; } } RACE_DESC* init_samatra (void) { RACE_DESC *RaceDescPtr; samatra_desc.preprocess_func = samatra_preprocess; samatra_desc.postprocess_func = samatra_postprocess; samatra_desc.cyborg_control.intelligence_func = samatra_intelligence; RaceDescPtr = &samatra_desc; return (RaceDescPtr); }