From 7f6002caba3f0a6749820c2772161caf55b8d267 Mon Sep 17 00:00:00 2001 From: neonloop Date: Fri, 7 May 2021 20:00:12 +0000 Subject: Initial commit (uqm-0.8.0) --- src/uqm/ships/lastbat/lastbat.c | 926 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 926 insertions(+) create mode 100644 src/uqm/ships/lastbat/lastbat.c (limited to 'src/uqm/ships/lastbat/lastbat.c') diff --git a/src/uqm/ships/lastbat/lastbat.c b/src/uqm/ships/lastbat/lastbat.c new file mode 100644 index 0000000..9d44742 --- /dev/null +++ b/src/uqm/ships/lastbat/lastbat.c @@ -0,0 +1,926 @@ +//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); +} + -- cgit v1.2.3