diff options
Diffstat (limited to 'src/uqm/ships')
142 files changed, 15531 insertions, 0 deletions
diff --git a/src/uqm/ships/Makeinfo b/src/uqm/ships/Makeinfo new file mode 100644 index 0000000..e77d2db --- /dev/null +++ b/src/uqm/ships/Makeinfo @@ -0,0 +1,5 @@ +uqm_SUBDIRS="androsyn arilou blackurq chenjesu chmmr druuge human ilwrath + lastbat melnorme mmrnmhrm mycon orz pkunk probe shofixti sis_ship + slylandr spathi supox syreen thradd umgah urquan utwig vux yehat + zoqfot" +uqm_HFILES="ship.h" diff --git a/src/uqm/ships/androsyn/Makeinfo b/src/uqm/ships/androsyn/Makeinfo new file mode 100644 index 0000000..2f2f511 --- /dev/null +++ b/src/uqm/ships/androsyn/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="androsyn.c" +uqm_HFILES="androsyn.h icode.h resinst.h" diff --git a/src/uqm/ships/androsyn/androsyn.c b/src/uqm/ships/androsyn/androsyn.c new file mode 100644 index 0000000..1139d8d --- /dev/null +++ b/src/uqm/ships/androsyn/androsyn.c @@ -0,0 +1,528 @@ +//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 "androsyn.h" +#include "resinst.h" + +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 20 +#define MAX_ENERGY 24 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 8 +#define MAX_THRUST 24 +#define THRUST_INCREMENT 3 +#define TURN_WAIT 4 +#define THRUST_WAIT 0 +#define SHIP_MASS 6 + +// Bubbles +#define WEAPON_ENERGY_COST 3 +#define WEAPON_WAIT 0 +#define ANDROSYNTH_OFFSET 14 +#define MISSILE_OFFSET 3 +#define MISSILE_SPEED DISPLAY_TO_WORLD (8) +#define MISSILE_LIFE 200 +#define MISSILE_HITS 3 +#define MISSILE_DAMAGE 2 +#define TRACK_WAIT 2 + +// Blazer +#define SPECIAL_ENERGY_COST 2 +#define BLAZER_DEGENERATION (-1) +#define SPECIAL_WAIT 0 +#define BLAZER_OFFSET 10 +#define BLAZER_THRUST 60 +#define BLAZER_TURN_WAIT 1 +#define BLAZER_DAMAGE 3 +#define BLAZER_MASS 1 + +static RACE_DESC androsynth_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | SEEKING_WEAPON, + 15, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + ANDROSYNTH_RACE_STRINGS, + ANDROSYNTH_ICON_MASK_PMAP_ANIM, + ANDROSYNTH_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + INFINITE_RADIUS, /* Initial sphere of influence radius */ + // XXX: Why infinite radius? Bug? + { /* Known location (center of SoI) */ + MAX_X_UNIVERSE >> 1, MAX_Y_UNIVERSE >> 1, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + ANDROSYNTH_BIG_MASK_PMAP_ANIM, + ANDROSYNTH_MED_MASK_PMAP_ANIM, + ANDROSYNTH_SML_MASK_PMAP_ANIM, + }, + { + BUBBLE_BIG_MASK_PMAP_ANIM, + BUBBLE_MED_MASK_PMAP_ANIM, + BUBBLE_SML_MASK_PMAP_ANIM, + }, + { + BLAZER_BIG_MASK_PMAP_ANIM, + BLAZER_MED_MASK_PMAP_ANIM, + BLAZER_SML_MASK_PMAP_ANIM, + }, + { + ANDROSYNTH_CAPT_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + ANDROSYNTH_VICTORY_SONG, + ANDROSYNTH_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + LONG_RANGE_WEAPON >> 2, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + + +// Private per-instance ship data +typedef struct +{ + ElementCollisionFunc* collision_func; +} ANDROSYNTH_DATA; + +// Local typedef +typedef ANDROSYNTH_DATA CustomShipData_t; + +// Retrieve race-specific ship data from a race desc +static CustomShipData_t * +GetCustomShipData (RACE_DESC *pRaceDesc) +{ + return pRaceDesc->data; +} + +// Set the race-specific data in a race desc +// (Re)Allocates its own storage for the data. +static void +SetCustomShipData (RACE_DESC *pRaceDesc, const CustomShipData_t *data) +{ + if (pRaceDesc->data == data) + return; // no-op + + if (pRaceDesc->data) // Out with the old + { + HFree (pRaceDesc->data); + pRaceDesc->data = NULL; + } + + if (data) // In with the new + { + CustomShipData_t* newData = HMalloc (sizeof (*data)); + *newData = *data; + pRaceDesc->data = newData; + } +} + +static void +blazer_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + BYTE old_offs; + COUNT old_crew_level; + COUNT old_life; + + old_crew_level = ElementPtr0->crew_level; + old_life = ElementPtr0->life_span; + old_offs = ElementPtr0->blast_offset; + ElementPtr0->blast_offset = BLAZER_OFFSET; + ElementPtr0->mass_points = BLAZER_DAMAGE; + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + ElementPtr0->mass_points = BLAZER_MASS; + ElementPtr0->blast_offset = old_offs; + ElementPtr0->life_span = old_life; + ElementPtr0->crew_level = old_crew_level; + + ElementPtr0->state_flags &= ~(DISAPPEARING | NONSOLID); + collision (ElementPtr0, pPt0, ElementPtr1, pPt1); +} + +static void +bubble_preprocess (ELEMENT *ElementPtr) +{ + BYTE thrust_wait, turn_wait; + + thrust_wait = HINIBBLE (ElementPtr->turn_wait); + turn_wait = LONIBBLE (ElementPtr->turn_wait); + if (thrust_wait > 0) + --thrust_wait; + else + { + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->current.image.frame); + ElementPtr->state_flags |= CHANGING; + + thrust_wait = (BYTE)((COUNT)TFB_Random () & 3); + } + + if (turn_wait > 0) + --turn_wait; + else + { + COUNT facing; + SIZE delta_facing; + + facing = NORMALIZE_FACING (ANGLE_TO_FACING ( + GetVelocityTravelAngle (&ElementPtr->velocity))); + if ((delta_facing = TrackShip (ElementPtr, &facing)) == -1) + facing = (COUNT)TFB_Random (); + else if (delta_facing <= ANGLE_TO_FACING (HALF_CIRCLE)) + facing += (COUNT)TFB_Random () & (ANGLE_TO_FACING (HALF_CIRCLE) - 1); + else + facing -= (COUNT)TFB_Random () & (ANGLE_TO_FACING (HALF_CIRCLE) - 1); + SetVelocityVector (&ElementPtr->velocity, + MISSILE_SPEED, facing); + turn_wait = TRACK_WAIT; + } + + ElementPtr->turn_wait = MAKE_BYTE (turn_wait, thrust_wait); +} + +static COUNT +initialize_bubble (ELEMENT *ShipPtr, HELEMENT BubbleArray[]) +{ + 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; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.index = 0; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = ANDROSYNTH_OFFSET; + MissileBlock.speed = MISSILE_SPEED; + MissileBlock.hit_points = MISSILE_HITS; + MissileBlock.damage = MISSILE_DAMAGE; + MissileBlock.life = MISSILE_LIFE; + MissileBlock.preprocess_func = bubble_preprocess; + MissileBlock.blast_offs = MISSILE_OFFSET; + BubbleArray[0] = initialize_missile (&MissileBlock); + + if (BubbleArray[0]) + { + ELEMENT *BubblePtr; + + LockElement (BubbleArray[0], &BubblePtr); + BubblePtr->turn_wait = 0; + UnlockElement (BubbleArray[0]); + } + + return (1); +} + +static void +androsynth_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + EVALUATE_DESC *lpEvalDesc; + STARSHIP *StarShipPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + /* in blazer form */ + if (ShipPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.special) + { + ObjectsOfConcern[CREW_OBJECT_INDEX].ObjectPtr = 0; + if (lpEvalDesc->ObjectPtr && lpEvalDesc->MoveState == ENTICE) + { + if ((lpEvalDesc->ObjectPtr->state_flags & FINITE_LIFE) + && !(lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT)) + lpEvalDesc->MoveState = AVOID; + else + lpEvalDesc->ObjectPtr = 0; + } + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + } + else + { + STARSHIP *pEnemyStarShip = NULL; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (lpEvalDesc->ObjectPtr) + { + GetElementStarShip (lpEvalDesc->ObjectPtr, &pEnemyStarShip); + if (lpEvalDesc->which_turn <= 16 + && (StarShipPtr->special_counter > 0 + || StarShipPtr->RaceDescPtr->ship_info.energy_level < MAX_ENERGY / 3 + || ((WEAPON_RANGE (&pEnemyStarShip->RaceDescPtr->cyborg_control) <= CLOSE_RANGE_WEAPON + && lpEvalDesc->ObjectPtr->crew_level > BLAZER_DAMAGE) + || (lpEvalDesc->ObjectPtr->crew_level > (BLAZER_DAMAGE * 3) + && MANEUVERABILITY (&pEnemyStarShip->RaceDescPtr->cyborg_control) > SLOW_SHIP)))) + lpEvalDesc->MoveState = ENTICE; + } + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + if (StarShipPtr->special_counter == 0) + { + StarShipPtr->ship_input_state &= ~SPECIAL; + if ((ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr + && ObjectsOfConcern[ENEMY_WEAPON_INDEX].which_turn <= 4) + || (lpEvalDesc->ObjectPtr + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= MAX_ENERGY / 3 + && (WEAPON_RANGE (&pEnemyStarShip->RaceDescPtr->cyborg_control) >= + WEAPON_RANGE (&StarShipPtr->RaceDescPtr->cyborg_control) << 1 + || (lpEvalDesc->which_turn < 16 + && (WEAPON_RANGE (&pEnemyStarShip->RaceDescPtr->cyborg_control) > CLOSE_RANGE_WEAPON + || lpEvalDesc->ObjectPtr->crew_level <= BLAZER_DAMAGE) + && (lpEvalDesc->ObjectPtr->crew_level <= (BLAZER_DAMAGE * 3) + || MANEUVERABILITY (&pEnemyStarShip->RaceDescPtr->cyborg_control) <= + SLOW_SHIP))))) + StarShipPtr->ship_input_state |= SPECIAL; + } + + if (!(StarShipPtr->ship_input_state & SPECIAL) + && StarShipPtr->weapon_counter == 0 + && lpEvalDesc->ObjectPtr) + { + if (lpEvalDesc->which_turn <= 4) + StarShipPtr->ship_input_state |= WEAPON; + else if (lpEvalDesc->MoveState != PURSUE + && lpEvalDesc->which_turn <= 12) + { + COUNT travel_facing, direction_facing; + SIZE delta_x, delta_y, + ship_delta_x, ship_delta_y, + other_delta_x, other_delta_y; + + GetCurrentVelocityComponents (&ShipPtr->velocity, + &ship_delta_x, &ship_delta_y); + GetCurrentVelocityComponents (&lpEvalDesc->ObjectPtr->velocity, + &other_delta_x, &other_delta_y); + delta_x = ship_delta_x - other_delta_x; + delta_y = ship_delta_y - other_delta_y; + travel_facing = ARCTAN (delta_x, delta_y); + + delta_x = + lpEvalDesc->ObjectPtr->next.location.x - + ShipPtr->next.location.x; + delta_y = + lpEvalDesc->ObjectPtr->next.location.y - + ShipPtr->next.location.y; + direction_facing = ARCTAN (delta_x, delta_y); + + if (NORMALIZE_ANGLE (travel_facing + - direction_facing + OCTANT) <= QUADRANT) + StarShipPtr->ship_input_state |= WEAPON; + } + } + } +} + +static void +androsynth_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + /* take care of blazer effect */ + if (ElementPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.special) + { + if ((StarShipPtr->cur_status_flags & SPECIAL) + || StarShipPtr->RaceDescPtr->ship_info.energy_level == 0) + { + StarShipPtr->RaceDescPtr->characteristics.energy_regeneration = + (BYTE)BLAZER_DEGENERATION; + StarShipPtr->energy_counter = ENERGY_WAIT; + + if (StarShipPtr->cur_status_flags & SPECIAL) + { + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), + ElementPtr); /* COMET_ON */ + ElementPtr->turn_wait = 0; + ElementPtr->thrust_wait = 0; + StarShipPtr->RaceDescPtr->characteristics.special_wait = + StarShipPtr->RaceDescPtr->characteristics.turn_wait; + ElementPtr->mass_points = BLAZER_MASS; + StarShipPtr->RaceDescPtr->characteristics.turn_wait + = BLAZER_TURN_WAIT; + + /* Save the current collision func because we were not the + * ones who set it */ + { + const ANDROSYNTH_DATA shipData = { ElementPtr->collision_func }; + SetCustomShipData (StarShipPtr->RaceDescPtr, &shipData); + ElementPtr->collision_func = blazer_collision; + } + } + } + + if (StarShipPtr->RaceDescPtr->ship_info.energy_level == 0) + /* if blazer wasn't able to change back into ship + * give it a little more juice to try to get out + * of its predicament. + */ + { + DeltaEnergy (ElementPtr, -BLAZER_DEGENERATION); + StarShipPtr->energy_counter = 1; + } + } +} + +static void +androsynth_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + STATUS_FLAGS cur_status_flags; + + GetElementStarShip (ElementPtr, &StarShipPtr); + + cur_status_flags = StarShipPtr->cur_status_flags; + if (ElementPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.ship) + { + if (cur_status_flags & SPECIAL) + { + if (StarShipPtr->RaceDescPtr->ship_info.energy_level < SPECIAL_ENERGY_COST) + DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST); /* so text will flash */ + else + { + cur_status_flags &= ~WEAPON; + + ElementPtr->next.image.farray = + StarShipPtr->RaceDescPtr->ship_data.special; + ElementPtr->next.image.frame = + SetEquFrameIndex (StarShipPtr->RaceDescPtr->ship_data.special[0], + ElementPtr->next.image.frame); + ElementPtr->state_flags |= CHANGING; + } + } + } + else + { + cur_status_flags &= ~(THRUST | WEAPON | SPECIAL); + + /* protection against vux */ + if (StarShipPtr->RaceDescPtr->characteristics.turn_wait > BLAZER_TURN_WAIT) + { + StarShipPtr->RaceDescPtr->characteristics.special_wait += + StarShipPtr->RaceDescPtr->characteristics.turn_wait + - BLAZER_TURN_WAIT; + StarShipPtr->RaceDescPtr->characteristics.turn_wait = BLAZER_TURN_WAIT; + } + + if (StarShipPtr->RaceDescPtr->ship_info.energy_level == 0) + { + ZeroVelocityComponents (&ElementPtr->velocity); + cur_status_flags &= ~(LEFT | RIGHT + | SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED); + + StarShipPtr->RaceDescPtr->characteristics.turn_wait = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + StarShipPtr->RaceDescPtr->characteristics.energy_regeneration = ENERGY_REGENERATION; + ElementPtr->mass_points = SHIP_MASS; + ElementPtr->collision_func = + GetCustomShipData (StarShipPtr->RaceDescPtr)->collision_func; + ElementPtr->next.image.farray = + StarShipPtr->RaceDescPtr->ship_data.ship; + ElementPtr->next.image.frame = + SetEquFrameIndex (StarShipPtr->RaceDescPtr->ship_data.ship[0], + ElementPtr->next.image.frame); + ElementPtr->state_flags |= CHANGING; + } + else + { + if (ElementPtr->thrust_wait) + --ElementPtr->thrust_wait; + else + { + COUNT facing; + + facing = StarShipPtr->ShipFacing; + if (ElementPtr->turn_wait == 0 + && (cur_status_flags & (LEFT | RIGHT))) + { + if (cur_status_flags & LEFT) + --facing; + else + ++facing; + } + + SetVelocityVector (&ElementPtr->velocity, + BLAZER_THRUST, NORMALIZE_FACING (facing)); + cur_status_flags |= SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED; + } + } + } + StarShipPtr->cur_status_flags = cur_status_flags; +} + +static void +uninit_androsynth (RACE_DESC *pRaceDesc) +{ + SetCustomShipData (pRaceDesc, NULL); +} + + +RACE_DESC* +init_androsynth (void) +{ + RACE_DESC *RaceDescPtr; + + androsynth_desc.uninit_func = uninit_androsynth; + androsynth_desc.preprocess_func = androsynth_preprocess; + androsynth_desc.postprocess_func = androsynth_postprocess; + androsynth_desc.init_weapon_func = initialize_bubble; + androsynth_desc.cyborg_control.intelligence_func = androsynth_intelligence; + + RaceDescPtr = &androsynth_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/androsyn/androsyn.h b/src/uqm/ships/androsyn/androsyn.h new file mode 100644 index 0000000..43fe88d --- /dev/null +++ b/src/uqm/ships/androsyn/androsyn.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef ANDROSYN_H +#define ANDROSYN_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_androsynth (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* ANDROSYN_H */ + diff --git a/src/uqm/ships/androsyn/icode.h b/src/uqm/ships/androsyn/icode.h new file mode 100644 index 0000000..67f053a --- /dev/null +++ b/src/uqm/ships/androsyn/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define ANDROSYNTH_CODE "ship.androsynth.code" diff --git a/src/uqm/ships/androsyn/resinst.h b/src/uqm/ships/androsyn/resinst.h new file mode 100644 index 0000000..94b4a3f --- /dev/null +++ b/src/uqm/ships/androsyn/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define ANDROSYNTH_BIG_MASK_PMAP_ANIM "ship.androsynth.graphics.guardian.large" +#define ANDROSYNTH_CAPT_MASK_PMAP_ANIM "ship.androsynth.graphics.captain" +#define ANDROSYNTH_ICON_MASK_PMAP_ANIM "ship.androsynth.icons" +#define ANDROSYNTH_MED_MASK_PMAP_ANIM "ship.androsynth.graphics.guardian.medium" +#define ANDROSYNTH_MICON_MASK_PMAP_ANIM "ship.androsynth.meleeicons" +#define ANDROSYNTH_RACE_STRINGS "ship.androsynth.text" +#define ANDROSYNTH_SHIP_SOUNDS "ship.androsynth.sounds" +#define ANDROSYNTH_SML_MASK_PMAP_ANIM "ship.androsynth.graphics.guardian.small" +#define ANDROSYNTH_VICTORY_SONG "ship.androsynth.ditty" +#define BLAZER_BIG_MASK_PMAP_ANIM "ship.androsynth.graphics.blazer.large" +#define BLAZER_MED_MASK_PMAP_ANIM "ship.androsynth.graphics.blazer.medium" +#define BLAZER_SML_MASK_PMAP_ANIM "ship.androsynth.graphics.blazer.small" +#define BUBBLE_BIG_MASK_PMAP_ANIM "ship.androsynth.graphics.bubble.large" +#define BUBBLE_MED_MASK_PMAP_ANIM "ship.androsynth.graphics.bubble.medium" +#define BUBBLE_SML_MASK_PMAP_ANIM "ship.androsynth.graphics.bubble.small" diff --git a/src/uqm/ships/arilou/Makeinfo b/src/uqm/ships/arilou/Makeinfo new file mode 100644 index 0000000..f132bdd --- /dev/null +++ b/src/uqm/ships/arilou/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="arilou.c" +uqm_HFILES="arilou.h icode.h resinst.h" diff --git a/src/uqm/ships/arilou/arilou.c b/src/uqm/ships/arilou/arilou.c new file mode 100644 index 0000000..78340a3 --- /dev/null +++ b/src/uqm/ships/arilou/arilou.c @@ -0,0 +1,303 @@ +//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 "arilou.h" +#include "resinst.h" + +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 6 +#define MAX_ENERGY 20 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 6 +#define MAX_THRUST /* DISPLAY_TO_WORLD (10) */ 40 +#define THRUST_INCREMENT MAX_THRUST +#define THRUST_WAIT 0 +#define TURN_WAIT 0 +#define SHIP_MASS 1 + +// Tracking Laser +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 1 +#define ARILOU_OFFSET 9 +#define LASER_RANGE DISPLAY_TO_WORLD (100 + ARILOU_OFFSET) + +// Teleporter +#define SPECIAL_ENERGY_COST 3 +#define SPECIAL_WAIT 2 +#define HYPER_LIFE 5 + +static RACE_DESC arilou_desc = +{ + { /* SHIP_INFO */ + /* FIRES_FORE | */ IMMEDIATE_WEAPON, + 16, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + ARILOU_RACE_STRINGS, + ARILOU_ICON_MASK_PMAP_ANIM, + ARILOU_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 250 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 438, 6372, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + ARILOU_BIG_MASK_PMAP_ANIM, + ARILOU_MED_MASK_PMAP_ANIM, + ARILOU_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + WARP_BIG_MASK_PMAP_ANIM, + WARP_MED_MASK_PMAP_ANIM, + WARP_SML_MASK_PMAP_ANIM, + }, + { + ARILOU_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + ARILOU_VICTORY_SONG, + ARILOU_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + LASER_RANGE >> 1, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static COUNT +initialize_autoaim_laser (ELEMENT *ShipPtr, HELEMENT LaserArray[]) +{ + COUNT orig_facing; + SIZE delta_facing; + STARSHIP *StarShipPtr; + LASER_BLOCK LaserBlock; + + GetElementStarShip (ShipPtr, &StarShipPtr); + LaserBlock.face = orig_facing = StarShipPtr->ShipFacing; + if ((delta_facing = TrackShip (ShipPtr, &LaserBlock.face)) > 0) + LaserBlock.face = NORMALIZE_FACING (orig_facing + delta_facing); + ShipPtr->hTarget = 0; + + LaserBlock.cx = ShipPtr->next.location.x; + LaserBlock.cy = ShipPtr->next.location.y; + LaserBlock.ex = COSINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); + LaserBlock.ey = SINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); + LaserBlock.sender = ShipPtr->playerNr; + LaserBlock.flags = IGNORE_SIMILAR; + LaserBlock.pixoffs = ARILOU_OFFSET; + LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x0A), 0x0E); + LaserArray[0] = initialize_laser (&LaserBlock); + + return (1); +} + +static void +arilou_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + StarShipPtr->ship_input_state |= THRUST; + + ObjectsOfConcern[ENEMY_SHIP_INDEX].MoveState = ENTICE; + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + if (StarShipPtr->special_counter == 0) + { + EVALUATE_DESC *lpEvalDesc; + + StarShipPtr->ship_input_state &= ~SPECIAL; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + if (lpEvalDesc->ObjectPtr && lpEvalDesc->which_turn <= 6) + { + BOOLEAN IsTrackingWeapon; + STARSHIP *EnemyStarShipPtr; + + GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); + if (((EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags + & SEEKING_WEAPON) && + lpEvalDesc->ObjectPtr->next.image.farray == + EnemyStarShipPtr->RaceDescPtr->ship_data.weapon) || + ((EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags + & SEEKING_SPECIAL) && + lpEvalDesc->ObjectPtr->next.image.farray == + EnemyStarShipPtr->RaceDescPtr->ship_data.special)) + IsTrackingWeapon = TRUE; + else + IsTrackingWeapon = FALSE; + + if (((lpEvalDesc->ObjectPtr->state_flags & PLAYER_SHIP) /* means IMMEDIATE WEAPON */ + || (IsTrackingWeapon && (lpEvalDesc->which_turn == 1 + || (lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT))) /* FIGHTERS!!! */ + || PlotIntercept (lpEvalDesc->ObjectPtr, ShipPtr, 3, 0)) + && !(TFB_Random () & 3)) + { + StarShipPtr->ship_input_state &= ~(LEFT | RIGHT | THRUST | WEAPON); + StarShipPtr->ship_input_state |= SPECIAL; + } + } + } + if (StarShipPtr->RaceDescPtr->ship_info.energy_level <= SPECIAL_ENERGY_COST << 1) + StarShipPtr->ship_input_state &= ~WEAPON; +} + +static void +arilou_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (!(ElementPtr->state_flags & NONSOLID)) + { + if (ElementPtr->thrust_wait == 0) + { + ZeroVelocityComponents (&ElementPtr->velocity); + StarShipPtr->cur_status_flags &= ~SHIP_AT_MAX_SPEED; + } + + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + /* Special key is pressed; start teleport */ + ZeroVelocityComponents (&ElementPtr->velocity); + StarShipPtr->cur_status_flags &= + ~(SHIP_AT_MAX_SPEED | LEFT | RIGHT | THRUST | WEAPON); + + ElementPtr->state_flags |= NONSOLID | FINITE_LIFE | CHANGING; + ElementPtr->life_span = HYPER_LIFE; + + ElementPtr->next.image.farray = + StarShipPtr->RaceDescPtr->ship_data.special; + ElementPtr->next.image.frame = + StarShipPtr->RaceDescPtr->ship_data.special[0]; + + ProcessSound (SetAbsSoundIndex ( + /* HYPERJUMP */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } + } + else if (ElementPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.special) + { + COUNT life_span; + + StarShipPtr->cur_status_flags = + (StarShipPtr->cur_status_flags + & ~(LEFT | RIGHT | THRUST | WEAPON | SPECIAL)) + | (StarShipPtr->old_status_flags + & (LEFT | RIGHT | THRUST | WEAPON | SPECIAL)); + ++StarShipPtr->weapon_counter; + ++StarShipPtr->special_counter; + ++StarShipPtr->energy_counter; + ++ElementPtr->turn_wait; + ++ElementPtr->thrust_wait; + + if ((life_span = ElementPtr->life_span) == NORMAL_LIFE) + { + /* Ending teleport */ + ElementPtr->state_flags &= ~(NONSOLID | FINITE_LIFE); + ElementPtr->state_flags |= APPEARING; + ElementPtr->current.image.farray = + ElementPtr->next.image.farray = + StarShipPtr->RaceDescPtr->ship_data.ship; + ElementPtr->current.image.frame = + ElementPtr->next.image.frame = + SetAbsFrameIndex (StarShipPtr->RaceDescPtr->ship_data.ship[0], + StarShipPtr->ShipFacing); + InitIntersectStartPoint (ElementPtr); + } + else + { + /* Teleporting in progress */ + --life_span; + if (life_span != 2) + { + if (life_span < 2) + ElementPtr->next.image.frame = + DecFrameIndex (ElementPtr->next.image.frame); + else + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->next.image.frame); + } + else + { + ElementPtr->next.location.x = + WRAP_X (DISPLAY_ALIGN_X (TFB_Random ())); + ElementPtr->next.location.y = + WRAP_Y (DISPLAY_ALIGN_Y (TFB_Random ())); + } + } + + ElementPtr->state_flags |= CHANGING; + } +} + +RACE_DESC* +init_arilou (void) +{ + RACE_DESC *RaceDescPtr; + + arilou_desc.preprocess_func = arilou_preprocess; + arilou_desc.init_weapon_func = initialize_autoaim_laser; + arilou_desc.cyborg_control.intelligence_func = arilou_intelligence; + + RaceDescPtr = &arilou_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/arilou/arilou.h b/src/uqm/ships/arilou/arilou.h new file mode 100644 index 0000000..8e65d58 --- /dev/null +++ b/src/uqm/ships/arilou/arilou.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef ARILOU_H +#define ARILOU_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_arilou (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* ARILOU_H */ + diff --git a/src/uqm/ships/arilou/icode.h b/src/uqm/ships/arilou/icode.h new file mode 100644 index 0000000..81d4fff --- /dev/null +++ b/src/uqm/ships/arilou/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define ARILOU_CODE "ship.arilou.code" diff --git a/src/uqm/ships/arilou/resinst.h b/src/uqm/ships/arilou/resinst.h new file mode 100644 index 0000000..173e222 --- /dev/null +++ b/src/uqm/ships/arilou/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define ARILOU_BIG_MASK_PMAP_ANIM "ship.arilou.graphics.skiff.large" +#define ARILOU_CAPTAIN_MASK_PMAP_ANIM "ship.arilou.graphics.captain" +#define ARILOU_ICON_MASK_PMAP_ANIM "ship.arilou.icons" +#define ARILOU_MED_MASK_PMAP_ANIM "ship.arilou.graphics.skiff.medium" +#define ARILOU_MICON_MASK_PMAP_ANIM "ship.arilou.meleeicons" +#define ARILOU_RACE_STRINGS "ship.arilou.text" +#define ARILOU_SHIP_SOUNDS "ship.arilou.sounds" +#define ARILOU_SML_MASK_PMAP_ANIM "ship.arilou.graphics.skiff.small" +#define ARILOU_VICTORY_SONG "ship.arilou.ditty" +#define WARP_BIG_MASK_PMAP_ANIM "ship.arilou.graphics.warp.large" +#define WARP_MED_MASK_PMAP_ANIM "ship.arilou.graphics.warp.medium" +#define WARP_SML_MASK_PMAP_ANIM "ship.arilou.graphics.warp.small" diff --git a/src/uqm/ships/blackurq/Makeinfo b/src/uqm/ships/blackurq/Makeinfo new file mode 100644 index 0000000..62ca12e --- /dev/null +++ b/src/uqm/ships/blackurq/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="blackurq.c" +uqm_HFILES="blackurq.h icode.h resinst.h" diff --git a/src/uqm/ships/blackurq/blackurq.c b/src/uqm/ships/blackurq/blackurq.c new file mode 100644 index 0000000..286191d --- /dev/null +++ b/src/uqm/ships/blackurq/blackurq.c @@ -0,0 +1,567 @@ +//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 "blackurq.h" +#include "resinst.h" + +#include "uqm/globdata.h" + +// Core characteristics +#define MAX_CREW MAX_CREW_SIZE +#define MAX_ENERGY MAX_ENERGY_SIZE +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 4 +#define MAX_THRUST 30 +#define THRUST_INCREMENT 6 +#define TURN_WAIT 4 +#define THRUST_WAIT 6 +#define SHIP_MASS 10 + +// Buzzsaw +#define WEAPON_ENERGY_COST 6 +#define WEAPON_WAIT 6 +#define MISSILE_OFFSET 9 +#define KOHR_AH_OFFSET 28 +#define MISSILE_SPEED 64 +#define MISSILE_LIFE 64 + /* actually, it's as long as you hold the button down.*/ +#define MISSILE_HITS 10 +#define MISSILE_DAMAGE 4 +#define SAW_RATE 0 +#define MAX_SAWS 8 +#define ACTIVATE_RANGE 224 + /* Originally SPACE_WIDTH - the distance within which + * stationary sawblades will home */ +#define TRACK_WAIT 4 +#define FRAGMENT_SPEED MISSILE_SPEED +#define FRAGMENT_LIFE 10 +#define FRAGMENT_RANGE (FRAGMENT_LIFE * FRAGMENT_SPEED) + +// F.R.I.E.D. +#define SPECIAL_ENERGY_COST (MAX_ENERGY_SIZE / 2) +#define SPECIAL_WAIT 9 +#define GAS_OFFSET 2 +#define GAS_SPEED 16 +#define GAS_RATE 2 /* Controls animation of the gas cloud decay - the decay + * animation advances one frame every GAS_RATE frames. */ +#define GAS_HITS 100 +#define GAS_DAMAGE 3 +#define GAS_ALT_DAMAGE 50 +#define NUM_GAS_CLOUDS 16 + +static RACE_DESC black_urquan_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 30, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + KOHR_AH_RACE_STRINGS, + KOHR_AH_ICON_MASK_PMAP_ANIM, + KOHR_AH_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 2666 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 6000, 6250, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + KOHR_AH_BIG_MASK_PMAP_ANIM, + KOHR_AH_MED_MASK_PMAP_ANIM, + KOHR_AH_SML_MASK_PMAP_ANIM, + }, + { + BUZZSAW_BIG_MASK_PMAP_ANIM, + BUZZSAW_MED_MASK_PMAP_ANIM, + BUZZSAW_SML_MASK_PMAP_ANIM, + }, + { + GAS_BIG_MASK_PMAP_ANIM, + GAS_MED_MASK_PMAP_ANIM, + GAS_SML_MASK_PMAP_ANIM, + }, + { + KOHR_AH_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + KOHR_AH_VICTORY_SONG, + KOHR_AH_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + CLOSE_RANGE_WEAPON, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +spin_preprocess (ELEMENT *ElementPtr) +{ + ELEMENT *ShipPtr; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + LockElement (StarShipPtr->hShip, &ShipPtr); + if (ShipPtr->crew_level + && ++StarShipPtr->RaceDescPtr->characteristics.special_wait > MAX_SAWS) + { + ElementPtr->life_span = 1; + ElementPtr->state_flags |= DISAPPEARING; + } + else + { + ++ElementPtr->life_span; + if (ElementPtr->turn_wait) + --ElementPtr->turn_wait; + else + { +#define LAST_SPIN_INDEX 1 + if (GetFrameIndex ( + ElementPtr->current.image.frame + ) < LAST_SPIN_INDEX) + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->current.image.frame); + else + ElementPtr->next.image.frame = + SetAbsFrameIndex (ElementPtr->current.image.frame, 0); + ElementPtr->state_flags |= CHANGING; + + ElementPtr->turn_wait = SAW_RATE; + } + } + UnlockElement (StarShipPtr->hShip); +} + +static void +buzztrack_preprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->thrust_wait) + --ElementPtr->thrust_wait; + else + { + COUNT facing = 0; + + if (ElementPtr->hTarget == 0 + && TrackShip (ElementPtr, &facing) < 0) + { + ZeroVelocityComponents (&ElementPtr->velocity); + } + else + { + SIZE delta_x, delta_y; + ELEMENT *eptr; + + LockElement (ElementPtr->hTarget, &eptr); + delta_x = eptr->current.location.x + - ElementPtr->current.location.x; + delta_y = eptr->current.location.y + - ElementPtr->current.location.y; + UnlockElement (ElementPtr->hTarget); + delta_x = WRAP_DELTA_X (delta_x); + delta_y = WRAP_DELTA_Y (delta_y); + facing = NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) + ); + + if (delta_x < 0) + delta_x = -delta_x; + if (delta_y < 0) + delta_y = -delta_y; + delta_x = WORLD_TO_DISPLAY (delta_x); + delta_y = WORLD_TO_DISPLAY (delta_y); + if (delta_x >= ACTIVATE_RANGE + || delta_y >= ACTIVATE_RANGE + || (DWORD)((UWORD)delta_x * delta_x) + + (DWORD)((UWORD)delta_y * delta_y) >= + (DWORD)ACTIVATE_RANGE * ACTIVATE_RANGE) + { + ZeroVelocityComponents (&ElementPtr->velocity); + } + else + { + ElementPtr->thrust_wait = TRACK_WAIT; + SetVelocityVector (&ElementPtr->velocity, + DISPLAY_TO_WORLD (2), facing); + } + } + } + + spin_preprocess (ElementPtr); +} + +static void +decelerate_preprocess (ELEMENT *ElementPtr) +{ + SIZE dx, dy; + + GetCurrentVelocityComponents (&ElementPtr->velocity, &dx, &dy); + dx /= 2; + dy /= 2; + SetVelocityComponents (&ElementPtr->velocity, dx, dy); + if (dx == 0 && dy == 0) + { + ElementPtr->preprocess_func = buzztrack_preprocess; + } + + spin_preprocess (ElementPtr); +} + +static void +splinter_preprocess (ELEMENT *ElementPtr) +{ + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->current.image.frame); + ElementPtr->state_flags |= CHANGING; +} + +static void +buzzsaw_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + + if (ElementPtr0->state_flags & DISAPPEARING) + { + ElementPtr0->state_flags &= ~DISAPPEARING; + ElementPtr0->state_flags |= NONSOLID | CHANGING; + ElementPtr0->life_span = 5; + ElementPtr0->next.image.frame = + SetAbsFrameIndex (ElementPtr0->current.image.frame, 2); + + ElementPtr0->preprocess_func = splinter_preprocess; + } +} + +static void +buzzsaw_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (!(StarShipPtr->cur_status_flags & WEAPON)) + { + ElementPtr->life_span >>= 1; + ElementPtr->preprocess_func = decelerate_preprocess; + } + + spin_preprocess (ElementPtr); +} + +static void +buzzsaw_postprocess (ELEMENT *ElementPtr) +{ + HELEMENT hElement; + + ElementPtr->postprocess_func = 0; + hElement = AllocElement (); + if (hElement) + { + COUNT primIndex; + ELEMENT *ListElementPtr; + STARSHIP *StarShipPtr; + + LockElement (hElement, &ListElementPtr); + primIndex = ListElementPtr->PrimIndex; + *ListElementPtr = *ElementPtr; + ListElementPtr->PrimIndex = primIndex; + (GLOBAL (DisplayArray))[primIndex] = + (GLOBAL (DisplayArray))[ElementPtr->PrimIndex]; + ListElementPtr->current = ListElementPtr->next; + InitIntersectStartPoint (ListElementPtr); + InitIntersectEndPoint (ListElementPtr); + ListElementPtr->state_flags = (ListElementPtr->state_flags + & ~(PRE_PROCESS | CHANGING | APPEARING)) + | POST_PROCESS; + UnlockElement (hElement); + + GetElementStarShip (ElementPtr, &StarShipPtr); + LockElement (StarShipPtr->hShip, &ListElementPtr); + InsertElement (hElement, GetSuccElement (ListElementPtr)); + UnlockElement (StarShipPtr->hShip); + + ElementPtr->life_span = 0; + } +} + +static COUNT +initialize_buzzsaw (ELEMENT *ShipPtr, HELEMENT SawArray[]) +{ + 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; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.index = 0; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = KOHR_AH_OFFSET; + MissileBlock.speed = MISSILE_SPEED; + MissileBlock.hit_points = MISSILE_HITS; + MissileBlock.damage = MISSILE_DAMAGE; + MissileBlock.life = MISSILE_LIFE; + MissileBlock.preprocess_func = buzzsaw_preprocess; + MissileBlock.blast_offs = MISSILE_OFFSET; + SawArray[0] = initialize_missile (&MissileBlock); + + if (SawArray[0]) + { + ELEMENT *SawPtr; + + LockElement (SawArray[0], &SawPtr); + SawPtr->turn_wait = SAW_RATE; + SawPtr->thrust_wait = 0; + SawPtr->postprocess_func = buzzsaw_postprocess; + SawPtr->collision_func = buzzsaw_collision; + UnlockElement (SawArray[0]); + } + + return (1); +} + +static void +black_urquan_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + EVALUATE_DESC *lpEvalDesc; + STARSHIP *StarShipPtr; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + if (lpEvalDesc->ObjectPtr + && lpEvalDesc->MoveState == ENTICE + && (lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT) + && lpEvalDesc->which_turn <= 8) + lpEvalDesc->MoveState = PURSUE; + + ship_intelligence (ShipPtr, + ObjectsOfConcern, ConcernCounter); + + GetElementStarShip (ShipPtr, &StarShipPtr); + StarShipPtr->ship_input_state &= ~SPECIAL; + + if (StarShipPtr->special_counter == 0 + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= SPECIAL_ENERGY_COST + && lpEvalDesc->ObjectPtr + && lpEvalDesc->which_turn <= 8) + StarShipPtr->ship_input_state |= SPECIAL; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (lpEvalDesc->ObjectPtr) + { + HELEMENT h, hNext; + ELEMENT *BuzzSawPtr; + + h = (StarShipPtr->old_status_flags & WEAPON) ? + GetSuccElement (ShipPtr) : (HELEMENT)0; + for (; h; h = hNext) + { + LockElement (h, &BuzzSawPtr); + hNext = GetSuccElement (BuzzSawPtr); + if (!(BuzzSawPtr->state_flags & NONSOLID) + && BuzzSawPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.weapon + && BuzzSawPtr->life_span > MISSILE_LIFE * 3 / 4 + && elementsOfSamePlayer (BuzzSawPtr, ShipPtr)) + { + { + //COUNT which_turn; + + if (!PlotIntercept (BuzzSawPtr, + lpEvalDesc->ObjectPtr, BuzzSawPtr->life_span, + FRAGMENT_RANGE / 2)) + StarShipPtr->ship_input_state &= ~WEAPON; + else if (StarShipPtr->weapon_counter == 0) + StarShipPtr->ship_input_state |= WEAPON; + + UnlockElement (h); + break; + } + hNext = 0; + } + UnlockElement (h); + } + + if (h == 0) + { + if (StarShipPtr->old_status_flags & WEAPON) + StarShipPtr->ship_input_state &= ~WEAPON; + else if (StarShipPtr->weapon_counter == 0 + && ship_weapons (ShipPtr, lpEvalDesc->ObjectPtr, FRAGMENT_RANGE / 2)) + StarShipPtr->ship_input_state |= WEAPON; + + if (StarShipPtr->special_counter == 0 + && !(StarShipPtr->ship_input_state & WEAPON) + && lpEvalDesc->which_turn <= 8 + && (StarShipPtr->ship_input_state & (LEFT | RIGHT)) + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= + SPECIAL_ENERGY_COST) + StarShipPtr->ship_input_state |= SPECIAL; + } + } +} + +static void +gas_cloud_preprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->turn_wait) + --ElementPtr->turn_wait; + else + { + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->current.image.frame); + ElementPtr->state_flags |= CHANGING; + + ElementPtr->turn_wait = GAS_RATE; + } +} + +static void +gas_cloud_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + if (ElementPtr1->state_flags & PLAYER_SHIP) + ElementPtr0->mass_points = GAS_DAMAGE; + else + ElementPtr0->mass_points = GAS_ALT_DAMAGE; + + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); +} + +static void +spawn_gas_cloud (ELEMENT *ElementPtr) +{ + SIZE dx, dy; + STARSHIP *StarShipPtr; + MISSILE_BLOCK MissileBlock; + + GetElementStarShip (ElementPtr, &StarShipPtr); + MissileBlock.cx = ElementPtr->next.location.x; + MissileBlock.cy = ElementPtr->next.location.y; + MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.special; + MissileBlock.index = 0; + MissileBlock.sender = ElementPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = 20; + MissileBlock.speed = GAS_SPEED; + MissileBlock.hit_points = GAS_HITS; + MissileBlock.damage = GAS_DAMAGE; + MissileBlock.life = + GetFrameCount (MissileBlock.farray[0]) * (GAS_RATE + 1) - 1; + MissileBlock.preprocess_func = gas_cloud_preprocess; + MissileBlock.blast_offs = GAS_OFFSET; + + GetCurrentVelocityComponents (&ElementPtr->velocity, &dx, &dy); + for (MissileBlock.face = 0; + MissileBlock.face < ANGLE_TO_FACING (FULL_CIRCLE); + MissileBlock.face += + (ANGLE_TO_FACING (FULL_CIRCLE) / NUM_GAS_CLOUDS)) + { + HELEMENT hGasCloud; + + hGasCloud = initialize_missile (&MissileBlock); + if (hGasCloud) + { + ELEMENT *GasCloudPtr; + + LockElement (hGasCloud, &GasCloudPtr); + SetElementStarShip (GasCloudPtr, StarShipPtr); + GasCloudPtr->hTarget = 0; + GasCloudPtr->turn_wait = GAS_RATE - 1; + GasCloudPtr->collision_func = gas_cloud_collision; + DeltaVelocityComponents (&GasCloudPtr->velocity, dx, dy); + UnlockElement (hGasCloud); + PutElement (hGasCloud); + } + } +} + +static void +black_urquan_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + spawn_gas_cloud (ElementPtr); + + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + + StarShipPtr->special_counter = SPECIAL_WAIT; + } +} + +static void +black_urquan_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + /* no spinning disks */ + StarShipPtr->RaceDescPtr->characteristics.special_wait = 0; + if (StarShipPtr->weapon_counter == 0 + && (StarShipPtr->cur_status_flags + & StarShipPtr->old_status_flags & WEAPON)) + ++StarShipPtr->weapon_counter; +} + +RACE_DESC* +init_black_urquan (void) +{ + RACE_DESC *RaceDescPtr; + + black_urquan_desc.preprocess_func = black_urquan_preprocess; + black_urquan_desc.postprocess_func = black_urquan_postprocess; + black_urquan_desc.init_weapon_func = initialize_buzzsaw; + black_urquan_desc.cyborg_control.intelligence_func = black_urquan_intelligence; + + RaceDescPtr = &black_urquan_desc; + + return (RaceDescPtr); +} diff --git a/src/uqm/ships/blackurq/blackurq.h b/src/uqm/ships/blackurq/blackurq.h new file mode 100644 index 0000000..4b2b5d9 --- /dev/null +++ b/src/uqm/ships/blackurq/blackurq.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef BLACKURQ_H +#define BLACKURQ_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_black_urquan (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* BLACKURQ_H */ + diff --git a/src/uqm/ships/blackurq/icode.h b/src/uqm/ships/blackurq/icode.h new file mode 100644 index 0000000..99c0ca2 --- /dev/null +++ b/src/uqm/ships/blackurq/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define KOHR_AH_CODE "ship.kohrah.code" diff --git a/src/uqm/ships/blackurq/resinst.h b/src/uqm/ships/blackurq/resinst.h new file mode 100644 index 0000000..840f519 --- /dev/null +++ b/src/uqm/ships/blackurq/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define BUZZSAW_BIG_MASK_PMAP_ANIM "ship.kohrah.graphics.buzzsaw.large" +#define BUZZSAW_MED_MASK_PMAP_ANIM "ship.kohrah.graphics.buzzsaw.medium" +#define BUZZSAW_SML_MASK_PMAP_ANIM "ship.kohrah.graphics.buzzsaw.small" +#define GAS_BIG_MASK_PMAP_ANIM "ship.kohrah.graphics.gas.large" +#define GAS_MED_MASK_PMAP_ANIM "ship.kohrah.graphics.gas.medium" +#define GAS_SML_MASK_PMAP_ANIM "ship.kohrah.graphics.gas.small" +#define KOHR_AH_BIG_MASK_PMAP_ANIM "ship.kohrah.graphics.marauder.large" +#define KOHR_AH_CAPTAIN_MASK_PMAP_ANIM "ship.kohrah.graphics.captain" +#define KOHR_AH_ICON_MASK_PMAP_ANIM "ship.kohrah.icons" +#define KOHR_AH_MED_MASK_PMAP_ANIM "ship.kohrah.graphics.marauder.medium" +#define KOHR_AH_MICON_MASK_PMAP_ANIM "ship.kohrah.meleeicons" +#define KOHR_AH_RACE_STRINGS "ship.kohrah.text" +#define KOHR_AH_SHIP_SOUNDS "ship.kohrah.sounds" +#define KOHR_AH_SML_MASK_PMAP_ANIM "ship.kohrah.graphics.marauder.small" +#define KOHR_AH_VICTORY_SONG "ship.kohrah.ditty" diff --git a/src/uqm/ships/chenjesu/Makeinfo b/src/uqm/ships/chenjesu/Makeinfo new file mode 100644 index 0000000..3f10d6a --- /dev/null +++ b/src/uqm/ships/chenjesu/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="chenjesu.c" +uqm_HFILES="chenjesu.h icode.h resinst.h" diff --git a/src/uqm/ships/chenjesu/chenjesu.c b/src/uqm/ships/chenjesu/chenjesu.c new file mode 100644 index 0000000..85a1014 --- /dev/null +++ b/src/uqm/ships/chenjesu/chenjesu.c @@ -0,0 +1,588 @@ +//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 "chenjesu.h" +#include "resinst.h" + +#include "uqm/globdata.h" +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 36 +#define MAX_ENERGY 30 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 4 +#define MAX_THRUST /* DISPLAY_TO_WORLD (7) */ 27 +#define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 3 +#define THRUST_WAIT 4 +#define TURN_WAIT 6 +#define SHIP_MASS 10 + +// Photon Shard +#define WEAPON_ENERGY_COST 5 +#define WEAPON_WAIT 0 +#define CHENJESU_OFFSET 16 +#define MISSILE_OFFSET 0 +#define MISSILE_SPEED DISPLAY_TO_WORLD (16) +#define MISSILE_LIFE 90 + /* actually, it's as long as you hold the button down. */ +#define MISSILE_HITS 10 +#define MISSILE_DAMAGE 6 +#define NUM_SPARKLES 8 + +// Shrapnel +#define FRAGMENT_OFFSET 2 +#define NUM_FRAGMENTS 8 +#define FRAGMENT_LIFE 10 +#define FRAGMENT_SPEED MISSILE_SPEED +#define FRAGMENT_RANGE (FRAGMENT_LIFE * FRAGMENT_SPEED) + /* This bit is for the cyborg only. */ +#define FRAGMENT_HITS 1 +#define FRAGMENT_DAMAGE 2 + +// DOGI +#define SPECIAL_ENERGY_COST MAX_ENERGY +#define SPECIAL_WAIT 0 +#define DOGGY_OFFSET 18 +#define DOGGY_SPEED DISPLAY_TO_WORLD (8) +#define ENERGY_DRAIN 10 +#define MAX_DOGGIES 4 +#define DOGGY_HITS 3 +#define DOGGY_MASS 4 + +static RACE_DESC chenjesu_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | SEEKING_SPECIAL | SEEKING_WEAPON, + 28, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + CHENJESU_RACE_STRINGS, + CHENJESU_ICON_MASK_PMAP_ANIM, + CHENJESU_MICON_MASK_PMAP_ANIM, + 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, + }, + { + { + CHENJESU_BIG_MASK_PMAP_ANIM, + CHENJESU_MED_MASK_PMAP_ANIM, + CHENJESU_SML_MASK_PMAP_ANIM, + }, + { + SPARK_BIG_MASK_PMAP_ANIM, + SPARK_MED_MASK_PMAP_ANIM, + SPARK_SML_MASK_PMAP_ANIM, + }, + { + DOGGY_BIG_MASK_PMAP_ANIM, + DOGGY_MED_MASK_PMAP_ANIM, + DOGGY_SML_MASK_PMAP_ANIM, + }, + { + CHENJESU_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + CHENJESU_VICTORY_SONG, + CHENJESU_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + LONG_RANGE_WEAPON, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +crystal_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + MISSILE_BLOCK MissileBlock; + + GetElementStarShip (ElementPtr, &StarShipPtr); + MissileBlock.cx = ElementPtr->next.location.x; + MissileBlock.cy = ElementPtr->next.location.y; + MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; + MissileBlock.index = 1; + MissileBlock.sender = ElementPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = 0; + MissileBlock.speed = FRAGMENT_SPEED; + MissileBlock.hit_points = FRAGMENT_HITS; + MissileBlock.damage = FRAGMENT_DAMAGE; + MissileBlock.life = FRAGMENT_LIFE; + MissileBlock.preprocess_func = NULL; + MissileBlock.blast_offs = FRAGMENT_OFFSET; + + for (MissileBlock.face = 0; + MissileBlock.face < ANGLE_TO_FACING (FULL_CIRCLE); + MissileBlock.face += + (ANGLE_TO_FACING (FULL_CIRCLE) / NUM_FRAGMENTS)) + { + HELEMENT hFragment; + + hFragment = initialize_missile (&MissileBlock); + if (hFragment) + { + ELEMENT *FragPtr; + + LockElement (hFragment, &FragPtr); + SetElementStarShip (FragPtr, StarShipPtr); + UnlockElement (hFragment); + PutElement (hFragment); + } + } + + ProcessSound (SetAbsSoundIndex ( + /* CRYSTAL_FRAGMENTS */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); +} + +static void +crystal_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (StarShipPtr->cur_status_flags & WEAPON) + ++ElementPtr->life_span; /* keep it going while key pressed */ + else + { + ElementPtr->life_span = 1; + + ElementPtr->postprocess_func = crystal_postprocess; + } +} + +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 +crystal_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + HELEMENT hBlastElement; + + hBlastElement = + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + if (hBlastElement) + { + ELEMENT *BlastElementPtr; + + LockElement (hBlastElement, &BlastElementPtr); + BlastElementPtr->current.location = ElementPtr1->current.location; + + BlastElementPtr->life_span = NUM_SPARKLES; + BlastElementPtr->turn_wait = BlastElementPtr->next_turn = 0; + { + BlastElementPtr->preprocess_func = animate; + } + + BlastElementPtr->current.image.farray = ElementPtr0->next.image.farray; + BlastElementPtr->current.image.frame = + SetAbsFrameIndex (BlastElementPtr->current.image.farray[0], + 2); /* skip stones */ + + UnlockElement (hBlastElement); + } +} + +static void +doggy_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + ++StarShipPtr->special_counter; + if (ElementPtr->thrust_wait > 0) /* could be non-zero after a collision */ + --ElementPtr->thrust_wait; + else + { + COUNT facing, orig_facing; + SIZE delta_facing; + + facing = orig_facing = + NORMALIZE_FACING (ANGLE_TO_FACING ( + GetVelocityTravelAngle (&ElementPtr->velocity) + )); + if ((delta_facing = TrackShip (ElementPtr, &facing)) < 0) + facing = NORMALIZE_FACING (TFB_Random ()); + else + { + ELEMENT *ShipPtr; + + LockElement (ElementPtr->hTarget, &ShipPtr); + facing = NORMALIZE_FACING (ANGLE_TO_FACING ( + ARCTAN (ShipPtr->current.location.x - + ElementPtr->current.location.x, + ShipPtr->current.location.y - + ElementPtr->current.location.y) + )); + delta_facing = NORMALIZE_FACING (facing - + GetFrameIndex (ShipPtr->current.image.frame)); + UnlockElement (ElementPtr->hTarget); + + if (delta_facing > ANGLE_TO_FACING (HALF_CIRCLE - OCTANT) && + delta_facing < ANGLE_TO_FACING (HALF_CIRCLE + OCTANT)) + { + if (delta_facing >= ANGLE_TO_FACING (HALF_CIRCLE)) + facing -= ANGLE_TO_FACING (QUADRANT); + else + facing += ANGLE_TO_FACING (QUADRANT); + } + + facing = NORMALIZE_FACING (facing); + } + + if (facing != orig_facing) + SetVelocityVector (&ElementPtr->velocity, + DOGGY_SPEED, facing); + } +} + +static void +doggy_death (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + ProcessSound (SetAbsSoundIndex ( + /* DOGGY_DIES */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 3), ElementPtr); + + ElementPtr->state_flags &= ~DISAPPEARING; + ElementPtr->state_flags |= NONSOLID | FINITE_LIFE; + ElementPtr->life_span = 6; + { + ElementPtr->preprocess_func = animate; + } + ElementPtr->death_func = NULL; + ElementPtr->collision_func = NULL; + ZeroVelocityComponents (&ElementPtr->velocity); + + ElementPtr->turn_wait = ElementPtr->next_turn = 0; +} + +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_doggy (ELEMENT *ElementPtr) +{ + HELEMENT hDoggyElement; + + if ((hDoggyElement = AllocElement ()) != 0) + { + COUNT angle; + ELEMENT *DoggyElementPtr; + STARSHIP *StarShipPtr; + + ElementPtr->state_flags |= DEFY_PHYSICS; + + PutElement (hDoggyElement); + LockElement (hDoggyElement, &DoggyElementPtr); + DoggyElementPtr->hit_points = DOGGY_HITS; + DoggyElementPtr->mass_points = DOGGY_MASS; + DoggyElementPtr->thrust_wait = 0; + DoggyElementPtr->playerNr = ElementPtr->playerNr; + DoggyElementPtr->state_flags = APPEARING; + DoggyElementPtr->life_span = NORMAL_LIFE; + SetPrimType (&(GLOBAL (DisplayArray))[DoggyElementPtr->PrimIndex], + STAMP_PRIM); + { + DoggyElementPtr->preprocess_func = doggy_preprocess; + DoggyElementPtr->postprocess_func = NULL; + DoggyElementPtr->collision_func = doggy_collision; + DoggyElementPtr->death_func = doggy_death; + } + + GetElementStarShip (ElementPtr, &StarShipPtr); + angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing) + HALF_CIRCLE; + DoggyElementPtr->current.location.x = ElementPtr->next.location.x + + COSINE (angle, DISPLAY_TO_WORLD (CHENJESU_OFFSET + DOGGY_OFFSET)); + DoggyElementPtr->current.location.y = ElementPtr->next.location.y + + SINE (angle, DISPLAY_TO_WORLD (CHENJESU_OFFSET + DOGGY_OFFSET)); + DoggyElementPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; + DoggyElementPtr->current.image.frame = StarShipPtr->RaceDescPtr->ship_data.special[0]; + + SetVelocityVector (&DoggyElementPtr->velocity, + DOGGY_SPEED, NORMALIZE_FACING (ANGLE_TO_FACING (angle))); + + SetElementStarShip (DoggyElementPtr, StarShipPtr); + + ProcessSound (SetAbsSoundIndex ( + /* RELEASE_DOGGY */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 4), DoggyElementPtr); + + UnlockElement (hDoggyElement); + } +} + +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; + } +} + +static COUNT +initialize_crystal (ELEMENT *ShipPtr, HELEMENT CrystalArray[]) +{ + 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; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.index = 0; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = CHENJESU_OFFSET; + MissileBlock.speed = MISSILE_SPEED; + MissileBlock.hit_points = MISSILE_HITS; + MissileBlock.damage = MISSILE_DAMAGE; + MissileBlock.life = MISSILE_LIFE; + MissileBlock.preprocess_func = crystal_preprocess; + MissileBlock.blast_offs = MISSILE_OFFSET; + CrystalArray[0] = initialize_missile (&MissileBlock); + + if (CrystalArray[0]) + { + ELEMENT *CrystalPtr; + + LockElement (CrystalArray[0], &CrystalPtr); + CrystalPtr->collision_func = crystal_collision; + UnlockElement (CrystalArray[0]); + } + + return (1); +} + +static void +chenjesu_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter < MAX_DOGGIES + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + spawn_doggy (ElementPtr); + } + + StarShipPtr->special_counter = 1; + /* say there is one doggy, because ship_postprocess will + * decrement special_counter */ +} + +static void +chenjesu_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (StarShipPtr->special_counter > 1) /* only when STANDARD + * computer opponent + */ + StarShipPtr->special_counter += MAX_DOGGIES; + if (StarShipPtr->cur_status_flags + & StarShipPtr->old_status_flags + & WEAPON) + ++StarShipPtr->weapon_counter; +} + +RACE_DESC* +init_chenjesu (void) +{ + RACE_DESC *RaceDescPtr; + + chenjesu_desc.preprocess_func = chenjesu_preprocess; + chenjesu_desc.postprocess_func = chenjesu_postprocess; + chenjesu_desc.init_weapon_func = initialize_crystal; + chenjesu_desc.cyborg_control.intelligence_func = chenjesu_intelligence; + + RaceDescPtr = &chenjesu_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/chenjesu/chenjesu.h b/src/uqm/ships/chenjesu/chenjesu.h new file mode 100644 index 0000000..37ac9d6 --- /dev/null +++ b/src/uqm/ships/chenjesu/chenjesu.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef CHENJESU_H +#define CHENJESU_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_chenjesu (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* CHENJESU_H */ + diff --git a/src/uqm/ships/chenjesu/icode.h b/src/uqm/ships/chenjesu/icode.h new file mode 100644 index 0000000..1f4b693 --- /dev/null +++ b/src/uqm/ships/chenjesu/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define CHENJESU_CODE "ship.chenjesu.code" diff --git a/src/uqm/ships/chenjesu/resinst.h b/src/uqm/ships/chenjesu/resinst.h new file mode 100644 index 0000000..966029a --- /dev/null +++ b/src/uqm/ships/chenjesu/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define CHENJESU_BIG_MASK_PMAP_ANIM "ship.chenjesu.graphics.broodhome.large" +#define CHENJESU_CAPTAIN_MASK_PMAP_ANIM "ship.chenjesu.graphics.captain" +#define CHENJESU_ICON_MASK_PMAP_ANIM "ship.chenjesu.icons" +#define CHENJESU_MED_MASK_PMAP_ANIM "ship.chenjesu.graphics.broodhome.medium" +#define CHENJESU_MICON_MASK_PMAP_ANIM "ship.chenjesu.meleeicons" +#define CHENJESU_RACE_STRINGS "ship.chenjesu.text" +#define CHENJESU_SHIP_SOUNDS "ship.chenjesu.sounds" +#define CHENJESU_SML_MASK_PMAP_ANIM "ship.chenjesu.graphics.broodhome.small" +#define CHENJESU_VICTORY_SONG "ship.chenjesu.ditty" +#define DOGGY_BIG_MASK_PMAP_ANIM "ship.chenjesu.graphics.doggy.large" +#define DOGGY_MED_MASK_PMAP_ANIM "ship.chenjesu.graphics.doggy.medium" +#define DOGGY_SML_MASK_PMAP_ANIM "ship.chenjesu.graphics.doggy.small" +#define SPARK_BIG_MASK_PMAP_ANIM "ship.chenjesu.graphics.spark.large" +#define SPARK_MED_MASK_PMAP_ANIM "ship.chenjesu.graphics.spark.medium" +#define SPARK_SML_MASK_PMAP_ANIM "ship.chenjesu.graphics.spark.small" diff --git a/src/uqm/ships/chmmr/Makeinfo b/src/uqm/ships/chmmr/Makeinfo new file mode 100644 index 0000000..70b8bc6 --- /dev/null +++ b/src/uqm/ships/chmmr/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="chmmr.c" +uqm_HFILES="chmmr.h icode.h resinst.h" diff --git a/src/uqm/ships/chmmr/chmmr.c b/src/uqm/ships/chmmr/chmmr.c new file mode 100644 index 0000000..8f6abf0 --- /dev/null +++ b/src/uqm/ships/chmmr/chmmr.c @@ -0,0 +1,790 @@ +//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 "chmmr.h" +#include "resinst.h" + +#include "uqm/colors.h" +#include "uqm/globdata.h" +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW MAX_CREW_SIZE +#define MAX_ENERGY MAX_ENERGY_SIZE +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 1 +#define MAX_THRUST 35 +#define THRUST_INCREMENT 7 +#define THRUST_WAIT 5 +#define TURN_WAIT 3 +#define SHIP_MASS 10 + +// Laser +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 0 +#define CHMMR_OFFSET 18 +#define LASER_RANGE DISPLAY_TO_WORLD (150) +#define NUM_CYCLES 4 + +// Tractor Beam +#define SPECIAL_ENERGY_COST 1 +#define SPECIAL_WAIT 0 +#define NUM_SHADOWS 5 + +// Satellites +#define NUM_SATELLITES 3 +#define SATELLITE_OFFSET DISPLAY_TO_WORLD (64) +#define SATELLITE_HITPOINTS 10 +#define SATELLITE_MASS 10 +#define DEFENSE_RANGE (UWORD)64 +#define DEFENSE_WAIT 2 + +static RACE_DESC chmmr_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | IMMEDIATE_WEAPON | SEEKING_SPECIAL | POINT_DEFENSE, + 30, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + CHMMR_RACE_STRINGS, + CHMMR_ICON_MASK_PMAP_ANIM, + CHMMR_MICON_MASK_PMAP_ANIM, + 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, + }, + { + { + CHMMR_BIG_MASK_PMAP_ANIM, + CHMMR_MED_MASK_PMAP_ANIM, + CHMMR_SML_MASK_PMAP_ANIM, + }, + { + MUZZLE_BIG_MASK_PMAP_ANIM, + MUZZLE_MED_MASK_PMAP_ANIM, + MUZZLE_SML_MASK_PMAP_ANIM, + }, + { + SATELLITE_BIG_MASK_PMAP_ANIM, + SATELLITE_MED_MASK_PMAP_ANIM, + SATELLITE_SML_MASK_PMAP_ANIM, + }, + { + CHMMR_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + CHMMR_VICTORY_SONG, + CHMMR_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + CLOSE_RANGE_WEAPON, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +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 +laser_death (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + StarShipPtr->special_counter = ElementPtr->turn_wait; + + if (StarShipPtr->hShip) + { + SIZE dx, dy; + long dist; + HELEMENT hIonSpots; + ELEMENT *ShipPtr; + + LockElement (StarShipPtr->hShip, &ShipPtr); + + dx = ElementPtr->current.location.x + - ShipPtr->current.location.x; + dy = ElementPtr->current.location.y + - ShipPtr->current.location.y; + if (((BYTE)TFB_Random () & 0x07) + && (dist = (long)dx * dx + (long)dy * dy) >= + (long)DISPLAY_TO_WORLD (CHMMR_OFFSET + 10) + * DISPLAY_TO_WORLD (CHMMR_OFFSET + 10) + && (hIonSpots = AllocElement ())) + { + COUNT angle, magnitude; + ELEMENT *IonSpotsPtr; + + LockElement (hIonSpots, &IonSpotsPtr); + IonSpotsPtr->playerNr = ElementPtr->playerNr; + IonSpotsPtr->state_flags = FINITE_LIFE | NONSOLID + | IGNORE_SIMILAR | APPEARING; + IonSpotsPtr->turn_wait = IonSpotsPtr->next_turn = 0; + IonSpotsPtr->life_span = 9; + + angle = ARCTAN (dx, dy); + magnitude = ((COUNT)TFB_Random () + % ((square_root (dist) + 1) + - DISPLAY_TO_WORLD (CHMMR_OFFSET + 10))) + + DISPLAY_TO_WORLD (CHMMR_OFFSET + 10); + IonSpotsPtr->current.location.x = + ShipPtr->current.location.x + + COSINE (angle, magnitude); + IonSpotsPtr->current.location.y = + ShipPtr->current.location.y + + SINE (angle, magnitude); + IonSpotsPtr->current.image.farray = + StarShipPtr->RaceDescPtr->ship_data.weapon; + IonSpotsPtr->current.image.frame = SetAbsFrameIndex ( + StarShipPtr->RaceDescPtr->ship_data.weapon[0], + ANGLE_TO_FACING (FULL_CIRCLE) << 1 + ); + + IonSpotsPtr->preprocess_func = animate; + + SetElementStarShip (IonSpotsPtr, StarShipPtr); + + SetPrimType (&(GLOBAL (DisplayArray))[ + IonSpotsPtr->PrimIndex + ], STAMP_PRIM); + + UnlockElement (hIonSpots); + PutElement (hIonSpots); + } + + UnlockElement (StarShipPtr->hShip); + } +} + +static COUNT +initialize_megawatt_laser (ELEMENT *ShipPtr, HELEMENT LaserArray[]) +{ + RECT r; + STARSHIP *StarShipPtr; + LASER_BLOCK LaserBlock; + static const Color cycle_array[] = + { + BUILD_COLOR (MAKE_RGB15_INIT (0x17, 0x00, 0x00), 0x2B), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x03, 0x00), 0x7F), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x11, 0x00), 0x7B), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x03, 0x00), 0x7F), + }; + + GetElementStarShip (ShipPtr, &StarShipPtr); + LaserBlock.face = StarShipPtr->ShipFacing; + GetFrameRect (SetAbsFrameIndex ( + StarShipPtr->RaceDescPtr->ship_data.weapon[0], LaserBlock.face + ), &r); + LaserBlock.cx = DISPLAY_ALIGN (ShipPtr->next.location.x) + + DISPLAY_TO_WORLD (r.corner.x); + LaserBlock.cy = DISPLAY_ALIGN (ShipPtr->next.location.y) + + DISPLAY_TO_WORLD (r.corner.y); + LaserBlock.ex = COSINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); + LaserBlock.ey = SINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); + LaserBlock.sender = ShipPtr->playerNr; + LaserBlock.flags = IGNORE_SIMILAR; + LaserBlock.pixoffs = 0; + LaserBlock.color = cycle_array[StarShipPtr->special_counter]; + LaserArray[0] = initialize_laser (&LaserBlock); + + if (LaserArray[0]) + { + ELEMENT *LaserPtr; + + LockElement (LaserArray[0], &LaserPtr); + + LaserPtr->mass_points = 2; + LaserPtr->death_func = laser_death; + LaserPtr->turn_wait = (BYTE)((StarShipPtr->special_counter + 1) + % NUM_CYCLES); + + UnlockElement (LaserArray[0]); + } + + return (1); +} + +static void +chmmr_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + STARSHIP *StarShipPtr; + EVALUATE_DESC *lpEvalDesc; + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + GetElementStarShip (ShipPtr, &StarShipPtr); + StarShipPtr->ship_input_state &= ~SPECIAL; + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (StarShipPtr->special_counter == 0 + && lpEvalDesc->ObjectPtr + && !(StarShipPtr->ship_input_state & WEAPON) + && lpEvalDesc->which_turn > 12 + && NORMALIZE_ANGLE ( + GetVelocityTravelAngle (&ShipPtr->velocity) + - (GetVelocityTravelAngle (&lpEvalDesc->ObjectPtr->velocity) + + HALF_CIRCLE) + QUADRANT + ) > HALF_CIRCLE) + StarShipPtr->ship_input_state |= SPECIAL; +} + +static void +chmmr_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + + if (StarShipPtr->cur_status_flags & WEAPON) + { + HELEMENT hMuzzleFlash; + ELEMENT *MuzzleFlashPtr; + + LockElement (GetTailElement (), &MuzzleFlashPtr); + if (MuzzleFlashPtr != ElementPtr + && elementsOfSamePlayer (MuzzleFlashPtr, ElementPtr) + && (MuzzleFlashPtr->state_flags & APPEARING) + && GetPrimType (&(GLOBAL (DisplayArray))[ + MuzzleFlashPtr->PrimIndex + ]) == LINE_PRIM + && !(StarShipPtr->special_counter & 1) + && (hMuzzleFlash = AllocElement ())) + { + LockElement (hMuzzleFlash, &MuzzleFlashPtr); + MuzzleFlashPtr->playerNr = ElementPtr->playerNr; + MuzzleFlashPtr->state_flags = FINITE_LIFE | NONSOLID + | IGNORE_SIMILAR | APPEARING; + MuzzleFlashPtr->life_span = 1; + + MuzzleFlashPtr->current = ElementPtr->next; + MuzzleFlashPtr->current.image.farray = + StarShipPtr->RaceDescPtr->ship_data.weapon; + MuzzleFlashPtr->current.image.frame = SetAbsFrameIndex ( + StarShipPtr->RaceDescPtr->ship_data.weapon[0], + StarShipPtr->ShipFacing + ANGLE_TO_FACING (FULL_CIRCLE) + ); + + SetElementStarShip (MuzzleFlashPtr, StarShipPtr); + + SetPrimType (&(GLOBAL (DisplayArray))[ + MuzzleFlashPtr->PrimIndex + ], STAMP_PRIM); + + UnlockElement (hMuzzleFlash); + PutElement (hMuzzleFlash); + } + UnlockElement (GetTailElement ()); + } + + if ((StarShipPtr->cur_status_flags & SPECIAL) + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + COUNT facing; + ELEMENT *ShipElementPtr; + + LockElement (ElementPtr->hTarget, &ShipElementPtr); + + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), + ShipElementPtr); + + UnlockElement (ElementPtr->hTarget); + + facing = 0; + if (TrackShip (ElementPtr, &facing) >= 0) + { + ELEMENT *ShipElementPtr; + + LockElement (ElementPtr->hTarget, &ShipElementPtr); + if (!GRAVITY_MASS (ShipElementPtr->mass_points + 1)) + { + SIZE i, dx, dy; + COUNT angle, magnitude; + STARSHIP *EnemyStarShipPtr; + static const SIZE shadow_offs[] = + { + DISPLAY_TO_WORLD (8), + DISPLAY_TO_WORLD (8 + 9), + DISPLAY_TO_WORLD (8 + 9 + 11), + DISPLAY_TO_WORLD (8 + 9 + 11 + 14), + DISPLAY_TO_WORLD (8 + 9 + 11 + 14 + 18), + }; + static const Color color_tab[] = + { + BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x10), 0x53), + BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x0E), 0x54), + BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x0C), 0x55), + BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x09), 0x56), + BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x07), 0x57), + }; + DWORD current_speed, max_speed; + + // calculate tractor beam effect + angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); + dx = (ElementPtr->next.location.x + + COSINE (angle, (LASER_RANGE / 3) + + DISPLAY_TO_WORLD (CHMMR_OFFSET))) + - ShipElementPtr->next.location.x; + dy = (ElementPtr->next.location.y + + SINE (angle, (LASER_RANGE / 3) + + DISPLAY_TO_WORLD (CHMMR_OFFSET))) + - ShipElementPtr->next.location.y; + angle = ARCTAN (dx, dy); + magnitude = WORLD_TO_VELOCITY (12) / + ShipElementPtr->mass_points; + DeltaVelocityComponents (&ShipElementPtr->velocity, + COSINE (angle, magnitude), SINE (angle, magnitude)); + + GetCurrentVelocityComponents (&ShipElementPtr->velocity, + &dx, &dy); + GetElementStarShip (ShipElementPtr, &EnemyStarShipPtr); + + // set the effected ship's speed flags + current_speed = VelocitySquared (dx, dy); + max_speed = VelocitySquared (WORLD_TO_VELOCITY ( + EnemyStarShipPtr->RaceDescPtr->characteristics.max_thrust), + 0); + EnemyStarShipPtr->cur_status_flags &= ~(SHIP_AT_MAX_SPEED + | SHIP_BEYOND_MAX_SPEED); + if (current_speed > max_speed) + EnemyStarShipPtr->cur_status_flags |= (SHIP_AT_MAX_SPEED + | SHIP_BEYOND_MAX_SPEED); + else if (current_speed == max_speed) + EnemyStarShipPtr->cur_status_flags |= SHIP_AT_MAX_SPEED; + + // add tractor beam graphical effects + for (i = 0; i < NUM_SHADOWS; ++i) + { + HELEMENT hShadow; + + hShadow = AllocElement (); + if (hShadow) + { + ELEMENT *ShadowElementPtr; + + LockElement (hShadow, &ShadowElementPtr); + ShadowElementPtr->playerNr = ShipElementPtr->playerNr; + ShadowElementPtr->state_flags = FINITE_LIFE | NONSOLID + | IGNORE_SIMILAR | POST_PROCESS; + ShadowElementPtr->life_span = 1; + + ShadowElementPtr->current = ShipElementPtr->next; + ShadowElementPtr->current.location.x += + COSINE (angle, shadow_offs[i]); + ShadowElementPtr->current.location.y += + SINE (angle, shadow_offs[i]); + ShadowElementPtr->next = ShadowElementPtr->current; + + SetElementStarShip (ShadowElementPtr, EnemyStarShipPtr); + SetVelocityComponents (&ShadowElementPtr->velocity, + dx, dy); + + SetPrimType (&(GLOBAL (DisplayArray))[ + ShadowElementPtr->PrimIndex + ], STAMPFILL_PRIM); + SetPrimColor (&(GLOBAL (DisplayArray))[ + ShadowElementPtr->PrimIndex + ], color_tab[i]); + + UnlockElement (hShadow); + InsertElement (hShadow, GetHeadElement ()); + } + } + } + UnlockElement (ElementPtr->hTarget); + } + } + + StarShipPtr->special_counter = 0; +} + +static void +satellite_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + ++ElementPtr->life_span; + + ElementPtr->next.image.frame = + SetAbsFrameIndex (ElementPtr->current.image.frame, + (GetFrameIndex (ElementPtr->current.image.frame) + 1) & 7); + ElementPtr->state_flags |= CHANGING; + + ElementPtr->turn_wait = (BYTE)NORMALIZE_ANGLE ( + ElementPtr->turn_wait + 1 + ); + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (StarShipPtr->hShip) + { + SIZE dx, dy; + ELEMENT *ShipPtr; + + StarShipPtr->RaceDescPtr->ship_info.ship_flags |= POINT_DEFENSE; + + LockElement (StarShipPtr->hShip, &ShipPtr); + + dx = (ShipPtr->next.location.x + + COSINE (ElementPtr->turn_wait, SATELLITE_OFFSET)) + - ElementPtr->current.location.x; + dy = (ShipPtr->next.location.y + + SINE (ElementPtr->turn_wait, SATELLITE_OFFSET)) + - ElementPtr->current.location.y; + dx = WRAP_DELTA_X (dx); + dy = WRAP_DELTA_Y (dy); + if ((long)dx * dx + (long)dy * dy + <= DISPLAY_TO_WORLD (20L) * DISPLAY_TO_WORLD (20L)) + SetVelocityComponents (&ElementPtr->velocity, + WORLD_TO_VELOCITY (dx), + WORLD_TO_VELOCITY (dy)); + else + { + COUNT angle; + + angle = ARCTAN (dx, dy); + SetVelocityComponents (&ElementPtr->velocity, + COSINE (angle, WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (20))), + SINE (angle, WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (20)))); + } + + UnlockElement (StarShipPtr->hShip); + } +} + +static void +spawn_point_defense (ELEMENT *ElementPtr) +{ + BYTE weakest; + UWORD best_dist; + STARSHIP *StarShipPtr; + HELEMENT hObject, hNextObject, hBestObject; + ELEMENT *ShipPtr; + ELEMENT *SattPtr; + ELEMENT *ObjectPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + hBestObject = 0; + best_dist = DEFENSE_RANGE + 1; + weakest = 255; + LockElement (StarShipPtr->hShip, &ShipPtr); + LockElement (ElementPtr->hTarget, &SattPtr); + for (hObject = GetPredElement (ElementPtr); + hObject; hObject = hNextObject) + { + LockElement (hObject, &ObjectPtr); + hNextObject = GetPredElement (ObjectPtr); + if (!elementsOfSamePlayer (ObjectPtr, ShipPtr) + && ObjectPtr->playerNr != NEUTRAL_PLAYER_NUM + && CollisionPossible (ObjectPtr, ShipPtr) + && !OBJECT_CLOAKED (ObjectPtr)) + { + SIZE delta_x, delta_y; + UWORD dist; + + delta_x = ObjectPtr->next.location.x + - SattPtr->next.location.x; + delta_y = ObjectPtr->next.location.y + - SattPtr->next.location.y; + if (delta_x < 0) + delta_x = -delta_x; + if (delta_y < 0) + delta_y = -delta_y; + delta_x = WORLD_TO_DISPLAY (delta_x); + delta_y = WORLD_TO_DISPLAY (delta_y); + if ((UWORD)delta_x <= DEFENSE_RANGE && + (UWORD)delta_y <= DEFENSE_RANGE && + (dist = + (UWORD)delta_x * (UWORD)delta_x + + (UWORD)delta_y * (UWORD)delta_y) <= + DEFENSE_RANGE * DEFENSE_RANGE + && (ObjectPtr->hit_points < weakest + || (ObjectPtr->hit_points == weakest + && dist < best_dist))) + { + hBestObject = hObject; + best_dist = dist; + weakest = ObjectPtr->hit_points; + } + } + UnlockElement (hObject); + } + + if (hBestObject) + { + LASER_BLOCK LaserBlock; + HELEMENT hPointDefense; + + LockElement (hBestObject, &ObjectPtr); + + LaserBlock.cx = SattPtr->next.location.x; + LaserBlock.cy = SattPtr->next.location.y; + LaserBlock.face = 0; + LaserBlock.ex = ObjectPtr->next.location.x + - SattPtr->next.location.x; + LaserBlock.ey = ObjectPtr->next.location.y + - SattPtr->next.location.y; + LaserBlock.sender = SattPtr->playerNr; + LaserBlock.flags = IGNORE_SIMILAR; + LaserBlock.pixoffs = 0; + LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x00, 0x01, 0x1F), 0x4D); + hPointDefense = initialize_laser (&LaserBlock); + if (hPointDefense) + { + ELEMENT *PDPtr; + + LockElement (hPointDefense, &PDPtr); + SetElementStarShip (PDPtr, StarShipPtr); + PDPtr->hTarget = 0; + UnlockElement (hPointDefense); + + PutElement (hPointDefense); + + SattPtr->thrust_wait = DEFENSE_WAIT; + } + + UnlockElement (hBestObject); + } + + UnlockElement (ElementPtr->hTarget); + UnlockElement (StarShipPtr->hShip); +} + +static void +satellite_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + if (ElementPtr->thrust_wait || ElementPtr->life_span == 0) + --ElementPtr->thrust_wait; + else + { + HELEMENT hDefense; + + hDefense = AllocElement (); + if (hDefense) + { + ELEMENT *DefensePtr; + + PutElement (hDefense); + + LockElement (hDefense, &DefensePtr); + DefensePtr->playerNr = ElementPtr->playerNr; + DefensePtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE; + + { + ELEMENT *SuccPtr; + + LockElement (GetSuccElement (ElementPtr), &SuccPtr); + DefensePtr->hTarget = GetPredElement (SuccPtr); + UnlockElement (GetSuccElement (ElementPtr)); + + DefensePtr->death_func = spawn_point_defense; + } + + GetElementStarShip (ElementPtr, &StarShipPtr); + SetElementStarShip (DefensePtr, StarShipPtr); + + UnlockElement (hDefense); + } + } +} + +static void +satellite_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + (void) ElementPtr0; /* Satisfying compiler (unused parameter) */ + (void) pPt0; /* Satisfying compiler (unused parameter) */ + (void) ElementPtr1; /* Satisfying compiler (unused parameter) */ + (void) pPt1; /* Satisfying compiler (unused parameter) */ +} + +static void +satellite_death (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + StarShipPtr->RaceDescPtr->ship_info.ship_flags &= ~POINT_DEFENSE; + + ElementPtr->state_flags &= ~DISAPPEARING; + ElementPtr->state_flags |= NONSOLID | FINITE_LIFE | CHANGING; + ElementPtr->life_span = 4; + ElementPtr->turn_wait = 1; + ElementPtr->next_turn = 0; + ElementPtr->next.image.frame = + SetAbsFrameIndex (ElementPtr->current.image.frame, 8); + + ElementPtr->preprocess_func = animate; + ElementPtr->death_func = NULL; + ElementPtr->postprocess_func = NULL; + ElementPtr->collision_func = NULL; +} + +static void +spawn_satellites (ELEMENT *ElementPtr) +{ + COUNT i; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (StarShipPtr->hShip) + { + LockElement (StarShipPtr->hShip, &ElementPtr); + for (i = 0; i < NUM_SATELLITES; ++i) + { + HELEMENT hSatellite; + + hSatellite = AllocElement (); + if (hSatellite) + { + COUNT angle; + ELEMENT *SattPtr; + + LockElement (hSatellite, &SattPtr); + SattPtr->playerNr = ElementPtr->playerNr; + SattPtr->state_flags = IGNORE_SIMILAR | APPEARING + | FINITE_LIFE; + SattPtr->life_span = NORMAL_LIFE + 1; + SattPtr->hit_points = SATELLITE_HITPOINTS; + SattPtr->mass_points = SATELLITE_MASS; + + angle = (i * FULL_CIRCLE + (NUM_SATELLITES >> 1)) + / NUM_SATELLITES; + SattPtr->turn_wait = (BYTE)angle; + SattPtr->current.location.x = ElementPtr->next.location.x + + COSINE (angle, SATELLITE_OFFSET); + SattPtr->current.location.y = ElementPtr->next.location.y + + SINE (angle, SATELLITE_OFFSET); + SattPtr->current.image.farray = + StarShipPtr->RaceDescPtr->ship_data.special; + SattPtr->current.image.frame = SetAbsFrameIndex ( + StarShipPtr->RaceDescPtr->ship_data.special[0], + (COUNT)TFB_Random () & 0x07 + ); + + SattPtr->preprocess_func = satellite_preprocess; + SattPtr->postprocess_func = satellite_postprocess; + SattPtr->death_func = satellite_death; + SattPtr->collision_func = satellite_collision; + + SetElementStarShip (SattPtr, StarShipPtr); + + SetPrimType (&(GLOBAL (DisplayArray))[ + SattPtr->PrimIndex + ], STAMP_PRIM); + + UnlockElement (hSatellite); + PutElement (hSatellite); + } + } + UnlockElement (StarShipPtr->hShip); + } +} + +static void +chmmr_preprocess (ELEMENT *ElementPtr) +{ + HELEMENT hSatellite; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + hSatellite = AllocElement (); + if (hSatellite) + { + ELEMENT *SattPtr; + STARSHIP *StarShipPtr; + + LockElement (hSatellite, &SattPtr); + SattPtr->playerNr = ElementPtr->playerNr; + SattPtr->state_flags = FINITE_LIFE | NONSOLID | IGNORE_SIMILAR + | APPEARING; + SattPtr->life_span = HYPERJUMP_LIFE + 1; + + SattPtr->death_func = spawn_satellites; + + GetElementStarShip (ElementPtr, &StarShipPtr); + SetElementStarShip (SattPtr, StarShipPtr); + + SetPrimType (&(GLOBAL (DisplayArray))[ + SattPtr->PrimIndex + ], NO_PRIM); + + UnlockElement (hSatellite); + PutElement (hSatellite); + } + + StarShipPtr->RaceDescPtr->preprocess_func = 0; +} + +RACE_DESC* +init_chmmr (void) +{ + RACE_DESC *RaceDescPtr; + + chmmr_desc.preprocess_func = chmmr_preprocess; + chmmr_desc.postprocess_func = chmmr_postprocess; + chmmr_desc.init_weapon_func = initialize_megawatt_laser; + chmmr_desc.cyborg_control.intelligence_func = chmmr_intelligence; + + RaceDescPtr = &chmmr_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/chmmr/chmmr.h b/src/uqm/ships/chmmr/chmmr.h new file mode 100644 index 0000000..88dd9b8 --- /dev/null +++ b/src/uqm/ships/chmmr/chmmr.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef CHMMR_H +#define CHMMR_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_chmmr (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* CHMMR_H */ + diff --git a/src/uqm/ships/chmmr/icode.h b/src/uqm/ships/chmmr/icode.h new file mode 100644 index 0000000..0873a15 --- /dev/null +++ b/src/uqm/ships/chmmr/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define CHMMR_CODE "ship.chmmr.code" diff --git a/src/uqm/ships/chmmr/resinst.h b/src/uqm/ships/chmmr/resinst.h new file mode 100644 index 0000000..a830273 --- /dev/null +++ b/src/uqm/ships/chmmr/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define CHMMR_BIG_MASK_PMAP_ANIM "ship.chmmr.graphics.avatar.large" +#define CHMMR_CAPTAIN_MASK_PMAP_ANIM "ship.chmmr.graphics.captain" +#define CHMMR_ICON_MASK_PMAP_ANIM "ship.chmmr.icons" +#define CHMMR_MED_MASK_PMAP_ANIM "ship.chmmr.graphics.avatar.medium" +#define CHMMR_MICON_MASK_PMAP_ANIM "ship.chmmr.meleeicons" +#define CHMMR_RACE_STRINGS "ship.chmmr.text" +#define CHMMR_SHIP_SOUNDS "ship.chmmr.sounds" +#define CHMMR_SML_MASK_PMAP_ANIM "ship.chmmr.graphics.avatar.small" +#define CHMMR_VICTORY_SONG "ship.chmmr.ditty" +#define MUZZLE_BIG_MASK_PMAP_ANIM "ship.chmmr.graphics.muzzle.large" +#define MUZZLE_MED_MASK_PMAP_ANIM "ship.chmmr.graphics.muzzle.medium" +#define MUZZLE_SML_MASK_PMAP_ANIM "ship.chmmr.graphics.muzzle.small" +#define SATELLITE_BIG_MASK_PMAP_ANIM "ship.chmmr.graphics.satellite.large" +#define SATELLITE_MED_MASK_PMAP_ANIM "ship.chmmr.graphics.satellite.medium" +#define SATELLITE_SML_MASK_PMAP_ANIM "ship.chmmr.graphics.satellite.small" diff --git a/src/uqm/ships/druuge/Makeinfo b/src/uqm/ships/druuge/Makeinfo new file mode 100644 index 0000000..6687b56 --- /dev/null +++ b/src/uqm/ships/druuge/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="druuge.c" +uqm_HFILES="druuge.h icode.h resinst.h" diff --git a/src/uqm/ships/druuge/druuge.c b/src/uqm/ships/druuge/druuge.c new file mode 100644 index 0000000..6ba2591 --- /dev/null +++ b/src/uqm/ships/druuge/druuge.c @@ -0,0 +1,324 @@ +//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 "druuge.h" +#include "resinst.h" + +// Core characteristics +#define MAX_CREW 14 +#define MAX_ENERGY 32 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 50 +#define MAX_THRUST 20 +#define THRUST_INCREMENT 2 +#define THRUST_WAIT 1 +#define TURN_WAIT 4 +#define SHIP_MASS 5 + +// Mass Driver +#define WEAPON_ENERGY_COST 4 +#define WEAPON_WAIT 10 +#define DRUUGE_OFFSET 24 +#define MISSILE_OFFSET 6 +#define MISSILE_SPEED DISPLAY_TO_WORLD (30) +#define MISSILE_LIFE 20 +#define MISSILE_RANGE (MISSILE_SPEED * MISSILE_LIFE) +#define MISSILE_HITS 4 +#define MISSILE_DAMAGE 6 +#define RECOIL_VELOCITY WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (6)) +#define MAX_RECOIL_VELOCITY (RECOIL_VELOCITY * 4) + +// Furnace +#define SPECIAL_ENERGY_COST 16 +#define SPECIAL_WAIT 30 + +static RACE_DESC druuge_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 17, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + DRUUGE_RACE_STRINGS, + DRUUGE_ICON_MASK_PMAP_ANIM, + DRUUGE_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 1400 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 9500, 2792, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + DRUUGE_BIG_MASK_PMAP_ANIM, + DRUUGE_MED_MASK_PMAP_ANIM, + DRUUGE_SML_MASK_PMAP_ANIM, + }, + { + DRUUGE_CANNON_BIG_MASK_PMAP_ANIM, + DRUUGE_CANNON_MED_MASK_PMAP_ANIM, + DRUUGE_CANNON_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + DRUUGE_CAPT_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + DRUUGE_VICTORY_SONG, + DRUUGE_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + MISSILE_RANGE, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +cannon_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + + if ((ElementPtr1->state_flags & PLAYER_SHIP) + && ElementPtr1->crew_level + && !GRAVITY_MASS (ElementPtr1->mass_points + 1)) + { + COUNT angle; + SIZE cur_delta_x, cur_delta_y; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr1, &StarShipPtr); + StarShipPtr->cur_status_flags &= + ~(SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED); + + angle = FACING_TO_ANGLE ( + GetFrameIndex (ElementPtr0->next.image.frame) + ); + 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)); + } + } +} + +static COUNT +initialize_cannon (ELEMENT *ShipPtr, HELEMENT CannonArray[]) +{ + 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; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.index = MissileBlock.face; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = DRUUGE_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; + CannonArray[0] = initialize_missile (&MissileBlock); + + if (CannonArray[0]) + { + ELEMENT *CannonPtr; + + LockElement (CannonArray[0], &CannonPtr); + CannonPtr->collision_func = cannon_collision; + UnlockElement (CannonArray[0]); + } + + return (1); +} + +static void +druuge_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + UWORD ship_flags = 0; + STARSHIP *StarShipPtr; + STARSHIP *EnemyStarShipPtr = NULL; + EVALUATE_DESC *lpEvalDesc; + + GetElementStarShip (ShipPtr, &StarShipPtr); + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (StarShipPtr->cur_status_flags & SHIP_BEYOND_MAX_SPEED) + lpEvalDesc->MoveState = ENTICE; + else if (lpEvalDesc->ObjectPtr + && lpEvalDesc->which_turn <= WORLD_TO_TURN (MISSILE_RANGE * 3 / 4)) + { + GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); + ship_flags = EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags; + EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags &= + ~(FIRES_FORE | FIRES_RIGHT | FIRES_AFT | FIRES_LEFT); + + lpEvalDesc->MoveState = PURSUE; + if (ShipPtr->thrust_wait == 0) + ++ShipPtr->thrust_wait; + } + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + if (EnemyStarShipPtr) + { + EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags = ship_flags; + } + + if (!(StarShipPtr->cur_status_flags & SHIP_BEYOND_MAX_SPEED) + && (lpEvalDesc->which_turn <= 12 + || ( + ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr + && ObjectsOfConcern[ENEMY_WEAPON_INDEX].which_turn <= 6 + ))) + { + StarShipPtr->ship_input_state |= WEAPON; + if (ShipPtr->thrust_wait < WEAPON_WAIT + 1) + ShipPtr->thrust_wait = WEAPON_WAIT + 1; + } + + + if ((StarShipPtr->ship_input_state & WEAPON) + && StarShipPtr->RaceDescPtr->ship_info.energy_level < WEAPON_ENERGY_COST + && ShipPtr->crew_level > 1) + StarShipPtr->ship_input_state |= SPECIAL; + else + StarShipPtr->ship_input_state &= ~SPECIAL; +} + +static void +druuge_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + /* if just fired cannon */ + if ((StarShipPtr->cur_status_flags & WEAPON) + && StarShipPtr->weapon_counter == + StarShipPtr->RaceDescPtr->characteristics.weapon_wait) + { + COUNT angle; + SIZE cur_delta_x, cur_delta_y; + + StarShipPtr->cur_status_flags &= ~SHIP_AT_MAX_SPEED; + + angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing) + HALF_CIRCLE; + DeltaVelocityComponents (&ElementPtr->velocity, + COSINE (angle, RECOIL_VELOCITY), + SINE (angle, RECOIL_VELOCITY)); + GetCurrentVelocityComponents (&ElementPtr->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 (&ElementPtr->velocity, + COSINE (angle, MAX_RECOIL_VELOCITY), + SINE (angle, MAX_RECOIL_VELOCITY)); + } + } +} + +static void +druuge_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (StarShipPtr->cur_status_flags & SPECIAL) + { + if (StarShipPtr->special_counter + || ElementPtr->crew_level == 1 + || StarShipPtr->RaceDescPtr->ship_info.energy_level + == StarShipPtr->RaceDescPtr->ship_info.max_energy) + StarShipPtr->cur_status_flags &= ~SPECIAL; + else + { + ProcessSound (SetAbsSoundIndex ( + /* BURN UP CREW */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + + DeltaCrew (ElementPtr, -1); + DeltaEnergy (ElementPtr, SPECIAL_ENERGY_COST); + + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } + } +} + +RACE_DESC* +init_druuge (void) +{ + RACE_DESC *RaceDescPtr; + + druuge_desc.preprocess_func = druuge_preprocess; + druuge_desc.postprocess_func = druuge_postprocess; + druuge_desc.init_weapon_func = initialize_cannon; + druuge_desc.cyborg_control.intelligence_func = druuge_intelligence; + + RaceDescPtr = &druuge_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/druuge/druuge.h b/src/uqm/ships/druuge/druuge.h new file mode 100644 index 0000000..f332bc3 --- /dev/null +++ b/src/uqm/ships/druuge/druuge.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef DRUUGE_H +#define DRUUGE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_druuge (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* DRUUGE_H */ + diff --git a/src/uqm/ships/druuge/icode.h b/src/uqm/ships/druuge/icode.h new file mode 100644 index 0000000..8599490 --- /dev/null +++ b/src/uqm/ships/druuge/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define DRUUGE_CODE "ship.druuge.code" diff --git a/src/uqm/ships/druuge/resinst.h b/src/uqm/ships/druuge/resinst.h new file mode 100644 index 0000000..2213ad9 --- /dev/null +++ b/src/uqm/ships/druuge/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define DRUUGE_BIG_MASK_PMAP_ANIM "ship.druuge.graphics.mauler.large" +#define DRUUGE_CANNON_BIG_MASK_PMAP_ANIM "ship.druuge.graphics.cannon.large" +#define DRUUGE_CANNON_MED_MASK_PMAP_ANIM "ship.druuge.graphics.cannon.medium" +#define DRUUGE_CANNON_SML_MASK_PMAP_ANIM "ship.druuge.graphics.cannon.small" +#define DRUUGE_CAPT_MASK_PMAP_ANIM "ship.druuge.graphics.captain" +#define DRUUGE_ICON_MASK_PMAP_ANIM "ship.druuge.icons" +#define DRUUGE_MED_MASK_PMAP_ANIM "ship.druuge.graphics.mauler.medium" +#define DRUUGE_MICON_MASK_PMAP_ANIM "ship.druuge.meleeicons" +#define DRUUGE_RACE_STRINGS "ship.druuge.text" +#define DRUUGE_SHIP_SOUNDS "ship.druuge.sounds" +#define DRUUGE_SML_MASK_PMAP_ANIM "ship.druuge.graphics.mauler.small" +#define DRUUGE_VICTORY_SONG "ship.druuge.ditty" diff --git a/src/uqm/ships/human/Makeinfo b/src/uqm/ships/human/Makeinfo new file mode 100644 index 0000000..f80f814 --- /dev/null +++ b/src/uqm/ships/human/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="human.c" +uqm_HFILES="human.h icode.h resinst.h" diff --git a/src/uqm/ships/human/human.c b/src/uqm/ships/human/human.c new file mode 100644 index 0000000..354486d --- /dev/null +++ b/src/uqm/ships/human/human.c @@ -0,0 +1,360 @@ +//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 "human.h" +#include "resinst.h" + +#include "uqm/colors.h" +#include "uqm/globdata.h" + +// Core characteristics +#define MAX_CREW 18 +#define MAX_ENERGY 18 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 8 +#define MAX_THRUST /* DISPLAY_TO_WORLD (6) */ 24 +#define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 3 +#define THRUST_WAIT 4 +#define TURN_WAIT 1 +#define SHIP_MASS 6 + +// Nuke +#define WEAPON_ENERGY_COST 9 +#define WEAPON_WAIT 10 +#define HUMAN_OFFSET 42 +#define NUKE_OFFSET 8 +#define MIN_MISSILE_SPEED DISPLAY_TO_WORLD (10) +#define MAX_MISSILE_SPEED DISPLAY_TO_WORLD (20) +#define MISSILE_SPEED (MAX_THRUST >= MIN_MISSILE_SPEED ? \ + MAX_THRUST : MIN_MISSILE_SPEED) +#define THRUST_SCALE DISPLAY_TO_WORLD (1) +#define MISSILE_LIFE 60 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 4 +#define TRACK_WAIT 3 + +// Point-Defense Laser +#define SPECIAL_ENERGY_COST 4 +#define SPECIAL_WAIT 9 +#define LASER_RANGE (UWORD)100 + +static RACE_DESC human_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | SEEKING_WEAPON | POINT_DEFENSE, + 11, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + HUMAN_RACE_STRINGS, + HUMAN_ICON_MASK_PMAP_ANIM, + HUMAN_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 0, /* Initial sphere of influence radius */ + { /* Known location (center of SoI) */ + 1752, 1450, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + HUMAN_BIG_MASK_PMAP_ANIM, + HUMAN_MED_MASK_PMAP_ANIM, + HUMAN_SML_MASK_PMAP_ANIM, + }, + { + SATURN_BIG_MASK_PMAP_ANIM, + SATURN_MED_MASK_PMAP_ANIM, + SATURN_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + HUMAN_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + HUMAN_VICTORY_SONG, + HUMAN_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + LONG_RANGE_WEAPON, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +nuke_preprocess (ELEMENT *ElementPtr) +{ + COUNT facing; + + facing = GetFrameIndex (ElementPtr->next.image.frame); + if (ElementPtr->turn_wait > 0) + --ElementPtr->turn_wait; + else + { + if (TrackShip (ElementPtr, &facing) > 0) + { + ElementPtr->next.image.frame = + SetAbsFrameIndex (ElementPtr->next.image.frame, + facing); + ElementPtr->state_flags |= CHANGING; + } + + ElementPtr->turn_wait = TRACK_WAIT; + } + + { + SIZE speed; + + if ((speed = MISSILE_SPEED + + ((MISSILE_LIFE - ElementPtr->life_span) * + THRUST_SCALE)) > MAX_MISSILE_SPEED) + speed = MAX_MISSILE_SPEED; + SetVelocityVector (&ElementPtr->velocity, + speed, facing); + } +} + +static void +spawn_point_defense (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (ElementPtr->state_flags & PLAYER_SHIP) + { + HELEMENT hDefense; + + hDefense = AllocElement (); + if (hDefense) + { + ELEMENT *DefensePtr; + + LockElement (hDefense, &DefensePtr); + DefensePtr->playerNr = ElementPtr->playerNr; + DefensePtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE; + DefensePtr->death_func = spawn_point_defense; + + GetElementStarShip (ElementPtr, &StarShipPtr); + SetElementStarShip (DefensePtr, StarShipPtr); + UnlockElement (hDefense); + + PutElement (hDefense); + } + } + else + { + BOOLEAN PaidFor; + HELEMENT hObject, hNextObject; + ELEMENT *ShipPtr; + + PaidFor = FALSE; + + LockElement (StarShipPtr->hShip, &ShipPtr); + for (hObject = GetTailElement (); hObject; hObject = hNextObject) + { + ELEMENT *ObjectPtr; + + LockElement (hObject, &ObjectPtr); + hNextObject = GetPredElement (ObjectPtr); + if (ObjectPtr != ShipPtr && CollidingElement (ObjectPtr) && + !OBJECT_CLOAKED (ObjectPtr)) + { + SIZE delta_x, delta_y; + + delta_x = ObjectPtr->next.location.x - + ShipPtr->next.location.x; + delta_y = ObjectPtr->next.location.y - + ShipPtr->next.location.y; + if (delta_x < 0) + delta_x = -delta_x; + if (delta_y < 0) + delta_y = -delta_y; + delta_x = WORLD_TO_DISPLAY (delta_x); + delta_y = WORLD_TO_DISPLAY (delta_y); + if ((UWORD)delta_x <= LASER_RANGE && + (UWORD)delta_y <= LASER_RANGE && + (UWORD)delta_x * (UWORD)delta_x + + (UWORD)delta_y * (UWORD)delta_y <= + LASER_RANGE * LASER_RANGE) + { + HELEMENT hPointDefense; + LASER_BLOCK LaserBlock; + + if (!PaidFor) + { + if (!DeltaEnergy (ShipPtr, -SPECIAL_ENERGY_COST)) + break; + + ProcessSound (SetAbsSoundIndex ( + /* POINT_DEFENSE_LASER */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + PaidFor = TRUE; + } + + LaserBlock.cx = ShipPtr->next.location.x; + LaserBlock.cy = ShipPtr->next.location.y; + LaserBlock.face = 0; + LaserBlock.ex = ObjectPtr->next.location.x + - ShipPtr->next.location.x; + LaserBlock.ey = ObjectPtr->next.location.y + - ShipPtr->next.location.y; + LaserBlock.sender = ShipPtr->playerNr; + LaserBlock.flags = IGNORE_SIMILAR; + LaserBlock.pixoffs = 0; + LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F); + hPointDefense = initialize_laser (&LaserBlock); + if (hPointDefense) + { + ELEMENT *PDPtr; + + LockElement (hPointDefense, &PDPtr); + SetElementStarShip (PDPtr, StarShipPtr); + PDPtr->hTarget = 0; + UnlockElement (hPointDefense); + + PutElement (hPointDefense); + } + } + } + UnlockElement (hObject); + } + UnlockElement (StarShipPtr->hShip); + } +} + +static COUNT +initialize_nuke (ELEMENT *ShipPtr, HELEMENT NukeArray[]) +{ + 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; + MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = 0; + MissileBlock.pixoffs = HUMAN_OFFSET; + MissileBlock.speed = MISSILE_SPEED; + MissileBlock.hit_points = MISSILE_HITS; + MissileBlock.damage = MISSILE_DAMAGE; + MissileBlock.life = MISSILE_LIFE; + MissileBlock.preprocess_func = nuke_preprocess; + MissileBlock.blast_offs = NUKE_OFFSET; + NukeArray[0] = initialize_missile (&MissileBlock); + + if (NukeArray[0]) + { + ELEMENT *NukePtr; + + LockElement (NukeArray[0], &NukePtr); + NukePtr->turn_wait = TRACK_WAIT; + UnlockElement (NukeArray[0]); + } + + return (1); +} + +static void +human_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + if (StarShipPtr->special_counter == 0 + && ((ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr != NULL + && ObjectsOfConcern[ENEMY_WEAPON_INDEX].which_turn <= 2) + || (ObjectsOfConcern[ENEMY_SHIP_INDEX].ObjectPtr != NULL + && ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn <= 4))) + StarShipPtr->ship_input_state |= SPECIAL; + else + StarShipPtr->ship_input_state &= ~SPECIAL; + ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr = NULL; + + ship_intelligence (ShipPtr, + ObjectsOfConcern, ConcernCounter); + + if (StarShipPtr->weapon_counter == 0) + { + if (ObjectsOfConcern[ENEMY_SHIP_INDEX].ObjectPtr + && (!(StarShipPtr->ship_input_state & (LEFT | RIGHT /* | THRUST */)) + || ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn <= 12)) + StarShipPtr->ship_input_state |= WEAPON; + } +} + +static void +human_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0) + { + spawn_point_defense (ElementPtr); + } +} + +RACE_DESC* +init_human (void) +{ + RACE_DESC *RaceDescPtr; + + human_desc.postprocess_func = human_postprocess; + human_desc.init_weapon_func = initialize_nuke; + human_desc.cyborg_control.intelligence_func = human_intelligence; + + RaceDescPtr = &human_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/human/human.h b/src/uqm/ships/human/human.h new file mode 100644 index 0000000..6f7314d --- /dev/null +++ b/src/uqm/ships/human/human.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef HUMAN_H +#define HUMAN_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_human (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* HUMAN_H */ + diff --git a/src/uqm/ships/human/icode.h b/src/uqm/ships/human/icode.h new file mode 100644 index 0000000..acfd62e --- /dev/null +++ b/src/uqm/ships/human/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define HUMAN_CODE "ship.earthling.code" diff --git a/src/uqm/ships/human/resinst.h b/src/uqm/ships/human/resinst.h new file mode 100644 index 0000000..3d4022e --- /dev/null +++ b/src/uqm/ships/human/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define HUMAN_BIG_MASK_PMAP_ANIM "ship.earthling.graphics.human.large" +#define HUMAN_CAPTAIN_MASK_PMAP_ANIM "ship.earthling.graphics.captain" +#define HUMAN_ICON_MASK_PMAP_ANIM "ship.earthling.icons" +#define HUMAN_MED_MASK_PMAP_ANIM "ship.earthling.graphics.human.medium" +#define HUMAN_MICON_MASK_PMAP_ANIM "ship.earthling.meleeicons" +#define HUMAN_RACE_STRINGS "ship.earthling.text" +#define HUMAN_SHIP_SOUNDS "ship.earthling.sounds" +#define HUMAN_SML_MASK_PMAP_ANIM "ship.earthling.graphics.human.small" +#define HUMAN_VICTORY_SONG "ship.earthling.ditty" +#define SATURN_BIG_MASK_PMAP_ANIM "ship.earthling.graphics.saturn.large" +#define SATURN_MED_MASK_PMAP_ANIM "ship.earthling.graphics.saturn.medium" +#define SATURN_SML_MASK_PMAP_ANIM "ship.earthling.graphics.saturn.small" diff --git a/src/uqm/ships/ilwrath/Makeinfo b/src/uqm/ships/ilwrath/Makeinfo new file mode 100644 index 0000000..cbc8f69 --- /dev/null +++ b/src/uqm/ships/ilwrath/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="ilwrath.c" +uqm_HFILES="icode.h ilwrath.h resinst.h" diff --git a/src/uqm/ships/ilwrath/icode.h b/src/uqm/ships/ilwrath/icode.h new file mode 100644 index 0000000..fa78adc --- /dev/null +++ b/src/uqm/ships/ilwrath/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define ILWRATH_CODE "ship.ilwrath.code" diff --git a/src/uqm/ships/ilwrath/ilwrath.c b/src/uqm/ships/ilwrath/ilwrath.c new file mode 100644 index 0000000..3947081 --- /dev/null +++ b/src/uqm/ships/ilwrath/ilwrath.c @@ -0,0 +1,409 @@ +//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 "ilwrath.h" +#include "resinst.h" + +#include "uqm/colors.h" +#include "uqm/globdata.h" + + +// Core characteristics +#define MAX_CREW 22 +#define MAX_ENERGY 16 +#define ENERGY_REGENERATION 4 +#define ENERGY_WAIT 4 +#define MAX_THRUST 25 +#define THRUST_INCREMENT 5 +#define THRUST_WAIT 0 +#define TURN_WAIT 2 +#define SHIP_MASS 7 +#define LOOK_AHEAD 4 + /* Controls how much the auto-turn will attempt to "lead" + * its target. */ + +// Hellfire Spout +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define MISSILE_LIFE 8 +#define ILWRATH_OFFSET 29 +#define MISSILE_SPEED MAX_THRUST +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define MISSILE_OFFSET 0 + +// Cloaking Device +#define SPECIAL_ENERGY_COST 3 +#define SPECIAL_WAIT 13 + +static RACE_DESC ilwrath_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 10, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + ILWRATH_RACE_STRINGS, + ILWRATH_ICON_MASK_PMAP_ANIM, + ILWRATH_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 1410 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 48, 1700, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + ILWRATH_BIG_MASK_PMAP_ANIM, + ILWRATH_MED_MASK_PMAP_ANIM, + ILWRATH_SML_MASK_PMAP_ANIM, + }, + { + FIRE_BIG_MASK_PMAP_ANIM, + FIRE_MED_MASK_PMAP_ANIM, + FIRE_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + ILWRATH_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + ILWRATH_VICTORY_SONG, + ILWRATH_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + CLOSE_RANGE_WEAPON, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +flame_preprocess (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 +flame_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + ElementPtr0->state_flags &= ~DISAPPEARING; + ElementPtr0->state_flags |= NONSOLID; +} + +static void +ilwrath_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + EVALUATE_DESC *lpEvalDesc; + STARSHIP *StarShipPtr; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + lpEvalDesc->MoveState = PURSUE; + if (lpEvalDesc->ObjectPtr && lpEvalDesc->which_turn <= 10) + /* don't want to dodge when you could be flaming */ + ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr = 0; + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + GetElementStarShip (ShipPtr, &StarShipPtr); + if (lpEvalDesc->ObjectPtr + && (lpEvalDesc->which_turn <= 6 + || (lpEvalDesc->which_turn <= 10 + && ObjectsOfConcern[ENEMY_WEAPON_INDEX].which_turn <= 10))) + { + StarShipPtr->ship_input_state &= ~SPECIAL; + if (OBJECT_CLOAKED (ShipPtr)) + { + StarShipPtr->ship_input_state &= ~LEFT | RIGHT; + StarShipPtr->ship_input_state |= THRUST; + } + StarShipPtr->ship_input_state |= WEAPON; + } + else if (StarShipPtr->special_counter == 0 + && (LOBYTE (GLOBAL (CurrentActivity)) != IN_ENCOUNTER + || !GET_GAME_STATE (PROBE_ILWRATH_ENCOUNTER))) + { + StarShipPtr->ship_input_state &= ~SPECIAL; + if (!OBJECT_CLOAKED (ShipPtr) + && !(StarShipPtr->ship_input_state & WEAPON)) + StarShipPtr->ship_input_state |= SPECIAL; + } +} + +static COUNT +initialize_flame (ELEMENT *ShipPtr, HELEMENT FlameArray[]) +{ + 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; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.index = 0; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = ILWRATH_OFFSET; + MissileBlock.speed = MISSILE_SPEED; + MissileBlock.hit_points = MISSILE_HITS; + MissileBlock.damage = MISSILE_DAMAGE; + MissileBlock.life = MISSILE_LIFE; + MissileBlock.preprocess_func = flame_preprocess; + MissileBlock.blast_offs = MISSILE_OFFSET; + FlameArray[0] = initialize_missile (&MissileBlock); + + if (FlameArray[0]) + { + SIZE dx, dy; + ELEMENT *FlamePtr; + + LockElement (FlameArray[0], &FlamePtr); + GetCurrentVelocityComponents (&ShipPtr->velocity, &dx, &dy); + DeltaVelocityComponents (&FlamePtr->velocity, dx, dy); + FlamePtr->current.location.x -= VELOCITY_TO_WORLD (dx); + FlamePtr->current.location.y -= VELOCITY_TO_WORLD (dy); + + FlamePtr->collision_func = flame_collision; + FlamePtr->turn_wait = 0; + UnlockElement (FlameArray[0]); + } + + return (1); +} + +static void +ilwrath_preprocess (ELEMENT *ElementPtr) +{ + STATUS_FLAGS status_flags; + STARSHIP *StarShipPtr; + PRIMITIVE *lpPrim; + + GetElementStarShip (ElementPtr, &StarShipPtr); + status_flags = StarShipPtr->cur_status_flags; + lpPrim = &(GLOBAL (DisplayArray))[ElementPtr->PrimIndex]; + if (GetPrimType (lpPrim) == STAMPFILL_PRIM) + { + Color color; + BOOLEAN weapon_discharge; + + color = GetPrimColor (lpPrim); + weapon_discharge = ((status_flags & WEAPON) + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= WEAPON_ENERGY_COST); + if (weapon_discharge + || (StarShipPtr->special_counter == 0 + && ((status_flags & SPECIAL) || + !sameColor (color, BLACK_COLOR)))) + { + if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F))) + SetPrimType (lpPrim, STAMP_PRIM); + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x0A, 0x1F, 0x1F), 0x0B))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F)); + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x00, 0x14, 0x14), 0x03))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x0A, 0x1F, 0x1F), 0x0B)); + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x1F), 0x09))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x00, 0x14, 0x14), 0x03)); + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x14), 0x01))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x1F), 0x09)); + else + { + ProcessSound (SetAbsSoundIndex ( + /* CLOAKING_OFF */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), ElementPtr); + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x14), 0x01)); + if (weapon_discharge) + { + COUNT facing; + + facing = StarShipPtr->ShipFacing; + if (TrackShip (ElementPtr, &facing) >= 0) + { + ELEMENT *eptr; + SIZE dx0, dy0, dx1, dy1; + VELOCITY_DESC v; + + LockElement (ElementPtr->hTarget, &eptr); + v = eptr->velocity; + GetNextVelocityComponents (&v, &dx0, &dy0, LOOK_AHEAD); + v = ElementPtr->velocity; + GetNextVelocityComponents (&v, &dx1, &dy1, LOOK_AHEAD); + dx0 = (eptr->current.location.x + dx0) + - (ElementPtr->current.location.x + dx1); + dy0 = (eptr->current.location.y + dy0) + - (ElementPtr->current.location.y + dy1); + UnlockElement (ElementPtr->hTarget); + + StarShipPtr->ShipFacing = + NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (dx0, dy0)) + ); +#ifdef NOTYET + if (ElementPtr->thrust_wait == 0 + && (StarShipPtr->cur_status_flags & THRUST)) + { + COUNT last_facing; + + do + { + VELOCITY_DESC temp_v; + + last_facing = StarShipPtr->ShipFacing; + inertial_thrust (ElementPtr); + temp_v = ElementPtr->velocity; + ElementPtr->velocity = v; + + dx0 += dx1; + dy0 += dy1; + GetNextVelocityComponents (&temp_v, + &dx1, &dy1, LOOK_AHEAD); + dx0 -= dx1; + dy0 -= dy1; + StarShipPtr->ShipFacing = + NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (dx0, dy0)) + ); + } while (StarShipPtr->ShipFacing != last_facing); + } +#endif /* NOTYET */ + if (ElementPtr->turn_wait == 0) + ++ElementPtr->turn_wait; + ElementPtr->next.image.frame = + SetAbsFrameIndex (ElementPtr->next.image.frame, + StarShipPtr->ShipFacing); + } + ElementPtr->hTarget = 0; + } + } + + ElementPtr->state_flags |= CHANGING; + status_flags &= ~SPECIAL; + StarShipPtr->special_counter = 0; + } + else if (!sameColor (color, BLACK_COLOR)) + { + if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x14), 0x01))) + { + SetPrimColor (lpPrim, BLACK_COLOR); + Untarget (ElementPtr); + } + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x1F), 0x09))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x14), 0x01)); + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x00, 0x14, 0x14), 0x03))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x1F), 0x09)); + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x0A, 0x1F, 0x1F), 0x0B))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x00, 0x14, 0x14), 0x03)); + else + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x0A, 0x1F, 0x1F), 0x0B)); + + ElementPtr->state_flags |= CHANGING; + } + } + + if ((status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F)); + SetPrimType (lpPrim, STAMPFILL_PRIM); + + ProcessSound (SetAbsSoundIndex ( + /* CLOAKING_ON */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), + ElementPtr); + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + + ElementPtr->state_flags |= CHANGING; + } +} + +RACE_DESC* +init_ilwrath (void) +{ + RACE_DESC *RaceDescPtr; + + ilwrath_desc.preprocess_func = ilwrath_preprocess; + ilwrath_desc.init_weapon_func = initialize_flame; + ilwrath_desc.cyborg_control.intelligence_func = ilwrath_intelligence; + + RaceDescPtr = &ilwrath_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/ilwrath/ilwrath.h b/src/uqm/ships/ilwrath/ilwrath.h new file mode 100644 index 0000000..a442b9d --- /dev/null +++ b/src/uqm/ships/ilwrath/ilwrath.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef ILWRATH_H +#define ILWRATH_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_ilwrath (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* ILWRATH_H */ + diff --git a/src/uqm/ships/ilwrath/resinst.h b/src/uqm/ships/ilwrath/resinst.h new file mode 100644 index 0000000..46cb53a --- /dev/null +++ b/src/uqm/ships/ilwrath/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define FIRE_BIG_MASK_PMAP_ANIM "ship.ilwrath.graphics.fire.large" +#define FIRE_MED_MASK_PMAP_ANIM "ship.ilwrath.graphics.fire.medium" +#define FIRE_SML_MASK_PMAP_ANIM "ship.ilwrath.graphics.fire.small" +#define ILWRATH_BIG_MASK_PMAP_ANIM "ship.ilwrath.graphics.avenger.large" +#define ILWRATH_CAPTAIN_MASK_PMAP_ANIM "ship.ilwrath.graphics.captain" +#define ILWRATH_ICON_MASK_PMAP_ANIM "ship.ilwrath.icons" +#define ILWRATH_MED_MASK_PMAP_ANIM "ship.ilwrath.graphics.avenger.medium" +#define ILWRATH_MICON_MASK_PMAP_ANIM "ship.ilwrath.meleeicons" +#define ILWRATH_RACE_STRINGS "ship.ilwrath.text" +#define ILWRATH_SHIP_SOUNDS "ship.ilwrath.sounds" +#define ILWRATH_SML_MASK_PMAP_ANIM "ship.ilwrath.graphics.avenger.small" +#define ILWRATH_VICTORY_SONG "ship.ilwrath.ditty" diff --git a/src/uqm/ships/lastbat/Makeinfo b/src/uqm/ships/lastbat/Makeinfo new file mode 100644 index 0000000..589d8d0 --- /dev/null +++ b/src/uqm/ships/lastbat/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="lastbat.c" +uqm_HFILES="icode.h lastbat.h resinst.h" diff --git a/src/uqm/ships/lastbat/icode.h b/src/uqm/ships/lastbat/icode.h new file mode 100644 index 0000000..087c891 --- /dev/null +++ b/src/uqm/ships/lastbat/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SAMATRA_CODE "ship.samatra.code" 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); +} + diff --git a/src/uqm/ships/lastbat/lastbat.h b/src/uqm/ships/lastbat/lastbat.h new file mode 100644 index 0000000..ccda7f1 --- /dev/null +++ b/src/uqm/ships/lastbat/lastbat.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef LASTBAT_H +#define LASTBAT_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_samatra (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* LASTBAT_H */ + diff --git a/src/uqm/ships/lastbat/resinst.h b/src/uqm/ships/lastbat/resinst.h new file mode 100644 index 0000000..779c00a --- /dev/null +++ b/src/uqm/ships/lastbat/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define GENERATOR_BIG_MASK_ANIM "ship.samatra.graphics.generator.large" +#define GENERATOR_MED_MASK_PMAP_ANIM "ship.samatra.graphics.generator.medium" +#define GENERATOR_SML_MASK_PMAP_ANIM "ship.samatra.graphics.generator.small" +#define SAMATRA_BIG_MASK_ANIM "ship.samatra.graphics.samatra.large" +#define SAMATRA_CAPTAIN_MASK_PMAP_ANIM "ship.samatra.graphics.captain" +#define SAMATRA_MED_MASK_PMAP_ANIM "ship.samatra.graphics.samatra.medium" +#define SAMATRA_SHIP_SOUNDS "ship.samatra.sounds" +#define SAMATRA_SML_MASK_PMAP_ANIM "ship.samatra.graphics.samatra.small" +#define SAMATRA_VICTORY_SONG "ship.samatra.ditty" +#define SENTINEL_BIG_MASK_ANIM "ship.samatra.graphics.sentinel.large" +#define SENTINEL_MED_MASK_PMAP_ANIM "ship.samatra.graphics.sentinel.medium" +#define SENTINEL_SML_MASK_PMAP_ANIM "ship.samatra.graphics.sentinel.small" diff --git a/src/uqm/ships/melnorme/Makeinfo b/src/uqm/ships/melnorme/Makeinfo new file mode 100644 index 0000000..f5bb991 --- /dev/null +++ b/src/uqm/ships/melnorme/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="melnorme.c" +uqm_HFILES="icode.h melnorme.h resinst.h" diff --git a/src/uqm/ships/melnorme/icode.h b/src/uqm/ships/melnorme/icode.h new file mode 100644 index 0000000..d9dd355 --- /dev/null +++ b/src/uqm/ships/melnorme/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define MELNORME_CODE "ship.melnorme.code" diff --git a/src/uqm/ships/melnorme/melnorme.c b/src/uqm/ships/melnorme/melnorme.c new file mode 100644 index 0000000..8e5ab2b --- /dev/null +++ b/src/uqm/ships/melnorme/melnorme.c @@ -0,0 +1,658 @@ +//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 "melnorme.h" +#include "resinst.h" + +#include "uqm/globdata.h" +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 20 +#define MAX_ENERGY MAX_ENERGY_SIZE +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 4 +#define MAX_THRUST 36 +#define THRUST_INCREMENT 6 +#define THRUST_WAIT 4 +#define TURN_WAIT 4 +#define SHIP_MASS 7 + +// Blaster Pulse +#define WEAPON_ENERGY_COST 5 +#define WEAPON_WAIT 1 +#define MELNORME_OFFSET 24 +#define LEVEL_COUNTER 72 +#define MAX_PUMP 4 +#define PUMPUP_SPEED DISPLAY_TO_WORLD (45) +#define PUMPUP_LIFE 10 +#define PUMPUP_DAMAGE 2 +#define MIN_PUMPITUDE_ANIMS 3 +#define NUM_PUMP_ANIMS 5 +#define REVERSE_DIR (BYTE)(1 << 7) + +// Confusion Pulse +#define SPECIAL_ENERGY_COST 20 +#define SPECIAL_WAIT 20 +#define CMISSILE_SPEED DISPLAY_TO_WORLD (30) +#define CMISSILE_LIFE 20 +#define CMISSILE_HITS 200 +#define CMISSILE_DAMAGE 0 +#define CMISSILE_OFFSET 4 + +static RACE_DESC melnorme_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 18, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + MELNORME_RACE_STRINGS, + MELNORME_ICON_MASK_PMAP_ANIM, + MELNORME_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + INFINITE_RADIUS, /* Initial sphere of influence radius */ + { /* Known location (center of SoI) */ + MAX_X_UNIVERSE >> 1, MAX_Y_UNIVERSE >> 1, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + MELNORME_BIG_MASK_PMAP_ANIM, + MELNORME_MED_MASK_PMAP_ANIM, + MELNORME_SML_MASK_PMAP_ANIM, + }, + { + PUMPUP_BIG_MASK_PMAP_ANIM, + PUMPUP_MED_MASK_PMAP_ANIM, + PUMPUP_SML_MASK_PMAP_ANIM, + }, + { + CONFUSE_BIG_MASK_PMAP_ANIM, + CONFUSE_MED_MASK_PMAP_ANIM, + CONFUSE_SML_MASK_PMAP_ANIM, + }, + { + MELNORME_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + MELNORME_VICTORY_SONG, + MELNORME_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + PUMPUP_SPEED * PUMPUP_LIFE, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +pump_up_preprocess (ELEMENT *ElementPtr) +{ + if (--ElementPtr->thrust_wait & 1) + { + COUNT frame_index; + + frame_index = GetFrameIndex (ElementPtr->current.image.frame); + if (((ElementPtr->turn_wait & REVERSE_DIR) + && (frame_index % NUM_PUMP_ANIMS) != 0) + || (!(ElementPtr->turn_wait & REVERSE_DIR) + && ((frame_index + 1) % NUM_PUMP_ANIMS) == 0)) + { + --frame_index; + ElementPtr->turn_wait |= REVERSE_DIR; + } + else + { + ++frame_index; + ElementPtr->turn_wait &= ~REVERSE_DIR; + } + + ElementPtr->next.image.frame = SetAbsFrameIndex ( + ElementPtr->current.image.frame, frame_index); + + ElementPtr->state_flags |= CHANGING; + } +} + +static COUNT initialize_pump_up (ELEMENT *ShipPtr, HELEMENT PumpUpArray[]); + +static void +pump_up_postprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->state_flags & APPEARING) + { + ZeroVelocityComponents (&ElementPtr->velocity); + } + else + { + HELEMENT hPumpUp; + ELEMENT *EPtr; + ELEMENT *ShipPtr; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + LockElement (StarShipPtr->hShip, &ShipPtr); + initialize_pump_up (ShipPtr, &hPumpUp); + DeltaEnergy (ShipPtr, 0); + UnlockElement (StarShipPtr->hShip); + + LockElement (hPumpUp, &EPtr); + + EPtr->current.image.frame = ElementPtr->current.image.frame; + EPtr->turn_wait = ElementPtr->turn_wait; + EPtr->thrust_wait = ElementPtr->thrust_wait; + if (--EPtr->thrust_wait == 0) + { + if ((EPtr->turn_wait & ~REVERSE_DIR) < MAX_PUMP - 1) + { + ++EPtr->turn_wait; + EPtr->current.image.frame = SetRelFrameIndex ( + EPtr->current.image.frame, NUM_PUMP_ANIMS); + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), + EPtr); + } + EPtr->thrust_wait = LEVEL_COUNTER; + } + + EPtr->mass_points = EPtr->hit_points = + (PUMPUP_DAMAGE << (ElementPtr->turn_wait & ~REVERSE_DIR)); + SetElementStarShip (EPtr, StarShipPtr); + + if (EPtr->thrust_wait & 1) + { + COUNT frame_index; + + frame_index = GetFrameIndex (EPtr->current.image.frame); + if (((EPtr->turn_wait & REVERSE_DIR) + && (frame_index % NUM_PUMP_ANIMS) != 0) + || (!(EPtr->turn_wait & REVERSE_DIR) + && ((frame_index + 1) % NUM_PUMP_ANIMS) == 0)) + { + --frame_index; + EPtr->turn_wait |= REVERSE_DIR; + } + else + { + ++frame_index; + EPtr->turn_wait &= ~REVERSE_DIR; + } + + EPtr->current.image.frame = SetAbsFrameIndex ( + EPtr->current.image.frame, frame_index); + } + + if (StarShipPtr->cur_status_flags & StarShipPtr->old_status_flags + & WEAPON) + { + StarShipPtr->weapon_counter = WEAPON_WAIT; + } + else + { + COUNT angle; + + EPtr->life_span = PUMPUP_LIFE; + EPtr->preprocess_func = pump_up_preprocess; + EPtr->postprocess_func = 0; + + angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); + SetVelocityComponents (&EPtr->velocity, + COSINE (angle, WORLD_TO_VELOCITY (PUMPUP_SPEED)), + SINE (angle, WORLD_TO_VELOCITY (PUMPUP_SPEED))); + + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 3), EPtr); + } + + UnlockElement (hPumpUp); + PutElement (hPumpUp); + + SetPrimType (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], + NO_PRIM); + ElementPtr->state_flags |= NONSOLID; + } +} + +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 +pump_up_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + RECT r; + BYTE old_thrust_wait; + HELEMENT hBlastElement; + + GetFrameRect (ElementPtr0->next.image.frame, &r); + + old_thrust_wait = ElementPtr0->thrust_wait; + ElementPtr0->blast_offset = r.extent.width >> 1; + hBlastElement = weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + ElementPtr0->thrust_wait = old_thrust_wait; + + if (hBlastElement) + { + ELEMENT *BlastElementPtr; + + LockElement (hBlastElement, &BlastElementPtr); + + BlastElementPtr->life_span = + MIN_PUMPITUDE_ANIMS + + (ElementPtr0->turn_wait & ~REVERSE_DIR); + BlastElementPtr->turn_wait = BlastElementPtr->next_turn = 0; + { + BlastElementPtr->preprocess_func = animate; + } + + BlastElementPtr->current.image.farray = ElementPtr0->next.image.farray; + BlastElementPtr->current.image.frame = + SetAbsFrameIndex (BlastElementPtr->current.image.farray[0], + MAX_PUMP * NUM_PUMP_ANIMS); + + UnlockElement (hBlastElement); + } +} + +static COUNT +initialize_pump_up (ELEMENT *ShipPtr, HELEMENT PumpUpArray[]) +{ + 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; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.index = 0; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = MELNORME_OFFSET; + MissileBlock.speed = DISPLAY_TO_WORLD (MELNORME_OFFSET); + MissileBlock.hit_points = PUMPUP_DAMAGE; + MissileBlock.damage = PUMPUP_DAMAGE; + MissileBlock.life = 2; + MissileBlock.preprocess_func = 0; + MissileBlock.blast_offs = 0; + PumpUpArray[0] = initialize_missile (&MissileBlock); + + if (PumpUpArray[0]) + { + ELEMENT *PumpUpPtr; + + LockElement (PumpUpArray[0], &PumpUpPtr); + PumpUpPtr->postprocess_func = pump_up_postprocess; + PumpUpPtr->collision_func = pump_up_collision; + PumpUpPtr->thrust_wait = LEVEL_COUNTER; + UnlockElement (PumpUpArray[0]); + } + + return (1); +} + +static void +confuse_preprocess (ELEMENT *ElementPtr) +{ + if (!(ElementPtr->state_flags & NONSOLID)) + { + ElementPtr->next.image.frame = SetAbsFrameIndex ( + ElementPtr->current.image.frame, + (GetFrameIndex (ElementPtr->current.image.frame) + 1) & 7); + ElementPtr->state_flags |= CHANGING; + } + else if (ElementPtr->hTarget == 0) + { + ElementPtr->life_span = 0; + ElementPtr->state_flags |= DISAPPEARING; + } + else + { + ELEMENT *eptr; + + LockElement (ElementPtr->hTarget, &eptr); + + ElementPtr->next.location = eptr->next.location; + + if (ElementPtr->turn_wait) + { + HELEMENT hEffect; + STARSHIP *StarShipPtr; + + if (GetFrameIndex (ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->current.image.frame)) == 0) + ElementPtr->next.image.frame = + SetRelFrameIndex (ElementPtr->next.image.frame, -8); + + GetElementStarShip (eptr, &StarShipPtr); + StarShipPtr->ship_input_state = + (StarShipPtr->ship_input_state + & ~(LEFT | RIGHT | SPECIAL)) + | ElementPtr->turn_wait; + + hEffect = AllocElement (); + if (hEffect) + { + LockElement (hEffect, &eptr); + eptr->playerNr = ElementPtr->playerNr; + eptr->state_flags = FINITE_LIFE | NONSOLID | CHANGING; + eptr->life_span = 1; + eptr->current = eptr->next = ElementPtr->next; + eptr->preprocess_func = confuse_preprocess; + SetPrimType (&(GLOBAL (DisplayArray))[eptr->PrimIndex], + STAMP_PRIM); + + GetElementStarShip (ElementPtr, &StarShipPtr); + SetElementStarShip (eptr, StarShipPtr); + eptr->hTarget = ElementPtr->hTarget; + + UnlockElement (hEffect); + PutElement (hEffect); + } + } + + UnlockElement (ElementPtr->hTarget); + } +} + +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 COUNT +initialize_confusion (ELEMENT *ShipPtr, HELEMENT ConfusionArray[]) +{ + STARSHIP *StarShipPtr; + MISSILE_BLOCK ConfusionBlock; + + GetElementStarShip (ShipPtr, &StarShipPtr); + ConfusionBlock.cx = ShipPtr->next.location.x; + ConfusionBlock.cy = ShipPtr->next.location.y; + ConfusionBlock.farray = StarShipPtr->RaceDescPtr->ship_data.special; + ConfusionBlock.index = 0; + ConfusionBlock.face = StarShipPtr->ShipFacing; + ConfusionBlock.sender = ShipPtr->playerNr; + ConfusionBlock.flags = IGNORE_SIMILAR; + ConfusionBlock.pixoffs = MELNORME_OFFSET; + ConfusionBlock.speed = CMISSILE_SPEED; + ConfusionBlock.hit_points = CMISSILE_HITS; + ConfusionBlock.damage = CMISSILE_DAMAGE; + ConfusionBlock.life = CMISSILE_LIFE; + ConfusionBlock.preprocess_func = confuse_preprocess; + ConfusionBlock.blast_offs = CMISSILE_OFFSET; + ConfusionArray[0] = initialize_missile (&ConfusionBlock); + + if (ConfusionArray[0]) + { + ELEMENT *CMissilePtr; + + LockElement (ConfusionArray[0], &CMissilePtr); + CMissilePtr->collision_func = confusion_collision; + SetElementStarShip (CMissilePtr, StarShipPtr); + UnlockElement (ConfusionArray[0]); + } + return (1); +} + +static COUNT +initialize_test_pump_up (ELEMENT *ShipPtr, HELEMENT PumpUpArray[]) +{ + STARSHIP *StarShipPtr; + MISSILE_BLOCK MissileBlock; + //ELEMENT *PumpUpPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + MissileBlock.cx = ShipPtr->next.location.x; + MissileBlock.cy = ShipPtr->next.location.y; + MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.index = 0; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = MELNORME_OFFSET; + MissileBlock.speed = PUMPUP_SPEED; + MissileBlock.hit_points = PUMPUP_DAMAGE; + MissileBlock.damage = PUMPUP_DAMAGE; + MissileBlock.life = PUMPUP_LIFE; + MissileBlock.preprocess_func = 0; + MissileBlock.blast_offs = 0; + PumpUpArray[0] = initialize_missile (&MissileBlock); + + return (1); +} + +static void +melnorme_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + BYTE old_count; + STARSHIP *StarShipPtr; + EVALUATE_DESC *lpEvalDesc; + + GetElementStarShip (ShipPtr, &StarShipPtr); + + StarShipPtr->RaceDescPtr->init_weapon_func = initialize_test_pump_up; + old_count = StarShipPtr->weapon_counter; + + if (StarShipPtr->weapon_counter == WEAPON_WAIT) + StarShipPtr->weapon_counter = 0; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (lpEvalDesc->ObjectPtr) + { + if (StarShipPtr->RaceDescPtr->ship_info.energy_level < SPECIAL_ENERGY_COST + + WEAPON_ENERGY_COST + && !(StarShipPtr->old_status_flags & WEAPON)) + lpEvalDesc->MoveState = ENTICE; + else + { + STARSHIP *EnemyStarShipPtr; + + GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); + if (!(EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags + & IMMEDIATE_WEAPON)) + lpEvalDesc->MoveState = PURSUE; + } + } + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + if (StarShipPtr->weapon_counter == 0 + && (old_count != 0 + || ((StarShipPtr->special_counter + || StarShipPtr->RaceDescPtr->ship_info.energy_level >= SPECIAL_ENERGY_COST + + WEAPON_ENERGY_COST) + && !(StarShipPtr->ship_input_state & WEAPON)))) + StarShipPtr->ship_input_state ^= WEAPON; + + StarShipPtr->ship_input_state &= ~SPECIAL; + if (StarShipPtr->special_counter == 0 + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= SPECIAL_ENERGY_COST) + { + BYTE old_input_state; + + old_input_state = StarShipPtr->ship_input_state; + + StarShipPtr->RaceDescPtr->init_weapon_func = initialize_confusion; + + ++ShipPtr->turn_wait; + ++ShipPtr->thrust_wait; + ship_intelligence (ShipPtr, ObjectsOfConcern, ENEMY_SHIP_INDEX + 1); + --ShipPtr->thrust_wait; + --ShipPtr->turn_wait; + + if (StarShipPtr->ship_input_state & WEAPON) + { + StarShipPtr->ship_input_state &= ~WEAPON; + StarShipPtr->ship_input_state |= SPECIAL; + } + + StarShipPtr->ship_input_state = (unsigned char)(old_input_state + | (StarShipPtr->ship_input_state & SPECIAL)); + } + + StarShipPtr->weapon_counter = old_count; + + StarShipPtr->RaceDescPtr->init_weapon_func = initialize_pump_up; +} + +static void +melnorme_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + HELEMENT Confusion; + + initialize_confusion (ElementPtr, &Confusion); + if (Confusion) + { + ELEMENT *CMissilePtr; + LockElement (Confusion, &CMissilePtr); + + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), CMissilePtr); + + UnlockElement (Confusion); + PutElement (Confusion); + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } + } +} + +RACE_DESC* +init_melnorme (void) +{ + RACE_DESC *RaceDescPtr; + + melnorme_desc.postprocess_func = melnorme_postprocess; + melnorme_desc.init_weapon_func = initialize_pump_up; + melnorme_desc.cyborg_control.intelligence_func = melnorme_intelligence; + + RaceDescPtr = &melnorme_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/melnorme/melnorme.h b/src/uqm/ships/melnorme/melnorme.h new file mode 100644 index 0000000..287ec76 --- /dev/null +++ b/src/uqm/ships/melnorme/melnorme.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef MELNORME_H +#define MELNORME_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_melnorme (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* MELNORME_H */ + diff --git a/src/uqm/ships/melnorme/resinst.h b/src/uqm/ships/melnorme/resinst.h new file mode 100644 index 0000000..01b93df --- /dev/null +++ b/src/uqm/ships/melnorme/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define CONFUSE_BIG_MASK_PMAP_ANIM "ship.melnorme.graphics.confuse.large" +#define CONFUSE_MED_MASK_PMAP_ANIM "ship.melnorme.graphics.confuse.medium" +#define CONFUSE_SML_MASK_PMAP_ANIM "ship.melnorme.graphics.confuse.small" +#define MELNORME_BIG_MASK_PMAP_ANIM "ship.melnorme.graphics.trader.large" +#define MELNORME_CAPTAIN_MASK_PMAP_ANIM "ship.melnorme.graphics.captain" +#define MELNORME_ICON_MASK_PMAP_ANIM "ship.melnorme.icons" +#define MELNORME_MED_MASK_PMAP_ANIM "ship.melnorme.graphics.trader.medium" +#define MELNORME_MICON_MASK_PMAP_ANIM "ship.melnorme.meleeicons" +#define MELNORME_RACE_STRINGS "ship.melnorme.text" +#define MELNORME_SHIP_SOUNDS "ship.melnorme.sounds" +#define MELNORME_SML_MASK_PMAP_ANIM "ship.melnorme.graphics.trader.small" +#define MELNORME_VICTORY_SONG "ship.melnorme.ditty" +#define PUMPUP_BIG_MASK_PMAP_ANIM "ship.melnorme.graphics.pumpup.large" +#define PUMPUP_MED_MASK_PMAP_ANIM "ship.melnorme.graphics.pumpup.medium" +#define PUMPUP_SML_MASK_PMAP_ANIM "ship.melnorme.graphics.pumpup.small" diff --git a/src/uqm/ships/mmrnmhrm/Makeinfo b/src/uqm/ships/mmrnmhrm/Makeinfo new file mode 100644 index 0000000..0c86637 --- /dev/null +++ b/src/uqm/ships/mmrnmhrm/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="mmrnmhrm.c" +uqm_HFILES="icode.h mmrnmhrm.h resinst.h" diff --git a/src/uqm/ships/mmrnmhrm/icode.h b/src/uqm/ships/mmrnmhrm/icode.h new file mode 100644 index 0000000..ba3f593 --- /dev/null +++ b/src/uqm/ships/mmrnmhrm/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define MMRNMHRM_CODE "ship.mmrnmhrm.code" diff --git a/src/uqm/ships/mmrnmhrm/mmrnmhrm.c b/src/uqm/ships/mmrnmhrm/mmrnmhrm.c new file mode 100644 index 0000000..e8f8348 --- /dev/null +++ b/src/uqm/ships/mmrnmhrm/mmrnmhrm.c @@ -0,0 +1,527 @@ +//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 "mmrnmhrm.h" +#include "resinst.h" + +// Core characteristics +#define MAX_CREW 20 +#define MAX_ENERGY 10 +#define SHIP_MASS 3 + +// X-Wing characteristics +#define ENERGY_REGENERATION 2 +#define ENERGY_WAIT 6 +#define MAX_THRUST 20 +#define THRUST_INCREMENT 5 +#define THRUST_WAIT 1 +#define TURN_WAIT 2 + +// Y-Wing characteristics +#define YWING_ENERGY_REGENERATION 1 +#define YWING_SPECIAL_ENERGY_COST MAX_ENERGY +#define YWING_ENERGY_WAIT 6 +#define YWING_MAX_THRUST 50 +#define YWING_THRUST_INCREMENT 10 +#define YWING_THRUST_WAIT 0 +#define YWING_TURN_WAIT 14 + +// X-Wing Lasers +#define MMRNMHRM_OFFSET 16 +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define CENTER_OFFS DISPLAY_TO_WORLD (4) +#define WING_OFFS DISPLAY_TO_WORLD (10) +#define LASER_RANGE DISPLAY_TO_WORLD (125 + MMRNMHRM_OFFSET) + +// Y-Wing Missiles +#define YWING_WEAPON_ENERGY_COST 1 +#define YWING_WEAPON_WAIT 20 +#define LAUNCH_OFFS DISPLAY_TO_WORLD (4) +#define MISSILE_OFFSET 0 +#define MISSILE_SPEED DISPLAY_TO_WORLD (20) +#define MISSILE_LIFE 40 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define TRACK_WAIT 5 + +// Transform +#define SPECIAL_ENERGY_COST MAX_ENERGY +#define SPECIAL_WAIT 0 +#define YWING_SPECIAL_WAIT 0 + +static RACE_DESC mmrnmhrm_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | IMMEDIATE_WEAPON, + 19, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + MMRNMHRM_RACE_STRINGS, + MMRNMHRM_ICON_MASK_PMAP_ANIM, + MMRNMHRM_MICON_MASK_PMAP_ANIM, + 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, + }, + { + { + MMRNMHRM_BIG_MASK_PMAP_ANIM, + MMRNMHRM_MED_MASK_PMAP_ANIM, + MMRNMHRM_SML_MASK_PMAP_ANIM, + }, + { + TORP_BIG_MASK_PMAP_ANIM, + TORP_MED_MASK_PMAP_ANIM, + TORP_SML_MASK_PMAP_ANIM, + }, + { + YWING_BIG_MASK_PMAP_ANIM, + YWING_MED_MASK_PMAP_ANIM, + YWING_SML_MASK_PMAP_ANIM, + }, + { + MMRNMHRM_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + MMRNMHRM_VICTORY_SONG, + MMRNMHRM_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + CLOSE_RANGE_WEAPON, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +// Private per-instance ship data +typedef CHARACTERISTIC_STUFF MMRNMHRM_DATA; + +// Local typedef +typedef MMRNMHRM_DATA CustomShipData_t; + +// Retrieve race-specific ship data from a race desc +static CustomShipData_t * +GetCustomShipData (RACE_DESC *pRaceDesc) +{ + return pRaceDesc->data; +} + +// Set the race-specific data in a race desc +// (Re)Allocates its own storage for the data. +static void +SetCustomShipData (RACE_DESC *pRaceDesc, const CustomShipData_t *data) +{ + if (pRaceDesc->data == data) + return; // no-op + + if (pRaceDesc->data) // Out with the old + { + HFree (pRaceDesc->data); + pRaceDesc->data = NULL; + } + + if (data) // In with the new + { + CustomShipData_t* newData = HMalloc (sizeof (*data)); + *newData = *data; + pRaceDesc->data = newData; + } +} + +static void +missile_preprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->turn_wait > 0) + --ElementPtr->turn_wait; + else + { + COUNT facing; + + facing = GetFrameIndex (ElementPtr->next.image.frame); + if (TrackShip (ElementPtr, &facing) > 0) + { + ElementPtr->next.image.frame = + SetAbsFrameIndex (ElementPtr->next.image.frame, + facing); + ElementPtr->state_flags |= CHANGING; + + SetVelocityVector (&ElementPtr->velocity, + MISSILE_SPEED, facing); + } + + ElementPtr->turn_wait = TRACK_WAIT; + } +} + +static void +mmrnmhrm_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + BOOLEAN CanTransform; + EVALUATE_DESC *lpEvalDesc; + STARSHIP *StarShipPtr; + STARSHIP *EnemyStarShipPtr = NULL; + + GetElementStarShip (ShipPtr, &StarShipPtr); + CanTransform = (BOOLEAN)(StarShipPtr->special_counter == 0 + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= + StarShipPtr->RaceDescPtr->characteristics.special_energy_cost); + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (lpEvalDesc->ObjectPtr) + { + GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); + } + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + StarShipPtr->ship_input_state &= ~SPECIAL; + if (CanTransform + && lpEvalDesc->ObjectPtr + && !(StarShipPtr->ship_input_state & WEAPON)) + { + SIZE delta_x, delta_y; + COUNT travel_angle, direction_angle; + + GetCurrentVelocityComponents (&lpEvalDesc->ObjectPtr->velocity, + &delta_x, &delta_y); + if (delta_x == 0 && delta_y == 0) + direction_angle = travel_angle = 0; + else + { + delta_x = lpEvalDesc->ObjectPtr->current.location.x + - ShipPtr->current.location.x; + delta_y = lpEvalDesc->ObjectPtr->current.location.y + - ShipPtr->current.location.y; + direction_angle = ARCTAN (-delta_x, -delta_y); + travel_angle = GetVelocityTravelAngle ( + &lpEvalDesc->ObjectPtr->velocity + ); + } + + if (ShipPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.ship) + { + if (lpEvalDesc->which_turn > 8) + { + if (MANEUVERABILITY (&EnemyStarShipPtr->RaceDescPtr->cyborg_control) <= SLOW_SHIP + || NORMALIZE_ANGLE ( + direction_angle - travel_angle + QUADRANT + ) > HALF_CIRCLE) + StarShipPtr->ship_input_state |= SPECIAL; + } + } + else + { + SIZE ship_delta_x, ship_delta_y; + + GetCurrentVelocityComponents (&ShipPtr->velocity, + &ship_delta_x, &ship_delta_y); + delta_x -= ship_delta_x; + delta_y -= ship_delta_y; + travel_angle = ARCTAN (delta_x, delta_y); + if (lpEvalDesc->which_turn < 16) + { + if (lpEvalDesc->which_turn <= 8 + || NORMALIZE_ANGLE ( + direction_angle - travel_angle + OCTANT + ) <= QUADRANT) + StarShipPtr->ship_input_state |= SPECIAL; + } + else if (lpEvalDesc->which_turn > 32 + && NORMALIZE_ANGLE ( + direction_angle - travel_angle + QUADRANT + ) > HALF_CIRCLE) + StarShipPtr->ship_input_state |= SPECIAL; + } + } + + if (ShipPtr->current.image.farray == StarShipPtr->RaceDescPtr->ship_data.special) + { + if (!(StarShipPtr->ship_input_state & SPECIAL) + && lpEvalDesc->ObjectPtr) + StarShipPtr->ship_input_state |= WEAPON; + else + StarShipPtr->ship_input_state &= ~WEAPON; + } +} + +static void +twin_laser_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + if (!(ElementPtr1->state_flags & PLAYER_SHIP) + || !elementsOfSamePlayer (ElementPtr0, ElementPtr1)) + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); +} + +static COUNT +initialize_dual_weapons (ELEMENT *ShipPtr, HELEMENT WeaponArray[]) +{ + COORD cx, cy; + COUNT facing, angle; + SIZE offs_x, offs_y; + STARSHIP *StarShipPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + facing = StarShipPtr->ShipFacing; + angle = FACING_TO_ANGLE (facing); + cx = ShipPtr->next.location.x + COSINE (angle, CENTER_OFFS); + cy = ShipPtr->next.location.y + SINE (angle, CENTER_OFFS); + + if (ShipPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.ship) + { + COORD ex, ey; + LASER_BLOCK LaserBlock; + ELEMENT *LaserPtr; + + LaserBlock.sender = ShipPtr->playerNr; + LaserBlock.flags = 0; + LaserBlock.pixoffs = 0; + LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x0A, 0x0A), 0x0C); + LaserBlock.face = facing; + + ex = cx + COSINE (angle, LASER_RANGE); + ey = cy + SINE (angle, LASER_RANGE); + offs_x = -SINE (angle, WING_OFFS); + offs_y = COSINE (angle, WING_OFFS); + + LaserBlock.cx = cx + offs_x; + LaserBlock.cy = cy + offs_y; + LaserBlock.ex = ex - LaserBlock.cx; + LaserBlock.ey = ey - LaserBlock.cy; + if ((WeaponArray[0] = initialize_laser (&LaserBlock))) + { + LockElement (WeaponArray[0], &LaserPtr); + LaserPtr->collision_func = twin_laser_collision; + UnlockElement (WeaponArray[0]); + } + + LaserBlock.cx = cx - offs_x; + LaserBlock.cy = cy - offs_y; + LaserBlock.ex = ex - LaserBlock.cx; + LaserBlock.ey = ey - LaserBlock.cy; + if ((WeaponArray[1] = initialize_laser (&LaserBlock))) + { + LockElement (WeaponArray[1], &LaserPtr); + LaserPtr->collision_func = twin_laser_collision; + UnlockElement (WeaponArray[1]); + } + } + else + { + MISSILE_BLOCK TorpBlock; + ELEMENT *TorpPtr; + + TorpBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; + TorpBlock.sender = ShipPtr->playerNr; + TorpBlock.flags = IGNORE_SIMILAR; + TorpBlock.pixoffs = 0; + TorpBlock.speed = MISSILE_SPEED; + TorpBlock.hit_points = MISSILE_HITS; + TorpBlock.damage = MISSILE_DAMAGE; + TorpBlock.life = MISSILE_LIFE; + TorpBlock.preprocess_func = missile_preprocess; + TorpBlock.blast_offs = MISSILE_OFFSET; + + TorpBlock.face = TorpBlock.index = NORMALIZE_FACING (facing - 1); + offs_x = -SINE (FACING_TO_ANGLE (TorpBlock.face), LAUNCH_OFFS); + offs_y = COSINE (FACING_TO_ANGLE (TorpBlock.face), LAUNCH_OFFS); + + TorpBlock.cx = cx + offs_x; + TorpBlock.cy = cy + offs_y; + if ((WeaponArray[0] = initialize_missile (&TorpBlock))) + { + LockElement (WeaponArray[0], &TorpPtr); + TorpPtr->turn_wait = TRACK_WAIT; + UnlockElement (WeaponArray[0]); + } + + TorpBlock.face = TorpBlock.index = NORMALIZE_FACING (facing + 1); + + TorpBlock.cx = cx - offs_x; + TorpBlock.cy = cy - offs_y; + if ((WeaponArray[1] = initialize_missile (&TorpBlock))) + { + LockElement (WeaponArray[1], &TorpPtr); + TorpPtr->turn_wait = TRACK_WAIT; + UnlockElement (WeaponArray[1]); + } + } + + return (2); +} + +static void +mmrnmhrm_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + /* take care of transform effect */ + if (ElementPtr->next.image.farray != ElementPtr->current.image.farray) + { + MMRNMHRM_DATA tempShipData; + MMRNMHRM_DATA *otherwing_desc; + + ProcessSound (SetAbsSoundIndex ( + /* TRANSFORM */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + + StarShipPtr->weapon_counter = 0; + + /* Swap characteristics descriptors around */ + otherwing_desc = GetCustomShipData (StarShipPtr->RaceDescPtr); + if (!otherwing_desc) + return; // No ship data (?!) + + tempShipData = *otherwing_desc; + SetCustomShipData (StarShipPtr->RaceDescPtr, &StarShipPtr->RaceDescPtr->characteristics); + StarShipPtr->RaceDescPtr->characteristics = tempShipData; + StarShipPtr->RaceDescPtr->cyborg_control.ManeuverabilityIndex = 0; + + if (ElementPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.special) + { + StarShipPtr->RaceDescPtr->cyborg_control.WeaponRange = LONG_RANGE_WEAPON - 1; + StarShipPtr->RaceDescPtr->ship_info.ship_flags &= ~IMMEDIATE_WEAPON; + StarShipPtr->RaceDescPtr->ship_info.ship_flags |= SEEKING_WEAPON; + StarShipPtr->RaceDescPtr->ship_data.ship_sounds = + SetAbsSoundIndex (StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2); + + StarShipPtr->cur_status_flags &= + ~(SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED); + } + else + { + StarShipPtr->RaceDescPtr->cyborg_control.WeaponRange = CLOSE_RANGE_WEAPON; + StarShipPtr->RaceDescPtr->ship_info.ship_flags &= ~SEEKING_WEAPON; + StarShipPtr->RaceDescPtr->ship_info.ship_flags |= IMMEDIATE_WEAPON; + StarShipPtr->RaceDescPtr->ship_data.ship_sounds = + SetAbsSoundIndex (StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 0); + + if (StarShipPtr->cur_status_flags + & (SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED)) + StarShipPtr->cur_status_flags |= + SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED; + } + } +} + +static void +mmrnmhrm_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + + if (!(ElementPtr->state_flags & APPEARING)) + { + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0) + { + /* Either we transform or text will flash */ + if (DeltaEnergy (ElementPtr, + -StarShipPtr->RaceDescPtr->characteristics.special_energy_cost)) + { + if (ElementPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.ship) + ElementPtr->next.image.farray = + StarShipPtr->RaceDescPtr->ship_data.special; + else + ElementPtr->next.image.farray = + StarShipPtr->RaceDescPtr->ship_data.ship; + ElementPtr->next.image.frame = + SetEquFrameIndex (ElementPtr->next.image.farray[0], + ElementPtr->next.image.frame); + ElementPtr->state_flags |= CHANGING; + + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } + } + } +} + +static void +uninit_mmrnmhrm (RACE_DESC *pRaceDesc) +{ + SetCustomShipData (pRaceDesc, NULL); +} + +RACE_DESC* +init_mmrnmhrm (void) +{ + RACE_DESC *RaceDescPtr; + // The caller of this func will copy the struct + static RACE_DESC new_mmrnmhrm_desc; + MMRNMHRM_DATA otherwing_desc; + + mmrnmhrm_desc.uninit_func = uninit_mmrnmhrm; + mmrnmhrm_desc.preprocess_func = mmrnmhrm_preprocess; + mmrnmhrm_desc.postprocess_func = mmrnmhrm_postprocess; + mmrnmhrm_desc.init_weapon_func = initialize_dual_weapons; + mmrnmhrm_desc.cyborg_control.intelligence_func = mmrnmhrm_intelligence; + + new_mmrnmhrm_desc = mmrnmhrm_desc; + + otherwing_desc.max_thrust = YWING_MAX_THRUST; + otherwing_desc.thrust_increment = YWING_THRUST_INCREMENT; + otherwing_desc.energy_regeneration = YWING_ENERGY_REGENERATION; + otherwing_desc.weapon_energy_cost = YWING_WEAPON_ENERGY_COST; + otherwing_desc.special_energy_cost = YWING_SPECIAL_ENERGY_COST; + otherwing_desc.energy_wait = YWING_ENERGY_WAIT; + otherwing_desc.turn_wait = YWING_TURN_WAIT; + otherwing_desc.thrust_wait = YWING_THRUST_WAIT; + otherwing_desc.weapon_wait = YWING_WEAPON_WAIT; + otherwing_desc.special_wait = YWING_SPECIAL_WAIT; + otherwing_desc.ship_mass = SHIP_MASS; + + SetCustomShipData (&new_mmrnmhrm_desc, &otherwing_desc); + + RaceDescPtr = &new_mmrnmhrm_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/mmrnmhrm/mmrnmhrm.h b/src/uqm/ships/mmrnmhrm/mmrnmhrm.h new file mode 100644 index 0000000..c2c8512 --- /dev/null +++ b/src/uqm/ships/mmrnmhrm/mmrnmhrm.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef MMRNMHRM_H +#define MMRNMHRM_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_mmrnmhrm (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* MMRNMHRM_H */ + diff --git a/src/uqm/ships/mmrnmhrm/resinst.h b/src/uqm/ships/mmrnmhrm/resinst.h new file mode 100644 index 0000000..f44285f --- /dev/null +++ b/src/uqm/ships/mmrnmhrm/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define MMRNMHRM_BIG_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.xform.large" +#define MMRNMHRM_CAPTAIN_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.captain" +#define MMRNMHRM_ICON_MASK_PMAP_ANIM "ship.mmrnmhrm.icons" +#define MMRNMHRM_MED_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.xform.medium" +#define MMRNMHRM_MICON_MASK_PMAP_ANIM "ship.mmrnmhrm.meleeicons" +#define MMRNMHRM_RACE_STRINGS "ship.mmrnmhrm.text" +#define MMRNMHRM_SHIP_SOUNDS "ship.mmrnmhrm.sounds" +#define MMRNMHRM_SML_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.xform.small" +#define MMRNMHRM_VICTORY_SONG "ship.mmrnmhrm.ditty" +#define TORP_BIG_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.torpedo.large" +#define TORP_MED_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.torpedo.medium" +#define TORP_SML_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.torpedo.small" +#define YWING_BIG_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.ywing.large" +#define YWING_MED_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.ywing.medium" +#define YWING_SML_MASK_PMAP_ANIM "ship.mmrnmhrm.graphics.ywing.small" diff --git a/src/uqm/ships/mycon/Makeinfo b/src/uqm/ships/mycon/Makeinfo new file mode 100644 index 0000000..0ba8988 --- /dev/null +++ b/src/uqm/ships/mycon/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="mycon.c" +uqm_HFILES="icode.h mycon.h resinst.h" diff --git a/src/uqm/ships/mycon/icode.h b/src/uqm/ships/mycon/icode.h new file mode 100644 index 0000000..b3caa58 --- /dev/null +++ b/src/uqm/ships/mycon/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define MYCON_CODE "ship.mycon.code" diff --git a/src/uqm/ships/mycon/mycon.c b/src/uqm/ships/mycon/mycon.c new file mode 100644 index 0000000..8c99fbe --- /dev/null +++ b/src/uqm/ships/mycon/mycon.c @@ -0,0 +1,376 @@ +//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 "mycon.h" +#include "resinst.h" + +// Core characteristics +#define MAX_CREW 20 +#define MAX_ENERGY 40 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 4 +#define MAX_THRUST /* DISPLAY_TO_WORLD (7) */ 27 +#define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 9 +#define THRUST_WAIT 6 +#define TURN_WAIT 6 +#define SHIP_MASS 7 + +// Plasmoid +#define WEAPON_ENERGY_COST 20 +#define WEAPON_WAIT 5 +#define MYCON_OFFSET 24 +#define MISSILE_OFFSET 0 +#define NUM_PLASMAS 11 +#define NUM_GLOBALLS 8 +#define PLASMA_DURATION 13 +#define MISSILE_LIFE (NUM_PLASMAS * PLASMA_DURATION) +#define MISSILE_SPEED DISPLAY_TO_WORLD (8) +#define MISSILE_DAMAGE 10 +#define TRACK_WAIT 1 + +// Regenerate +#define SPECIAL_ENERGY_COST MAX_ENERGY +#define SPECIAL_WAIT 0 +#define REGENERATION_AMOUNT 4 + +static RACE_DESC mycon_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | SEEKING_WEAPON, + 21, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + MYCON_RACE_STRINGS, + MYCON_ICON_MASK_PMAP_ANIM, + MYCON_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 1070 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 6392, 2200, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + MYCON_BIG_MASK_PMAP_ANIM, + MYCON_MED_MASK_PMAP_ANIM, + MYCON_SML_MASK_PMAP_ANIM, + }, + { + PLASMA_BIG_MASK_PMAP_ANIM, + PLASMA_MED_MASK_PMAP_ANIM, + PLASMA_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + MYCON_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + MYCON_VICTORY_SONG, + MYCON_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + DISPLAY_TO_WORLD (800), + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +plasma_preprocess (ELEMENT *ElementPtr) +{ + COUNT plasma_index; + + if (ElementPtr->mass_points > ElementPtr->hit_points) + ElementPtr->life_span = ElementPtr->hit_points * PLASMA_DURATION; + else + ElementPtr->hit_points = (BYTE)((ElementPtr->life_span * + MISSILE_DAMAGE + (MISSILE_LIFE - 1)) / MISSILE_LIFE); + ElementPtr->mass_points = ElementPtr->hit_points; + plasma_index = NUM_PLASMAS - ((ElementPtr->life_span + + (PLASMA_DURATION - 1)) / PLASMA_DURATION); + if (plasma_index != GetFrameIndex (ElementPtr->next.image.frame)) + { + ElementPtr->next.image.frame = + SetAbsFrameIndex (ElementPtr->next.image.frame, + plasma_index); + ElementPtr->state_flags |= CHANGING; + } + + if (ElementPtr->turn_wait > 0) + --ElementPtr->turn_wait; + else + { + COUNT facing; + + facing = NORMALIZE_FACING (ANGLE_TO_FACING ( + GetVelocityTravelAngle (&ElementPtr->velocity) + )); + if (TrackShip (ElementPtr, &facing) > 0) + SetVelocityVector (&ElementPtr->velocity, + MISSILE_SPEED, facing); + + ElementPtr->turn_wait = TRACK_WAIT; + } +} + +static void +plasma_blast_preprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->life_span >= ElementPtr->thrust_wait) + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->next.image.frame); + else + ElementPtr->next.image.frame = + DecFrameIndex (ElementPtr->next.image.frame); + if (ElementPtr->hTarget) + { + ELEMENT *ShipPtr; + + LockElement (ElementPtr->hTarget, &ShipPtr); + ElementPtr->next.location = ShipPtr->next.location; + UnlockElement (ElementPtr->hTarget); + } + + ElementPtr->state_flags |= CHANGING; +} + +static void +plasma_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + SIZE old_mass; + HELEMENT hBlastElement; + + old_mass = (SIZE)ElementPtr0->mass_points; + if ((ElementPtr0->pParent != ElementPtr1->pParent + || (ElementPtr1->state_flags & PLAYER_SHIP)) + && (hBlastElement = + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1))) + { + SIZE num_animations; + ELEMENT *BlastElementPtr; + + LockElement (hBlastElement, &BlastElementPtr); + BlastElementPtr->pParent = ElementPtr0->pParent; + if (!(ElementPtr1->state_flags & PLAYER_SHIP)) + BlastElementPtr->hTarget = 0; + else + { + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr1, &StarShipPtr); + BlastElementPtr->hTarget = StarShipPtr->hShip; + } + + BlastElementPtr->current.location = ElementPtr1->current.location; + + if ((num_animations = + (old_mass * NUM_GLOBALLS + + (MISSILE_DAMAGE - 1)) / MISSILE_DAMAGE) == 0) + num_animations = 1; + + BlastElementPtr->thrust_wait = (BYTE)num_animations; + BlastElementPtr->life_span = (num_animations << 1) - 1; + { + BlastElementPtr->preprocess_func = plasma_blast_preprocess; + } + BlastElementPtr->current.image.farray = ElementPtr0->next.image.farray; + BlastElementPtr->current.image.frame = + SetAbsFrameIndex (BlastElementPtr->current.image.farray[0], + NUM_PLASMAS); + + UnlockElement (hBlastElement); + } +} + +static void +mycon_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + STARSHIP *StarShipPtr; + EVALUATE_DESC *lpEvalDesc; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + if (lpEvalDesc->ObjectPtr && lpEvalDesc->MoveState == ENTICE) + { + if ((lpEvalDesc->ObjectPtr->state_flags & FINITE_LIFE) + && !(lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT)) + lpEvalDesc->MoveState = AVOID; + else + lpEvalDesc->MoveState = PURSUE; + } + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + GetElementStarShip (ShipPtr, &StarShipPtr); + if (ObjectsOfConcern[ENEMY_WEAPON_INDEX].MoveState == PURSUE) + StarShipPtr->ship_input_state &= ~THRUST; /* don't pursue seekers */ + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (StarShipPtr->weapon_counter == 0 + && lpEvalDesc->ObjectPtr + && (lpEvalDesc->which_turn <= 16 + || ShipPtr->crew_level == StarShipPtr->RaceDescPtr->ship_info.max_crew)) + { + COUNT travel_facing, direction_facing; + SIZE delta_x, delta_y; + + travel_facing = NORMALIZE_FACING ( + ANGLE_TO_FACING (GetVelocityTravelAngle (&ShipPtr->velocity) + + HALF_CIRCLE) + ); + delta_x = lpEvalDesc->ObjectPtr->current.location.x + - ShipPtr->current.location.x; + delta_y = lpEvalDesc->ObjectPtr->current.location.y + - ShipPtr->current.location.y; + direction_facing = NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) + ); + + if (NORMALIZE_FACING (direction_facing + - StarShipPtr->ShipFacing + + ANGLE_TO_FACING (QUADRANT)) + <= ANGLE_TO_FACING (HALF_CIRCLE) + && (!(StarShipPtr->cur_status_flags & + (SHIP_BEYOND_MAX_SPEED | SHIP_IN_GRAVITY_WELL)) + || NORMALIZE_FACING (direction_facing + - travel_facing + ANGLE_TO_FACING (OCTANT)) + <= ANGLE_TO_FACING (QUADRANT))) + StarShipPtr->ship_input_state |= WEAPON; + } + + if (StarShipPtr->special_counter == 0) + { + StarShipPtr->ship_input_state &= ~SPECIAL; + StarShipPtr->RaceDescPtr->cyborg_control.WeaponRange = DISPLAY_TO_WORLD (800); + if (ShipPtr->crew_level < StarShipPtr->RaceDescPtr->ship_info.max_crew) + { + StarShipPtr->RaceDescPtr->cyborg_control.WeaponRange = MISSILE_SPEED * MISSILE_LIFE; + if (StarShipPtr->RaceDescPtr->ship_info.energy_level >= SPECIAL_ENERGY_COST + && !(StarShipPtr->ship_input_state & WEAPON)) + StarShipPtr->ship_input_state |= SPECIAL; + } + } +} + +static COUNT +initialize_plasma (ELEMENT *ShipPtr, HELEMENT PlasmaArray[]) +{ + 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; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.index = 0; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = 0; + MissileBlock.pixoffs = MYCON_OFFSET; + MissileBlock.speed = MISSILE_SPEED; + MissileBlock.hit_points = MISSILE_DAMAGE; + MissileBlock.damage = MISSILE_DAMAGE; + MissileBlock.life = MISSILE_LIFE; + MissileBlock.preprocess_func = plasma_preprocess; + MissileBlock.blast_offs = MISSILE_OFFSET; + PlasmaArray[0] = initialize_missile (&MissileBlock); + + if (PlasmaArray[0]) + { + ELEMENT *PlasmaPtr; + + LockElement (PlasmaArray[0], &PlasmaPtr); + PlasmaPtr->collision_func = plasma_collision; + PlasmaPtr->turn_wait = TRACK_WAIT + 2; + UnlockElement (PlasmaArray[0]); + } + + return (1); +} + +static void +mycon_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && ElementPtr->crew_level != StarShipPtr->RaceDescPtr->ship_info.max_crew + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + SIZE add_crew; + + ProcessSound (SetAbsSoundIndex ( + /* GROW_NEW_CREW */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + if ((add_crew = REGENERATION_AMOUNT) > + StarShipPtr->RaceDescPtr->ship_info.max_crew - ElementPtr->crew_level) + add_crew = StarShipPtr->RaceDescPtr->ship_info.max_crew - ElementPtr->crew_level; + DeltaCrew (ElementPtr, add_crew); + + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } +} + +RACE_DESC* +init_mycon (void) +{ + RACE_DESC *RaceDescPtr; + + mycon_desc.postprocess_func = mycon_postprocess; + mycon_desc.init_weapon_func = initialize_plasma; + mycon_desc.cyborg_control.intelligence_func = mycon_intelligence; + + RaceDescPtr = &mycon_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/mycon/mycon.h b/src/uqm/ships/mycon/mycon.h new file mode 100644 index 0000000..8051b7c --- /dev/null +++ b/src/uqm/ships/mycon/mycon.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef MYCON_H +#define MYCON_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_mycon (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* MYCON_H */ + diff --git a/src/uqm/ships/mycon/resinst.h b/src/uqm/ships/mycon/resinst.h new file mode 100644 index 0000000..38908a2 --- /dev/null +++ b/src/uqm/ships/mycon/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define MYCON_BIG_MASK_PMAP_ANIM "ship.mycon.graphics.podship.large" +#define MYCON_CAPTAIN_MASK_PMAP_ANIM "ship.mycon.graphics.captain" +#define MYCON_ICON_MASK_PMAP_ANIM "ship.mycon.icons" +#define MYCON_MED_MASK_PMAP_ANIM "ship.mycon.graphics.podship.medium" +#define MYCON_MICON_MASK_PMAP_ANIM "ship.mycon.meleeicons" +#define MYCON_RACE_STRINGS "ship.mycon.text" +#define MYCON_SHIP_SOUNDS "ship.mycon.sounds" +#define MYCON_SML_MASK_PMAP_ANIM "ship.mycon.graphics.podship.small" +#define MYCON_VICTORY_SONG "ship.mycon.ditty" +#define PLASMA_BIG_MASK_PMAP_ANIM "ship.mycon.graphics.plasma.large" +#define PLASMA_MED_MASK_PMAP_ANIM "ship.mycon.graphics.plasma.medium" +#define PLASMA_SML_MASK_PMAP_ANIM "ship.mycon.graphics.plasma.small" diff --git a/src/uqm/ships/orz/Makeinfo b/src/uqm/ships/orz/Makeinfo new file mode 100644 index 0000000..0c4961d --- /dev/null +++ b/src/uqm/ships/orz/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="orz.c" +uqm_HFILES="icode.h orz.h resinst.h" diff --git a/src/uqm/ships/orz/icode.h b/src/uqm/ships/orz/icode.h new file mode 100644 index 0000000..bb45c4e --- /dev/null +++ b/src/uqm/ships/orz/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define ORZ_CODE "ship.orz.code" diff --git a/src/uqm/ships/orz/orz.c b/src/uqm/ships/orz/orz.c new file mode 100644 index 0000000..1a95fec --- /dev/null +++ b/src/uqm/ships/orz/orz.c @@ -0,0 +1,1083 @@ +//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); +} + diff --git a/src/uqm/ships/orz/orz.h b/src/uqm/ships/orz/orz.h new file mode 100644 index 0000000..a62caac --- /dev/null +++ b/src/uqm/ships/orz/orz.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#ifndef ORZ_H +#define ORZ_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_orz (void); + +void intruder_preprocess (ELEMENT *ElementPtr); +void marine_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1); + +#if defined(__cplusplus) +} +#endif + +#endif /* ORZ_H */ + diff --git a/src/uqm/ships/orz/resinst.h b/src/uqm/ships/orz/resinst.h new file mode 100644 index 0000000..4af5264 --- /dev/null +++ b/src/uqm/ships/orz/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define HOWITZER_BIG_MASK_PMAP_ANIM "ship.orz.graphics.howitzer.large" +#define HOWITZER_MED_MASK_PMAP_ANIM "ship.orz.graphics.howitzer.medium" +#define HOWITZER_SML_MASK_PMAP_ANIM "ship.orz.graphics.howitzer.small" +#define ORZ_BIG_MASK_PMAP_ANIM "ship.orz.graphics.nemesis.large" +#define ORZ_CAPTAIN_MASK_PMAP_ANIM "ship.orz.graphics.captain" +#define ORZ_ICON_MASK_PMAP_ANIM "ship.orz.icons" +#define ORZ_MED_MASK_PMAP_ANIM "ship.orz.graphics.nemesis.medium" +#define ORZ_MICON_MASK_PMAP_ANIM "ship.orz.meleeicons" +#define ORZ_RACE_STRINGS "ship.orz.text" +#define ORZ_SHIP_SOUNDS "ship.orz.sounds" +#define ORZ_SML_MASK_PMAP_ANIM "ship.orz.graphics.nemesis.small" +#define ORZ_VICTORY_SONG "ship.orz.ditty" +#define TURRET_BIG_MASK_PMAP_ANIM "ship.orz.graphics.turret.large" +#define TURRET_MED_MASK_PMAP_ANIM "ship.orz.graphics.turret.medium" +#define TURRET_SML_MASK_PMAP_ANIM "ship.orz.graphics.turret.small" diff --git a/src/uqm/ships/pkunk/Makeinfo b/src/uqm/ships/pkunk/Makeinfo new file mode 100644 index 0000000..54d92b0 --- /dev/null +++ b/src/uqm/ships/pkunk/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="pkunk.c" +uqm_HFILES="icode.h pkunk.h resinst.h" diff --git a/src/uqm/ships/pkunk/icode.h b/src/uqm/ships/pkunk/icode.h new file mode 100644 index 0000000..4d0d4e5 --- /dev/null +++ b/src/uqm/ships/pkunk/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define PKUNK_CODE "ship.pkunk.code" diff --git a/src/uqm/ships/pkunk/pkunk.c b/src/uqm/ships/pkunk/pkunk.c new file mode 100644 index 0000000..76f8413 --- /dev/null +++ b/src/uqm/ships/pkunk/pkunk.c @@ -0,0 +1,640 @@ +//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 "pkunk.h" +#include "resinst.h" + +#include "uqm/globdata.h" +#include "uqm/tactrans.h" +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 8 +#define MAX_ENERGY 12 +#define ENERGY_REGENERATION 0 +#define ENERGY_WAIT 0 +#define MAX_THRUST 64 +#define THRUST_INCREMENT 16 +#define THRUST_WAIT 0 +#define TURN_WAIT 0 +#define SHIP_MASS 1 + +// Triple Miniguns +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define PKUNK_OFFSET 15 +#define MISSILE_OFFSET 1 +#define MISSILE_SPEED DISPLAY_TO_WORLD (24) +#define MISSILE_LIFE 5 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 + +// Taunt +#define SPECIAL_ENERGY_COST 2 +#define SPECIAL_WAIT 16 + +// Respawn +#define PHOENIX_LIFE 12 +#define START_PHOENIX_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A) +#define TRANSITION_LIFE 1 +#define TRANSITION_SPEED DISPLAY_TO_WORLD (20) + +static RACE_DESC pkunk_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | FIRES_LEFT | FIRES_RIGHT, + 20, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + PKUNK_RACE_STRINGS, + PKUNK_ICON_MASK_PMAP_ANIM, + PKUNK_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 666 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 502, 401, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + 0, /* SPECIAL_WAIT */ + SHIP_MASS, + }, + { + { + PKUNK_BIG_MASK_PMAP_ANIM, + PKUNK_MED_MASK_PMAP_ANIM, + PKUNK_SML_MASK_PMAP_ANIM, + }, + { + BUG_BIG_MASK_PMAP_ANIM, + BUG_MED_MASK_PMAP_ANIM, + BUG_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + PKUNK_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + PKUNK_VICTORY_SONG, + PKUNK_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + CLOSE_RANGE_WEAPON + 1, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +// Private per-instance ship data +typedef struct +{ + HELEMENT hPhoenix; + ElementProcessFunc *saved_preprocess_func; + ElementProcessFunc *saved_postprocess_func; + ElementProcessFunc *saved_death_func; + +} PKUNK_DATA; + +// Local typedef +typedef PKUNK_DATA CustomShipData_t; + +// Retrieve race-specific ship data from a race desc +static CustomShipData_t * +GetCustomShipData (RACE_DESC *pRaceDesc) +{ + return pRaceDesc->data; +} + +// Set the race-specific data in a race desc +// (Re)Allocates its own storage for the data. +static void +SetCustomShipData (RACE_DESC *pRaceDesc, const CustomShipData_t *data) +{ + if (pRaceDesc->data == data) + return; // no-op + + if (pRaceDesc->data) // Out with the old + { + HFree (pRaceDesc->data); + pRaceDesc->data = NULL; + } + + if (data) // In with the new + { + CustomShipData_t* newData = HMalloc (sizeof (*data)); + *newData = *data; + pRaceDesc->data = newData; + } +} + +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 COUNT +initialize_bug_missile (ELEMENT *ShipPtr, HELEMENT MissileArray[]) +{ + COUNT i; + 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; + MissileBlock.index = 0; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = PKUNK_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; + + for (i = 0; i < 3; ++i) + { + MissileBlock.face = + StarShipPtr->ShipFacing + + (ANGLE_TO_FACING (QUADRANT) * i); + if (i == 2) + MissileBlock.face += ANGLE_TO_FACING (QUADRANT); + MissileBlock.face = NORMALIZE_FACING (MissileBlock.face); + + if ((MissileArray[i] = initialize_missile (&MissileBlock))) + { + SIZE dx, dy; + ELEMENT *MissilePtr; + + LockElement (MissileArray[i], &MissilePtr); + GetCurrentVelocityComponents (&ShipPtr->velocity, &dx, &dy); + DeltaVelocityComponents (&MissilePtr->velocity, dx, dy); + MissilePtr->current.location.x -= VELOCITY_TO_WORLD (dx); + MissilePtr->current.location.y -= VELOCITY_TO_WORLD (dy); + + MissilePtr->preprocess_func = animate; + UnlockElement (MissileArray[i]); + } + } + + return (3); +} + +static void +pkunk_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + STARSHIP *StarShipPtr; + PKUNK_DATA *PkunkData; + + GetElementStarShip (ShipPtr, &StarShipPtr); + PkunkData = GetCustomShipData (StarShipPtr->RaceDescPtr); + if (PkunkData->hPhoenix && (StarShipPtr->control & STANDARD_RATING)) + { + RemoveElement (PkunkData->hPhoenix); + FreeElement (PkunkData->hPhoenix); + PkunkData->hPhoenix = 0; + } + + if (StarShipPtr->RaceDescPtr->ship_info.energy_level < + StarShipPtr->RaceDescPtr->ship_info.max_energy + && (StarShipPtr->special_counter == 0 + || (BYTE)TFB_Random () < 20)) + StarShipPtr->ship_input_state |= SPECIAL; + else + StarShipPtr->ship_input_state &= ~SPECIAL; + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); +} + +static void pkunk_preprocess (ELEMENT *ElementPtr); + +static void +new_pkunk (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + PKUNK_DATA *PkunkData; + + GetElementStarShip (ElementPtr, &StarShipPtr); + PkunkData = GetCustomShipData (StarShipPtr->RaceDescPtr); + + ElementPtr->state_flags = APPEARING | PLAYER_SHIP | IGNORE_SIMILAR; + ElementPtr->mass_points = SHIP_MASS; + // Restore the element processing callbacks after the explosion. + // The callbacks were changed for the explosion sequence + ElementPtr->preprocess_func = PkunkData->saved_preprocess_func; + ElementPtr->postprocess_func = PkunkData->saved_postprocess_func; + ElementPtr->death_func = PkunkData->saved_death_func; + // preprocess_func() is called during the phoenix transition and + // then cleared, so we need to restore it + StarShipPtr->RaceDescPtr->preprocess_func = pkunk_preprocess; + StarShipPtr->RaceDescPtr->ship_info.crew_level = MAX_CREW; + StarShipPtr->RaceDescPtr->ship_info.energy_level = MAX_ENERGY; + /* fix vux impairment */ + StarShipPtr->RaceDescPtr->characteristics.max_thrust = MAX_THRUST; + StarShipPtr->RaceDescPtr->characteristics.thrust_increment = THRUST_INCREMENT; + StarShipPtr->RaceDescPtr->characteristics.turn_wait = TURN_WAIT; + StarShipPtr->RaceDescPtr->characteristics.thrust_wait = THRUST_WAIT; + StarShipPtr->RaceDescPtr->characteristics.special_wait = 0; + + StarShipPtr->ship_input_state = 0; + // Pkunk wins in a simultaneous destruction if it reincarnates + StarShipPtr->cur_status_flags &= PLAY_VICTORY_DITTY; + StarShipPtr->old_status_flags = 0; + StarShipPtr->energy_counter = 0; + StarShipPtr->weapon_counter = 0; + StarShipPtr->special_counter = 0; + ElementPtr->crew_level = 0; + ElementPtr->turn_wait = 0; + ElementPtr->thrust_wait = 0; + ElementPtr->life_span = NORMAL_LIFE; + + StarShipPtr->ShipFacing = NORMALIZE_FACING (TFB_Random ()); + ElementPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.ship; + ElementPtr->current.image.frame = SetAbsFrameIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship[0], + StarShipPtr->ShipFacing); + SetPrimType (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], STAMP_PRIM); + + do + { + ElementPtr->current.location.x = + WRAP_X (DISPLAY_ALIGN_X (TFB_Random ())); + ElementPtr->current.location.y = + WRAP_Y (DISPLAY_ALIGN_Y (TFB_Random ())); + } while (CalculateGravity (ElementPtr) + || TimeSpaceMatterConflict (ElementPtr)); + + // XXX: Hack: Set hTarget!=0 so that ship_preprocess() does not + // call ship_transition() for us. + ElementPtr->hTarget = StarShipPtr->hShip; +} + +// This function is called when the ship dies but reincarnates. +// The generic ship_death() function is not called for the ship in this case. +static void +pkunk_reincarnation_death (ELEMENT *ShipPtr) +{ + // Simulate ship death + StopAllBattleMusic (); + StartShipExplosion (ShipPtr, true); + // Once the explosion ends, we will get a brand new ship + ShipPtr->death_func = new_pkunk; +} + +static void +intercept_pkunk_death (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + PKUNK_DATA *PkunkData; + ELEMENT *ShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + PkunkData = GetCustomShipData (StarShipPtr->RaceDescPtr); + + if (StarShipPtr->RaceDescPtr->ship_info.crew_level != 0) + { // Ship not dead yet. + // Keep the Phoenix element alive. + ElementPtr->state_flags &= ~DISAPPEARING; + ElementPtr->life_span = 1; + return; + } + + LockElement (StarShipPtr->hShip, &ShipPtr); + // GRAVITY_MASS() indicates a warp-out here. If Pkunk dies while warping + // out, there is no reincarnation. + if (!GRAVITY_MASS (ShipPtr->mass_points + 1)) + { + // XXX: Hack: Set mass_points to indicate a reincarnation to + // FindAliveStarShip() + ShipPtr->mass_points = MAX_SHIP_MASS + 1; + // Save the various element processing callbacks before the + // explosion happens, because we were not the ones who set + // these callbacks and they are about to be changed. + PkunkData->saved_preprocess_func = ShipPtr->preprocess_func; + PkunkData->saved_postprocess_func = ShipPtr->postprocess_func; + PkunkData->saved_death_func = ShipPtr->death_func; + + ShipPtr->death_func = pkunk_reincarnation_death; + } + UnlockElement (StarShipPtr->hShip); +} + +static void +spawn_phoenix_trail (ELEMENT *ElementPtr) +{ + 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 colorTableCount = sizeof colorTable / sizeof colorTable[0]; + + ElementPtr->colorCycleIndex++; + if (ElementPtr->colorCycleIndex != colorTableCount) + { + ElementPtr->life_span = TRANSITION_LIFE; + + SetPrimColor (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], + colorTable[ElementPtr->colorCycleIndex]); + + ElementPtr->state_flags &= ~DISAPPEARING; + ElementPtr->state_flags |= CHANGING; + } // else, the element disappears. +} + +static void +phoenix_transition (ELEMENT *ElementPtr) +{ + HELEMENT hShipImage; + ELEMENT *ShipImagePtr; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + LockElement (StarShipPtr->hShip, &ShipImagePtr); + + if (!(ShipImagePtr->state_flags & NONSOLID)) + { + ElementPtr->preprocess_func = NULL; + } + else if ((hShipImage = AllocElement ())) + { + COUNT angle; + + PutElement (hShipImage); + + LockElement (hShipImage, &ShipImagePtr); + ShipImagePtr->playerNr = NEUTRAL_PLAYER_NUM; + ShipImagePtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID; + ShipImagePtr->life_span = TRANSITION_LIFE; + SetPrimType (&(GLOBAL (DisplayArray))[ShipImagePtr->PrimIndex], + STAMPFILL_PRIM); + SetPrimColor ( + &(GLOBAL (DisplayArray))[ShipImagePtr->PrimIndex], + START_PHOENIX_COLOR); + ShipImagePtr->colorCycleIndex = 0; + ShipImagePtr->current.image = ElementPtr->current.image; + ShipImagePtr->current.location = ElementPtr->current.location; + if (!(ElementPtr->state_flags & PLAYER_SHIP)) + { + angle = ElementPtr->mass_points; + + ShipImagePtr->current.location.x += + COSINE (angle, TRANSITION_SPEED); + ShipImagePtr->current.location.y += + SINE (angle, TRANSITION_SPEED); + ElementPtr->preprocess_func = NULL; + } + else + { + angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); + + ShipImagePtr->current.location.x -= + COSINE (angle, TRANSITION_SPEED) + * (ElementPtr->life_span - 1); + ShipImagePtr->current.location.y -= + SINE (angle, TRANSITION_SPEED) + * (ElementPtr->life_span - 1); + + ShipImagePtr->current.location.x = + WRAP_X (ShipImagePtr->current.location.x); + ShipImagePtr->current.location.y = + WRAP_Y (ShipImagePtr->current.location.y); + } + + ShipImagePtr->mass_points = (BYTE)angle; + ShipImagePtr->preprocess_func = phoenix_transition; + ShipImagePtr->death_func = spawn_phoenix_trail; + SetElementStarShip (ShipImagePtr, StarShipPtr); + + UnlockElement (hShipImage); + } + + UnlockElement (StarShipPtr->hShip); +} + +static void +pkunk_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + PKUNK_DATA *PkunkData; + + GetElementStarShip (ElementPtr, &StarShipPtr); + PkunkData = GetCustomShipData (StarShipPtr->RaceDescPtr); + if (ElementPtr->state_flags & APPEARING) + { + HELEMENT hPhoenix = 0; + + if (TFB_Random () & 1) + hPhoenix = AllocElement (); + + // The hPhoenix element is created and placed at the head of the + // queue so that it is preprocessed before any of the ships' elements + // are, and so before death_func() is called for the dead Pkunk. + // hPhoenix detects when the Pkunk ship dies and tweaks the ship, + // starting the death + reincarnation sequence. + if (hPhoenix) + { + ELEMENT *PhoenixPtr; + + LockElement (hPhoenix, &PhoenixPtr); + PhoenixPtr->playerNr = ElementPtr->playerNr; + PhoenixPtr->state_flags = FINITE_LIFE | NONSOLID | IGNORE_SIMILAR; + PhoenixPtr->life_span = 1; + + PhoenixPtr->death_func = intercept_pkunk_death; + + SetElementStarShip (PhoenixPtr, StarShipPtr); + + UnlockElement (hPhoenix); + InsertElement (hPhoenix, GetHeadElement ()); + } + PkunkData->hPhoenix = hPhoenix; + + // XXX: Hack: new_pkunk() sets hTarget!=0 which indicates a + // reincarnation to us. + if (ElementPtr->hTarget == 0) + { + // A brand new ship is preprocessed only once + StarShipPtr->RaceDescPtr->preprocess_func = 0; + } + else + { // Start the reincarnation sequence + COUNT angle, facing; + + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1 + ), ElementPtr); + + ElementPtr->life_span = PHOENIX_LIFE; + SetPrimType (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], + NO_PRIM); + ElementPtr->state_flags |= NONSOLID | FINITE_LIFE | CHANGING; + + facing = StarShipPtr->ShipFacing; + for (angle = OCTANT; angle < FULL_CIRCLE; angle += QUADRANT) + { + StarShipPtr->ShipFacing = NORMALIZE_FACING ( + facing + ANGLE_TO_FACING (angle) + ); + phoenix_transition (ElementPtr); + } + StarShipPtr->ShipFacing = facing; + } + } + + if (StarShipPtr->RaceDescPtr->preprocess_func) + { + StarShipPtr->cur_status_flags &= + ~(LEFT | RIGHT | THRUST | WEAPON | SPECIAL); + + if (ElementPtr->life_span == NORMAL_LIFE) + { + ElementPtr->current.image.frame = + ElementPtr->next.image.frame = + SetEquFrameIndex ( + ElementPtr->current.image.farray[0], + ElementPtr->current.image.frame); + SetPrimType (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], + STAMP_PRIM); + InitIntersectStartPoint (ElementPtr); + InitIntersectEndPoint (ElementPtr); + InitIntersectFrame (ElementPtr); + ZeroVelocityComponents (&ElementPtr->velocity); + ElementPtr->state_flags &= ~(NONSOLID | FINITE_LIFE); + ElementPtr->state_flags |= CHANGING; + + StarShipPtr->RaceDescPtr->preprocess_func = 0; + } + } +} + +static COUNT LastSound = 0; + +static void +pkunk_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (StarShipPtr->RaceDescPtr->characteristics.special_wait) + --StarShipPtr->RaceDescPtr->characteristics.special_wait; + else if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->RaceDescPtr->ship_info.energy_level < + StarShipPtr->RaceDescPtr->ship_info.max_energy) + { + COUNT CurSound; + + do + { + CurSound = + 2 + ((COUNT)TFB_Random () + % (GetSoundCount (StarShipPtr->RaceDescPtr->ship_data.ship_sounds) - 2)); + } while (CurSound == LastSound); + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, CurSound + ), ElementPtr); + LastSound = CurSound; + + DeltaEnergy (ElementPtr, SPECIAL_ENERGY_COST); + + StarShipPtr->RaceDescPtr->characteristics.special_wait = SPECIAL_WAIT; + } +} + +static void +uninit_pkunk (RACE_DESC *pRaceDesc) +{ + SetCustomShipData (pRaceDesc, NULL); +} + +RACE_DESC* +init_pkunk (void) +{ + RACE_DESC *RaceDescPtr; + // The caller of this func will copy the struct + static RACE_DESC new_pkunk_desc; + PKUNK_DATA empty_data; + memset (&empty_data, 0, sizeof (empty_data)); + + pkunk_desc.uninit_func = uninit_pkunk; + pkunk_desc.preprocess_func = pkunk_preprocess; + pkunk_desc.postprocess_func = pkunk_postprocess; + pkunk_desc.init_weapon_func = initialize_bug_missile; + pkunk_desc.cyborg_control.intelligence_func = pkunk_intelligence; + + /* copy initial ship settings to the new descriptor */ + new_pkunk_desc = pkunk_desc; + SetCustomShipData (&new_pkunk_desc, &empty_data); + + RaceDescPtr = &new_pkunk_desc; + + LastSound = 0; + // We need to reinitialise it at least each battle, to ensure + // that NetPlay is synchronised if one player played another + // game before playing against a networked opponent. + + return (RaceDescPtr); +} diff --git a/src/uqm/ships/pkunk/pkunk.h b/src/uqm/ships/pkunk/pkunk.h new file mode 100644 index 0000000..91681b8 --- /dev/null +++ b/src/uqm/ships/pkunk/pkunk.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef PKUNK_H +#define PKUNK_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_pkunk (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* PKUNK_H */ + diff --git a/src/uqm/ships/pkunk/resinst.h b/src/uqm/ships/pkunk/resinst.h new file mode 100644 index 0000000..9c1168e --- /dev/null +++ b/src/uqm/ships/pkunk/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define BUG_BIG_MASK_PMAP_ANIM "ship.pkunk.graphics.bug.large" +#define BUG_MED_MASK_PMAP_ANIM "ship.pkunk.graphics.bug.medium" +#define BUG_SML_MASK_PMAP_ANIM "ship.pkunk.graphics.bug.small" +#define PKUNK_BIG_MASK_PMAP_ANIM "ship.pkunk.graphics.fury.large" +#define PKUNK_CAPTAIN_MASK_PMAP_ANIM "ship.pkunk.graphics.captain" +#define PKUNK_ICON_MASK_PMAP_ANIM "ship.pkunk.icons" +#define PKUNK_MED_MASK_PMAP_ANIM "ship.pkunk.graphics.fury.medium" +#define PKUNK_MICON_MASK_PMAP_ANIM "ship.pkunk.meleeicons" +#define PKUNK_RACE_STRINGS "ship.pkunk.text" +#define PKUNK_SHIP_SOUNDS "ship.pkunk.sounds" +#define PKUNK_SML_MASK_PMAP_ANIM "ship.pkunk.graphics.fury.small" +#define PKUNK_VICTORY_SONG "ship.pkunk.ditty" diff --git a/src/uqm/ships/probe/Makeinfo b/src/uqm/ships/probe/Makeinfo new file mode 100644 index 0000000..27e5093 --- /dev/null +++ b/src/uqm/ships/probe/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="probe.c" +uqm_HFILES="icode.h probe.h resinst.h" diff --git a/src/uqm/ships/probe/icode.h b/src/uqm/ships/probe/icode.h new file mode 100644 index 0000000..badab2a --- /dev/null +++ b/src/uqm/ships/probe/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define URQUAN_DRONE_CODE "ship.drone.code" diff --git a/src/uqm/ships/probe/probe.c b/src/uqm/ships/probe/probe.c new file mode 100644 index 0000000..32d9149 --- /dev/null +++ b/src/uqm/ships/probe/probe.c @@ -0,0 +1,118 @@ +//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 "probe.h" +#include "resinst.h" + +#define MAX_CREW 1 +#define MAX_ENERGY 1 +#define ENERGY_REGENERATION 0 +#define WEAPON_ENERGY_COST 0 +#define SPECIAL_ENERGY_COST 0 +#define ENERGY_WAIT 0 +#define MAX_THRUST 0 +#define THRUST_INCREMENT 0 +#define TURN_WAIT 0 +#define THRUST_WAIT 0 +#define WEAPON_WAIT 0 +#define SPECIAL_WAIT 0 + +#define SHIP_MASS 0 + +static RACE_DESC probe_desc = +{ + { /* SHIP_INFO */ + 0, + 0, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + 0, + 0, + URQUAN_DRONE_MICON_MASK_PMAP_ANIM, + 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, + }, + { + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + NULL_RESOURCE, + NULL, NULL, NULL, NULL, NULL + }, + NULL_RESOURCE, + NULL_RESOURCE, + { 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 */ +}; + +RACE_DESC* +init_probe (void) +{ + RACE_DESC *RaceDescPtr; + + RaceDescPtr = &probe_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/probe/probe.h b/src/uqm/ships/probe/probe.h new file mode 100644 index 0000000..c588970 --- /dev/null +++ b/src/uqm/ships/probe/probe.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef PROBE_H +#define PROBE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_probe (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* PROBE_H */ + diff --git a/src/uqm/ships/probe/resinst.h b/src/uqm/ships/probe/resinst.h new file mode 100644 index 0000000..5365c6d --- /dev/null +++ b/src/uqm/ships/probe/resinst.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define URQUAN_DRONE_MICON_MASK_PMAP_ANIM "ship.drone.meleeicons" diff --git a/src/uqm/ships/ship.h b/src/uqm/ships/ship.h new file mode 100644 index 0000000..6a9c6d2 --- /dev/null +++ b/src/uqm/ships/ship.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/* + * This file contains definitions that are common to all ship files. + */ + +#ifndef UQM_SHIPS_SHIP_H_ +#define UQM_SHIPS_SHIP_H_ + +#include "uqm/collide.h" + +// XXX: Do we really need this one? +//#include "reslib.h" +#include "uqm/intel.h" +#include "uqm/races.h" +#include "uqm/status.h" +#include "uqm/sounds.h" +#include "uqm/weapon.h" +#include "uqm/ship.h" + + +#endif /* UQM_SHIPS_SHIP_H_ */ + diff --git a/src/uqm/ships/shofixti/Makeinfo b/src/uqm/ships/shofixti/Makeinfo new file mode 100644 index 0000000..52d9121 --- /dev/null +++ b/src/uqm/ships/shofixti/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="shofixti.c" +uqm_HFILES="icode.h resinst.h shofixti.h" diff --git a/src/uqm/ships/shofixti/icode.h b/src/uqm/ships/shofixti/icode.h new file mode 100644 index 0000000..4afe8d3 --- /dev/null +++ b/src/uqm/ships/shofixti/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SHOFIXTI_CODE "ship.shofixti.code" diff --git a/src/uqm/ships/shofixti/resinst.h b/src/uqm/ships/shofixti/resinst.h new file mode 100644 index 0000000..bd95cb2 --- /dev/null +++ b/src/uqm/ships/shofixti/resinst.h @@ -0,0 +1,23 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define DART_BIG_MASK_PMAP_ANIM "ship.shofixti.graphics.missile.large" +#define DART_MED_MASK_PMAP_ANIM "ship.shofixti.graphics.missile.medium" +#define DART_SML_MASK_PMAP_ANIM "ship.shofixti.graphics.missile.small" +#define DESTRUCT_BIG_MASK_ANIM "ship.shofixti.graphics.destruct.large" +#define DESTRUCT_MED_MASK_ANIM "ship.shofixti.graphics.destruct.medium" +#define DESTRUCT_SML_MASK_ANIM "ship.shofixti.graphics.destruct.small" +#define OLDSHOF_BIG_MASK_PMAP_ANIM "ship.shofixti.graphics.oldscout.large" +#define OLDSHOF_CAPTAIN_MASK_PMAP_ANIM "ship.shofixti.graphics.oldcaptain" +#define OLDSHOF_MED_MASK_PMAP_ANIM "ship.shofixti.graphics.oldscout.medium" +#define OLDSHOF_SML_MASK_PMAP_ANIM "ship.shofixti.graphics.oldscout.small" +#define SHOFIXTI_BIG_MASK_PMAP_ANIM "ship.shofixti.graphics.scout.large" +#define SHOFIXTI_CAPTAIN_MASK_PMAP_ANIM "ship.shofixti.graphics.captain" +#define SHOFIXTI_ICON_MASK_PMAP_ANIM "ship.shofixti.icons" +#define SHOFIXTI_MED_MASK_PMAP_ANIM "ship.shofixti.graphics.scout.medium" +#define SHOFIXTI_MICON_MASK_PMAP_ANIM "ship.shofixti.meleeicons" +#define SHOFIXTI_RACE_STRINGS "ship.shofixti.text" +#define SHOFIXTI_SHIP_SOUNDS "ship.shofixti.sounds" +#define SHOFIXTI_SML_MASK_PMAP_ANIM "ship.shofixti.graphics.scout.small" +#define SHOFIXTI_VICTORY_SONG "ship.shofixti.ditty" diff --git a/src/uqm/ships/shofixti/shofixti.c b/src/uqm/ships/shofixti/shofixti.c new file mode 100644 index 0000000..03de57e --- /dev/null +++ b/src/uqm/ships/shofixti/shofixti.c @@ -0,0 +1,521 @@ +//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 "shofixti.h" +#include "resinst.h" + +#include "uqm/globdata.h" +#include "uqm/tactrans.h" +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 6 +#define MAX_ENERGY 4 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 9 +#define MAX_THRUST 35 +#define THRUST_INCREMENT 5 +#define TURN_WAIT 1 +#define THRUST_WAIT 0 +#define WEAPON_WAIT 3 +#define SPECIAL_WAIT 0 +#define SHIP_MASS 1 + +// Dart Gun +#define WEAPON_ENERGY_COST 1 +#define SHOFIXTI_OFFSET 15 +#define MISSILE_OFFSET 1 +#define MISSILE_SPEED DISPLAY_TO_WORLD (24) +#define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 + +// Glory Device +#define SPECIAL_ENERGY_COST 0 +#define DESTRUCT_RANGE 180 +#define MAX_DESTRUCTION (DESTRUCT_RANGE / 10) + +// Full game: Tanaka/Katana's damaged ships +#define NUM_LIMPETS 3 + +static RACE_DESC shofixti_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 5, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + SHOFIXTI_RACE_STRINGS, + SHOFIXTI_ICON_MASK_PMAP_ANIM, + SHOFIXTI_MICON_MASK_PMAP_ANIM, + 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, + }, + { + { + SHOFIXTI_BIG_MASK_PMAP_ANIM, + SHOFIXTI_MED_MASK_PMAP_ANIM, + SHOFIXTI_SML_MASK_PMAP_ANIM, + }, + { + DART_BIG_MASK_PMAP_ANIM, + DART_MED_MASK_PMAP_ANIM, + DART_SML_MASK_PMAP_ANIM, + }, + { + DESTRUCT_BIG_MASK_ANIM, + DESTRUCT_MED_MASK_ANIM, + DESTRUCT_SML_MASK_ANIM, + }, + { + SHOFIXTI_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + SHOFIXTI_VICTORY_SONG, + SHOFIXTI_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 COUNT +initialize_standard_missile (ELEMENT *ShipPtr, HELEMENT MissileArray[]) +{ + + 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; + MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = SHOFIXTI_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); + + return (1); +} + +static void +destruct_preprocess (ELEMENT *ElementPtr) +{ +#define DESTRUCT_SWITCH ((NUM_EXPLOSION_FRAMES * 3) - 3) + PRIMITIVE *lpPrim; + + // ship_death() set the ship element's life_span to + // (NUM_EXPLOSION_FRAMES * 3) + lpPrim = &(GLOBAL (DisplayArray))[ElementPtr->PrimIndex]; + ElementPtr->state_flags |= CHANGING; + if (ElementPtr->life_span > DESTRUCT_SWITCH) + { + // First, stamp-fill the ship's own element with changing colors + // for 3 frames. No explosion element yet. + SetPrimType (lpPrim, STAMPFILL_PRIM); + if (ElementPtr->life_span == DESTRUCT_SWITCH + 2) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x0A), 0x0E)); + else + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F)); + } + else if (ElementPtr->life_span < DESTRUCT_SWITCH) + { + // Stamp-fill the explosion element with cycling colors for the + // remainder of the glory explosion frames. + Color color = GetPrimColor (lpPrim); + + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->current.image.frame); + if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x0A), 0x0E)); + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x0A), 0x0E))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x0A, 0x0A), 0x0C)); + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x0A, 0x0A), 0x0C))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x14, 0x0A, 0x00), 0x06)); + else if (sameColor (color, + BUILD_COLOR (MAKE_RGB15 (0x14, 0x0A, 0x00), 0x06))) + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x14, 0x00, 0x00), 0x04)); + } + else + { + HELEMENT hDestruct; + + SetPrimType (lpPrim, NO_PRIM); + // The ship's own element will not be drawn anymore but will remain + // alive all through the glory explosion. + ElementPtr->preprocess_func = NULL; + + // Spawn a separate glory explosion element. + // XXX: Why? Why not keep using the ship's element? + // Is it because of conflicting state_flags, hit_points or + // mass_points? + hDestruct = AllocElement (); + if (hDestruct) + { + ELEMENT *DestructPtr; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + + PutElement (hDestruct); + LockElement (hDestruct, &DestructPtr); + SetElementStarShip (DestructPtr, StarShipPtr); + DestructPtr->hit_points = 0; + DestructPtr->mass_points = 0; + DestructPtr->playerNr = NEUTRAL_PLAYER_NUM; + DestructPtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID; + SetPrimType (&(GLOBAL (DisplayArray))[DestructPtr->PrimIndex], + STAMPFILL_PRIM); + SetPrimColor (&(GLOBAL (DisplayArray))[DestructPtr->PrimIndex], + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F)); + DestructPtr->current.image.farray = + StarShipPtr->RaceDescPtr->ship_data.special; + DestructPtr->current.image.frame = + StarShipPtr->RaceDescPtr->ship_data.special[0]; + DestructPtr->life_span = GetFrameCount ( + DestructPtr->current.image.frame); + DestructPtr->current.location = ElementPtr->current.location; + DestructPtr->preprocess_func = destruct_preprocess; + DestructPtr->postprocess_func = NULL; + DestructPtr->death_func = NULL; + ZeroVelocityComponents (&DestructPtr->velocity); + UnlockElement (hDestruct); + } + } +} + +/* In order to detect any Orz Marines that have boarded the ship + when it self-destructs, we'll need to see some Orz functions */ +#include "../orz/orz.h" +#define ORZ_MARINE(ptr) (ptr->preprocess_func == intruder_preprocess && \ + ptr->collision_func == marine_collision) + +static void +self_destruct_kill_objects (ELEMENT *ElementPtr) +{ + // This is called during PostProcessQueue(), close to or at the end, + // for the temporary destruct element to apply the effects of glory + // explosion. The effects are not seen until the next frame. + HELEMENT hElement, hNextElement; + + for (hElement = GetHeadElement (); hElement != 0; hElement = hNextElement) + { + ELEMENT *ObjPtr; + SIZE delta_x, delta_y; + DWORD dist; + + LockElement (hElement, &ObjPtr); + hNextElement = GetSuccElement (ObjPtr); + + if (!CollidingElement (ObjPtr) && !ORZ_MARINE (ObjPtr)) + { + UnlockElement (hElement); + continue; + } + + delta_x = ObjPtr->next.location.x - ElementPtr->next.location.x; + if (delta_x < 0) + delta_x = -delta_x; + delta_y = ObjPtr->next.location.y - ElementPtr->next.location.y; + if (delta_y < 0) + delta_y = -delta_y; + delta_x = WORLD_TO_DISPLAY (delta_x); + delta_y = WORLD_TO_DISPLAY (delta_y); + dist = delta_x * delta_x + delta_y * delta_y; + if (delta_x <= DESTRUCT_RANGE && delta_y <= DESTRUCT_RANGE + && dist <= DESTRUCT_RANGE * DESTRUCT_RANGE) + { + int destruction = 1 + MAX_DESTRUCTION * + (DESTRUCT_RANGE - square_root (dist)) / DESTRUCT_RANGE; + + // XXX: Why not simply call do_damage()? + if (ObjPtr->state_flags & PLAYER_SHIP) + { + if (!DeltaCrew (ObjPtr, -destruction)) + ObjPtr->life_span = 0; + } + else if (!GRAVITY_MASS (ObjPtr->mass_points)) + { + if (destruction < ObjPtr->hit_points) + ObjPtr->hit_points -= destruction; + else + { + ObjPtr->hit_points = 0; + ObjPtr->life_span = 0; + } + } + } + + UnlockElement (hElement); + } +} + +// This function is called when the ship dies via Glory Device. +// The generic ship_death() function is not called for the ship in this case. +static void +shofixti_destruct_death (ELEMENT *ShipPtr) +{ + STARSHIP *StarShip; + STARSHIP *winner; + + GetElementStarShip (ShipPtr, &StarShip); + + StopAllBattleMusic (); + + StartShipExplosion (ShipPtr, false); + // We process the explosion ourselves because it is different + ShipPtr->preprocess_func = destruct_preprocess; + + PlaySound (SetAbsSoundIndex (StarShip->RaceDescPtr->ship_data.ship_sounds, + 1), CalcSoundPosition (ShipPtr), ShipPtr, GAME_SOUND_PRIORITY + 1); + + winner = GetWinnerStarShip (); + if (winner == NULL) + { // No winner determined yet + winner = FindAliveStarShip (ShipPtr); + if (winner == NULL) + { // No ships left alive after the Glory Device thus Shofixti wins + winner = StarShip; + } + SetWinnerStarShip (winner); + } + else if (winner == StarShip) + { // This ship is the winner + // It may have self-destructed before the ditty started playing, + // and in that case, there should be no ditty + StarShip->cur_status_flags &= ~PLAY_VICTORY_DITTY; + } + RecordShipDeath (ShipPtr); +} + +static void +self_destruct (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + HELEMENT hDestruct; + + GetElementStarShip (ElementPtr, &StarShipPtr); + + // Spawn a temporary element, which dies in this same frame, in order + // to defer the effects of the glory explosion. + // It will be the last element (or one of the last) for which the + // death_func() will be called from PostProcessQueue() in this frame. + // XXX: Why at the end? Why not just do it now? + hDestruct = AllocElement (); + if (hDestruct) + { + ELEMENT *DestructPtr; + + LockElement (hDestruct, &DestructPtr); + DestructPtr->playerNr = ElementPtr->playerNr; + DestructPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE; + DestructPtr->next.location = ElementPtr->next.location; + DestructPtr->life_span = 0; + DestructPtr->pParent = ElementPtr->pParent; + DestructPtr->hTarget = 0; + + DestructPtr->death_func = self_destruct_kill_objects; + + UnlockElement (hDestruct); + + PutElement (hDestruct); + } + + // Must kill off the remaining crew ourselves + DeltaCrew (ElementPtr, -(int)ElementPtr->crew_level); + + ElementPtr->state_flags |= NONSOLID; + ElementPtr->life_span = 0; + // The ship is now dead. It's death_func, i.e. shofixti_destruct_death(), + // will be called the next frame. + ElementPtr->death_func = shofixti_destruct_death; +} + +static void +shofixti_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + STARSHIP *StarShipPtr; + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + GetElementStarShip (ShipPtr, &StarShipPtr); + if (StarShipPtr->special_counter != 0) + return; + + if (StarShipPtr->ship_input_state & SPECIAL) + StarShipPtr->ship_input_state &= ~SPECIAL; + else + { + EVALUATE_DESC *lpWeaponEvalDesc; + EVALUATE_DESC *lpShipEvalDesc; + + lpWeaponEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + lpShipEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (StarShipPtr->RaceDescPtr->ship_data.special[0] + && (GetFrameCount (StarShipPtr->RaceDescPtr->ship_data. + captain_control.special) + - GetFrameIndex (StarShipPtr->RaceDescPtr->ship_data. + captain_control.special) > 5 + || (lpShipEvalDesc->ObjectPtr != NULL + && lpShipEvalDesc->which_turn <= 4) + || (lpWeaponEvalDesc->ObjectPtr != NULL + /* means IMMEDIATE WEAPON */ + && (((lpWeaponEvalDesc->ObjectPtr->state_flags & PLAYER_SHIP) + && ShipPtr->crew_level == 1) + || (PlotIntercept (lpWeaponEvalDesc->ObjectPtr, ShipPtr, 2, 0) + && lpWeaponEvalDesc->ObjectPtr->mass_points >= + ShipPtr->crew_level + && (TFB_Random () & 1)))))) + StarShipPtr->ship_input_state |= SPECIAL; + } +} + +static void +shofixti_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags + ^ StarShipPtr->old_status_flags) & SPECIAL) + { + StarShipPtr->RaceDescPtr->ship_data.captain_control.special = + IncFrameIndex (StarShipPtr->RaceDescPtr->ship_data. + captain_control.special); + if (GetFrameCount (StarShipPtr->RaceDescPtr->ship_data. + captain_control.special) + - GetFrameIndex (StarShipPtr->RaceDescPtr->ship_data. + captain_control.special) == 3) + self_destruct (ElementPtr); + } +} + +RACE_DESC* +init_shofixti (void) +{ + RACE_DESC *RaceDescPtr; + // The caller of this func will copy the struct + static RACE_DESC new_shofixti_desc; + + shofixti_desc.postprocess_func = shofixti_postprocess; + shofixti_desc.init_weapon_func = initialize_standard_missile; + shofixti_desc.cyborg_control.intelligence_func = shofixti_intelligence; + + new_shofixti_desc = shofixti_desc; + if (LOBYTE (GLOBAL (CurrentActivity)) == IN_ENCOUNTER + && !GET_GAME_STATE (SHOFIXTI_RECRUITED)) + { + // Tanaka/Katana flies in a damaged ship. + COUNT i; + + new_shofixti_desc.ship_data.ship_rsc[0] = OLDSHOF_BIG_MASK_PMAP_ANIM; + new_shofixti_desc.ship_data.ship_rsc[1] = OLDSHOF_MED_MASK_PMAP_ANIM; + new_shofixti_desc.ship_data.ship_rsc[2] = OLDSHOF_SML_MASK_PMAP_ANIM; + new_shofixti_desc.ship_data.special_rsc[0] = NULL_RESOURCE; + new_shofixti_desc.ship_data.special_rsc[1] = NULL_RESOURCE; + new_shofixti_desc.ship_data.special_rsc[2] = NULL_RESOURCE; + new_shofixti_desc.ship_data.captain_control.captain_rsc = + OLDSHOF_CAPTAIN_MASK_PMAP_ANIM; + + /* Weapon doesn't work as well */ + new_shofixti_desc.characteristics.weapon_wait = 10; + + /* Simulate VUX limpets */ + for (i = 0; i < NUM_LIMPETS; ++i) + { + if (++new_shofixti_desc.characteristics.turn_wait == 0) + --new_shofixti_desc.characteristics.turn_wait; + if (++new_shofixti_desc.characteristics.thrust_wait == 0) + --new_shofixti_desc.characteristics.thrust_wait; + +/* This should be the same as MIN_THRUST_INCREMENT in vux.c */ +#define MIN_THRUST_INCREMENT DISPLAY_TO_WORLD (1) + + if (new_shofixti_desc.characteristics.thrust_increment <= + MIN_THRUST_INCREMENT) + { + new_shofixti_desc.characteristics.max_thrust = + new_shofixti_desc.characteristics.thrust_increment << 1; + } + else + { + COUNT num_thrusts; + + num_thrusts = new_shofixti_desc.characteristics.max_thrust / + new_shofixti_desc.characteristics.thrust_increment; + --new_shofixti_desc.characteristics.thrust_increment; + new_shofixti_desc.characteristics.max_thrust = + new_shofixti_desc.characteristics.thrust_increment * + num_thrusts; + } + } + } + + RaceDescPtr = &new_shofixti_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/shofixti/shofixti.h b/src/uqm/ships/shofixti/shofixti.h new file mode 100644 index 0000000..e4fdd0c --- /dev/null +++ b/src/uqm/ships/shofixti/shofixti.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef SHOFIXTI_H +#define SHOFIXTI_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_shofixti (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* SHOFIXTI_H */ + diff --git a/src/uqm/ships/sis_ship/Makeinfo b/src/uqm/ships/sis_ship/Makeinfo new file mode 100644 index 0000000..540e3a6 --- /dev/null +++ b/src/uqm/ships/sis_ship/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="sis_ship.c" +uqm_HFILES="icode.h resinst.h sis_ship.h" diff --git a/src/uqm/ships/sis_ship/icode.h b/src/uqm/ships/sis_ship/icode.h new file mode 100644 index 0000000..3d57449 --- /dev/null +++ b/src/uqm/ships/sis_ship/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SIS_CODE "ship.flagship.code" diff --git a/src/uqm/ships/sis_ship/resinst.h b/src/uqm/ships/sis_ship/resinst.h new file mode 100644 index 0000000..cf8d074 --- /dev/null +++ b/src/uqm/ships/sis_ship/resinst.h @@ -0,0 +1,15 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define BLASTER_BIG_MASK_PMAP_ANIM "ship.flagship.graphics.blaster.large" +#define BLASTER_MED_MASK_PMAP_ANIM "ship.flagship.graphics.blaster.medium" +#define BLASTER_SML_MASK_PMAP_ANIM "ship.flagship.graphics.blaster.small" +#define SIS_BIG_MASK_PMAP_ANIM "ship.flagship.graphics.flagship.large" +#define SIS_CAPTAIN_MASK_PMAP_ANIM "ship.flagship.graphics.captain" +#define SIS_HYPER_MASK_PMAP_ANIM "ship.flagship.graphics.hyperspace" +#define SIS_ICON_MASK_PMAP_ANIM "ship.flagship.icons" +#define SIS_MED_MASK_PMAP_ANIM "ship.flagship.graphics.flagship.medium" +#define SIS_SHIP_SOUNDS "ship.flagship.sounds" +#define SIS_SML_MASK_PMAP_ANIM "ship.flagship.graphics.flagship.small" +#define SIS_VICTORY_SONG "ship.flagship.ditty" diff --git a/src/uqm/ships/sis_ship/sis_ship.c b/src/uqm/ships/sis_ship/sis_ship.c new file mode 100644 index 0000000..d589827 --- /dev/null +++ b/src/uqm/ships/sis_ship/sis_ship.c @@ -0,0 +1,1002 @@ +//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 "sis_ship.h" +#include "resinst.h" + +#include "uqm/colors.h" +#include "uqm/controls.h" +#include "uqm/globdata.h" +#include "uqm/hyper.h" +#include "libs/mathlib.h" + +/* Core characteristics. + * All of these are changed at init time by some module, except for + * MAX_ENERGY, THRUST_INCREMENT, and SHIP_MASS. */ + +#define MAX_CREW MAX_CREW_SIZE + /* This value gets thrown out - actual max crew is determined by the + * number of crew pods. The minimum value is 1 (just the Captain). */ + +#define MAX_ENERGY MAX_ENERGY_SIZE +#define ENERGY_REGENERATION 1 + /* Shiva furnaces increase this by 1 each. */ +#define SHIVA_ENERGY_REGEN_INC 1 + +#define ENERGY_WAIT 10 + /* Dynamos decrease this by 2 each, to a minimum of 4. */ +#define MIN_ENERGY_WAIT 4 +#define DYNAMO_UNIT_ENERGY_WAIT_DEC 2 + +#define MAX_THRUST 10 + /* Thrusters increase this and decrease THRUST_WAIT based on + * THRUST_INCREMENT, see InitDriveSlots near the bottom of this file + * for details. */ +#define THRUST_INCREMENT 4 +#define THRUST_WAIT 6 +#define TURN_WAIT 17 + /* Turning jets decrease by 2 each */ +#define SHIP_MASS MAX_SHIP_MASS + + +/* Primary weapon - energy cost and damage change at init time based on + * the number and type of weapon modules installed. */ + +#define BLASTER_DAMAGE 2 + /* This is the damage value for the basic ion bolt guns. Fusion + * blasters and hellbore cannons end up doing (BLASTER_DAMAGE * 2) + * and (BLASTER_DAMAGE * 3) damage, respectively, but this depends + * on enum values. */ + +#define BLASTER_HITS 2 /* Hitpoints for ion bolt guns, see BLASTER_DAMAGE */ + +#define WEAPON_ENERGY_COST 1 + /* This value gets thrown out and reset in an ugly manner based on + * the enum that is used for module IDs. Bigger gun = higher value. + */ +#define WEAPON_WAIT 6 +#define BLASTER_SPEED DISPLAY_TO_WORLD (24) +#define BLASTER_LIFE 12 + /* This value is greatly increased, based in part on the enum used + * for module IDs (bigger gun == longer life). See the first half of + * InitWeaponSlots */ +#define MAX_TRACKING 3 +#define TRACKER_ENERGY_COST 3 +#define BLASTER_OFFSET 8 +#define SIS_VERT_OFFSET 28 + /* Used for foward, spread, and rear slots */ +#define SIS_HORZ_OFFSET 20 + /* Used for side slot */ + + +/* Secondary weapon */ +#define SPECIAL_ENERGY_COST 0 + /* Increased by 1 for each point defense module */ +#define ANTIMISSILE_ENERGY_INC 1 +#define SPECIAL_WAIT 9 +#define LASER_RANGE (UWORD)100 +#define MAX_DEFENSE 8 + + +static RACE_DESC sis_desc = +{ + { /* SHIP_INFO */ + 0, + 16, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + NULL_RESOURCE, + SIS_ICON_MASK_PMAP_ANIM, + 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, + }, + { + { + SIS_BIG_MASK_PMAP_ANIM, + SIS_MED_MASK_PMAP_ANIM, + SIS_SML_MASK_PMAP_ANIM, + }, + { + BLASTER_BIG_MASK_PMAP_ANIM, + BLASTER_MED_MASK_PMAP_ANIM, + BLASTER_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + SIS_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + SIS_VICTORY_SONG, + SIS_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + BLASTER_SPEED * BLASTER_LIFE, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +// Private per-instance SIS data +typedef struct +{ + COUNT num_trackers; + COUNT num_blasters; + MISSILE_BLOCK MissileBlock[6]; + +} SIS_DATA; + +static void InitWeaponSlots (RACE_DESC *RaceDescPtr, + const BYTE *ModuleSlots); +static void InitModuleSlots (RACE_DESC *RaceDescPtr, + const BYTE *ModuleSlots); +static void InitDriveSlots (RACE_DESC *RaceDescPtr, + const BYTE *DriveSlots); +static void InitJetSlots (RACE_DESC *RaceDescPtr, + const BYTE *JetSlots); +static void uninit_sis (RACE_DESC *pRaceDesc); + + +// Local typedef +typedef SIS_DATA CustomShipData_t; + +// Retrieve race-specific ship data from a race desc +static CustomShipData_t * +GetCustomShipData (RACE_DESC *pRaceDesc) +{ + return pRaceDesc->data; +} + +// Set the race-specific data in a race desc +// (Re)Allocates its own storage for the data. +static void +SetCustomShipData (RACE_DESC *pRaceDesc, const CustomShipData_t *data) +{ + if (pRaceDesc->data == data) + return; // no-op + + if (pRaceDesc->data) // Out with the old + { + HFree (pRaceDesc->data); + pRaceDesc->data = NULL; + } + + if (data) // In with the new + { + CustomShipData_t* newData = HMalloc (sizeof (*data)); + *newData = *data; + pRaceDesc->data = newData; + } +} + +static void +sis_hyper_preprocess (ELEMENT *ElementPtr) +{ + SIZE udx = 0, udy = 0; + SIZE dx = 0, dy = 0; + SIZE AccelerateDirection; + STARSHIP *StarShipPtr; + + if (ElementPtr->state_flags & APPEARING) + ElementPtr->velocity = GLOBAL (velocity); + + AccelerateDirection = 0; + + GetElementStarShip (ElementPtr, &StarShipPtr); + ++StarShipPtr->weapon_counter; /* no shooting in hyperspace! */ + if ((GLOBAL (autopilot)).x == ~0 + || (GLOBAL (autopilot)).y == ~0 + || (StarShipPtr->cur_status_flags & (LEFT | RIGHT | THRUST))) + { +LeaveAutoPilot: + (GLOBAL (autopilot)).x = + (GLOBAL (autopilot)).y = ~0; + if (!(StarShipPtr->cur_status_flags & THRUST) + || (GLOBAL_SIS (FuelOnBoard) == 0 + && GET_GAME_STATE (ARILOU_SPACE_SIDE) <= 1)) + { + AccelerateDirection = -1; + GetCurrentVelocityComponents (&ElementPtr->velocity, + &dx, &dy); + udx = dx << 4; + udy = dy << 4; + + StarShipPtr->cur_status_flags &= ~THRUST; + } + } + else + { + SIZE facing; + POINT universe; + + universe.x = LOGX_TO_UNIVERSE (GLOBAL_SIS (log_x)); + universe.y = LOGY_TO_UNIVERSE (GLOBAL_SIS (log_y)); + udx = (GLOBAL (autopilot)).x - universe.x; + udy = -((GLOBAL (autopilot)).y - universe.y); + if ((dx = udx) < 0) + dx = -dx; + if ((dy = udy) < 0) + dy = -dy; + if (dx <= 1 && dy <= 1) + goto LeaveAutoPilot; + + facing = NORMALIZE_FACING (ANGLE_TO_FACING (ARCTAN (udx, udy))); + + /* This prevents ship from flying backwards on auto-pilot. + * It could also theoretically abort autopilot in a bad savegame */ + if ((StarShipPtr->cur_status_flags & SHIP_AT_MAX_SPEED) + /*|| (ElementPtr->state_flags & APPEARING)*/ ) + { + if (NORMALIZE_FACING (StarShipPtr->ShipFacing + + ANGLE_TO_FACING (QUADRANT) + - facing) > ANGLE_TO_FACING (HALF_CIRCLE)) + goto LeaveAutoPilot; + + facing = StarShipPtr->ShipFacing; + } + else if ((int)facing != (int)StarShipPtr->ShipFacing + && ElementPtr->turn_wait == 0) + { + if (NORMALIZE_FACING ( + StarShipPtr->ShipFacing - facing + ) >= ANGLE_TO_FACING (HALF_CIRCLE)) + { + facing = NORMALIZE_FACING (facing - 1); + StarShipPtr->cur_status_flags |= RIGHT; + } + else if ((int)StarShipPtr->ShipFacing != (int)facing) + { + facing = NORMALIZE_FACING (facing + 1); + StarShipPtr->cur_status_flags |= LEFT; + } + + if ((int)facing == (int)StarShipPtr->ShipFacing) + { + ZeroVelocityComponents (&ElementPtr->velocity); + } + } + + GetCurrentVelocityComponents (&ElementPtr->velocity, &dx, &dy); + if ((GLOBAL_SIS (FuelOnBoard) + || GET_GAME_STATE (ARILOU_SPACE_SIDE) > 1) + && (int)facing == (int)StarShipPtr->ShipFacing) + { + StarShipPtr->cur_status_flags |= SHIP_AT_MAX_SPEED; + AccelerateDirection = 1; + } + else + { + AccelerateDirection = -1; + udx = dx << 4; + udy = dy << 4; + } + } + + if (ElementPtr->thrust_wait == 0 && AccelerateDirection) + { + COUNT dist; + SIZE speed, velocity_increment; + + velocity_increment = WORLD_TO_VELOCITY ( + StarShipPtr->RaceDescPtr->characteristics.thrust_increment); + + if ((dist = square_root ((long)udx * udx + (long)udy * udy)) == 0) + dist = 1; /* prevent divide by zero */ + + speed = square_root ((long)dx * dx + (long)dy * dy); + if (AccelerateDirection < 0) + { + dy = (speed / velocity_increment - 1) * velocity_increment; + if (dy < speed - velocity_increment) + dy = speed - velocity_increment; + if ((speed = dy) < 0) + speed = 0; + + StarShipPtr->cur_status_flags &= ~SHIP_AT_MAX_SPEED; + } + else + { + SIZE max_velocity; + + AccelerateDirection = 0; + + max_velocity = WORLD_TO_VELOCITY ( + StarShipPtr->RaceDescPtr->characteristics.max_thrust); + + dy = (speed / velocity_increment + 1) + * velocity_increment; + if (dy < speed + velocity_increment) + dy = speed + velocity_increment; + if ((speed = dy) > max_velocity) + { + speed = max_velocity; + StarShipPtr->cur_status_flags |= SHIP_AT_MAX_SPEED; + } + } + + dx = (SIZE)((long)udx * speed / (long)dist); + dy = (SIZE)((long)udy * speed / (long)dist); + SetVelocityComponents (&ElementPtr->velocity, dx, dy); + + ElementPtr->thrust_wait = + StarShipPtr->RaceDescPtr->characteristics.thrust_wait; + } +} + +static void +sis_hyper_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GLOBAL (velocity) = ElementPtr->velocity; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (((StarShipPtr->cur_status_flags & WEAPON) || + PulsedInputState.menu[KEY_MENU_CANCEL]) + && StarShipPtr->special_counter == 0) + { +#define MENU_DELAY 10 + HyperspaceMenu (); + StarShipPtr->cur_status_flags &= ~SHIP_AT_MAX_SPEED; + StarShipPtr->special_counter = MENU_DELAY; + } +} + +static void +spawn_point_defense (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (ElementPtr->state_flags & PLAYER_SHIP) + { + HELEMENT hDefense; + + hDefense = AllocElement (); + if (hDefense) + { + ELEMENT *DefensePtr; + + LockElement (hDefense, &DefensePtr); + DefensePtr->playerNr = ElementPtr->playerNr; + DefensePtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE; + DefensePtr->death_func = spawn_point_defense; + + GetElementStarShip (ElementPtr, &StarShipPtr); + SetElementStarShip (DefensePtr, StarShipPtr); + UnlockElement (hDefense); + + PutElement (hDefense); + } + } + else + { + BOOLEAN PaidFor; + HELEMENT hObject, hNextObject; + ELEMENT *ShipPtr; + Color LaserColor; + static const Color ColorRange[] = + { + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x03, 0x00), 0x7F), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x07, 0x00), 0x7E), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x0A, 0x00), 0x7D), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x0E, 0x00), 0x7C), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x11, 0x00), 0x7B), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x15, 0x00), 0x7A), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x18, 0x00), 0x79), + BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x1C, 0x00), 0x78), + }; + + PaidFor = FALSE; + + LaserColor = ColorRange[ + StarShipPtr->RaceDescPtr->characteristics.special_energy_cost + ]; + LockElement (StarShipPtr->hShip, &ShipPtr); + for (hObject = GetTailElement (); hObject; hObject = hNextObject) + { + ELEMENT *ObjectPtr; + + LockElement (hObject, &ObjectPtr); + hNextObject = GetPredElement (ObjectPtr); + if (ObjectPtr != ShipPtr && CollidingElement (ObjectPtr) && + !OBJECT_CLOAKED (ObjectPtr)) + { + SIZE delta_x, delta_y; + + delta_x = ObjectPtr->next.location.x - + ShipPtr->next.location.x; + delta_y = ObjectPtr->next.location.y - + ShipPtr->next.location.y; + if (delta_x < 0) + delta_x = -delta_x; + if (delta_y < 0) + delta_y = -delta_y; + delta_x = WORLD_TO_DISPLAY (delta_x); + delta_y = WORLD_TO_DISPLAY (delta_y); + if ((UWORD)delta_x <= LASER_RANGE && + (UWORD)delta_y <= LASER_RANGE && + (UWORD)delta_x * (UWORD)delta_x + + (UWORD)delta_y * (UWORD)delta_y <= + LASER_RANGE * LASER_RANGE) + { + HELEMENT hPointDefense; + LASER_BLOCK LaserBlock; + + if (!PaidFor) + { + if (!DeltaEnergy (ShipPtr, + -(StarShipPtr->RaceDescPtr->characteristics.special_energy_cost + << 2))) + break; + + ProcessSound (SetAbsSoundIndex ( + /* POINT_DEFENSE_LASER */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + PaidFor = TRUE; + } + + LaserBlock.cx = ShipPtr->next.location.x; + LaserBlock.cy = ShipPtr->next.location.y; + LaserBlock.face = 0; + LaserBlock.ex = ObjectPtr->next.location.x + - ShipPtr->next.location.x; + LaserBlock.ey = ObjectPtr->next.location.y + - ShipPtr->next.location.y; + LaserBlock.sender = ShipPtr->playerNr; + LaserBlock.flags = IGNORE_SIMILAR; + LaserBlock.pixoffs = 0; + LaserBlock.color = LaserColor; + hPointDefense = initialize_laser (&LaserBlock); + if (hPointDefense) + { + ELEMENT *PDPtr; + + LockElement (hPointDefense, &PDPtr); + PDPtr->mass_points = + StarShipPtr->RaceDescPtr->characteristics.special_energy_cost; + SetElementStarShip (PDPtr, StarShipPtr); + PDPtr->hTarget = 0; + UnlockElement (hPointDefense); + + PutElement (hPointDefense); + } + } + } + UnlockElement (hObject); + } + UnlockElement (StarShipPtr->hShip); + } +} + +static void +sis_battle_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (StarShipPtr->RaceDescPtr->characteristics.special_energy_cost == 0) + { + StarShipPtr->cur_status_flags &= ~SPECIAL; + StarShipPtr->special_counter = 2; + } + if (!(StarShipPtr->RaceDescPtr->ship_info.ship_flags + & (FIRES_FORE | FIRES_RIGHT | FIRES_AFT | FIRES_LEFT))) + { + StarShipPtr->cur_status_flags &= ~WEAPON; + StarShipPtr->weapon_counter = 2; + } +} + +static void +sis_battle_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && StarShipPtr->RaceDescPtr->characteristics.special_energy_cost) + { + spawn_point_defense (ElementPtr); + } +} + +static void +blaster_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + HELEMENT hBlastElement; + + hBlastElement = weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + if (hBlastElement) + { + ELEMENT *BlastElementPtr; + + LockElement (hBlastElement, &BlastElementPtr); + switch (ElementPtr0->mass_points) + { + case BLASTER_DAMAGE * 1: + BlastElementPtr->life_span = 2; + BlastElementPtr->current.image.frame = + SetAbsFrameIndex (ElementPtr0->current.image.frame, 0); + BlastElementPtr->preprocess_func = NULL; + break; + case BLASTER_DAMAGE * 2: + BlastElementPtr->life_span = 6; + BlastElementPtr->current.image.frame = + IncFrameIndex (ElementPtr0->current.image.frame); + break; + case BLASTER_DAMAGE * 3: + BlastElementPtr->life_span = 7; + BlastElementPtr->current.image.frame = + SetAbsFrameIndex (ElementPtr0->current.image.frame, 20); + break; + } + UnlockElement (hBlastElement); + } +} + +static void +blaster_preprocess (ELEMENT *ElementPtr) +{ + BYTE wait; + + switch (ElementPtr->mass_points) + { + case BLASTER_DAMAGE * 1: + if (GetFrameIndex (ElementPtr->current.image.frame) < 8) + { + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->current.image.frame); + ElementPtr->state_flags |= CHANGING; + } + break; + case BLASTER_DAMAGE * 3: + if (GetFrameIndex (ElementPtr->current.image.frame) < 19) + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->current.image.frame); + else + ElementPtr->next.image.frame = + SetAbsFrameIndex (ElementPtr->current.image.frame, 16); + ElementPtr->state_flags |= CHANGING; + break; + } + + if (LONIBBLE (ElementPtr->turn_wait)) + --ElementPtr->turn_wait; + else if ((wait = HINIBBLE (ElementPtr->turn_wait))) + { + COUNT facing; + + facing = NORMALIZE_FACING (ANGLE_TO_FACING ( + GetVelocityTravelAngle (&ElementPtr->velocity))); + if (TrackShip (ElementPtr, &facing) > 0) + SetVelocityVector (&ElementPtr->velocity, BLASTER_SPEED, facing); + + ElementPtr->turn_wait = MAKE_BYTE (wait, wait); + } +} + +static COUNT +initialize_blasters (ELEMENT *ShipPtr, HELEMENT BlasterArray[]) +{ + BYTE nt; + COUNT i; + STARSHIP *StarShipPtr; + SIS_DATA *SisData; + + GetElementStarShip (ShipPtr, &StarShipPtr); + SisData = GetCustomShipData (StarShipPtr->RaceDescPtr); + + nt = (BYTE)((4 - SisData->num_trackers) & 3); + + for (i = 0; i < SisData->num_blasters; ++i) + { + MISSILE_BLOCK MissileBlock = SisData->MissileBlock[i]; + + MissileBlock.cx = ShipPtr->next.location.x; + MissileBlock.cy = ShipPtr->next.location.y; + MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.face = NORMALIZE_FACING (StarShipPtr->ShipFacing + + MissileBlock.face); + + BlasterArray[i] = initialize_missile (&MissileBlock); + if (BlasterArray[i]) + { + ELEMENT *BlasterPtr; + + LockElement (BlasterArray[i], &BlasterPtr); + BlasterPtr->collision_func = blaster_collision; + BlasterPtr->turn_wait = MAKE_BYTE (nt, nt); + UnlockElement (BlasterArray[i]); + } + + } + + return SisData->num_blasters; +} + +static void +sis_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + EVALUATE_DESC *lpEvalDesc; + STARSHIP *StarShipPtr; + SIS_DATA *SisData; + + GetElementStarShip (ShipPtr, &StarShipPtr); + SisData = GetCustomShipData (StarShipPtr->RaceDescPtr); + + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + if (lpEvalDesc->ObjectPtr) + { + if (StarShipPtr->RaceDescPtr->characteristics.special_energy_cost) + { + if (StarShipPtr->special_counter == 0 + && ((lpEvalDesc->ObjectPtr + && lpEvalDesc->which_turn <= 2) + || (ObjectsOfConcern[ENEMY_SHIP_INDEX].ObjectPtr != NULL + && ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn <= 4))) + StarShipPtr->ship_input_state |= SPECIAL; + else + StarShipPtr->ship_input_state &= ~SPECIAL; + lpEvalDesc->ObjectPtr = NULL; + } + else if (MANEUVERABILITY (&StarShipPtr->RaceDescPtr->cyborg_control) + < MEDIUM_SHIP + && lpEvalDesc->MoveState == ENTICE + && (!(lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT) + || lpEvalDesc->which_turn <= 8) + && (!(lpEvalDesc->ObjectPtr->state_flags & FINITE_LIFE) + || (lpEvalDesc->ObjectPtr->mass_points >= 4 + && lpEvalDesc->which_turn == 2 + && ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn > 16))) + lpEvalDesc->MoveState = PURSUE; + } + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (SisData->num_trackers + && StarShipPtr->weapon_counter == 0 + && !(StarShipPtr->ship_input_state & WEAPON) + && lpEvalDesc->ObjectPtr + && lpEvalDesc->which_turn <= 16) + { + COUNT direction_facing; + SIZE delta_x, delta_y; + UWORD fire_flags, ship_flags; + COUNT facing; + + delta_x = lpEvalDesc->ObjectPtr->current.location.x + - ShipPtr->current.location.x; + delta_y = lpEvalDesc->ObjectPtr->current.location.y + - ShipPtr->current.location.y; + direction_facing = NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y))); + + ship_flags = StarShipPtr->RaceDescPtr->ship_info.ship_flags; + for (fire_flags = FIRES_FORE, facing = StarShipPtr->ShipFacing; + fire_flags <= FIRES_LEFT; + fire_flags <<= 1, facing += QUADRANT) + { + if ((ship_flags & fire_flags) && NORMALIZE_FACING ( + direction_facing - facing + ANGLE_TO_FACING (OCTANT) + ) <= ANGLE_TO_FACING (QUADRANT)) + { + StarShipPtr->ship_input_state |= WEAPON; + break; + } + } + } +} + +static void +InitWeaponSlots (RACE_DESC *RaceDescPtr, const BYTE *ModuleSlots) +{ + COUNT i; + SIS_DATA *SisData = GetCustomShipData (RaceDescPtr); + MISSILE_BLOCK *lpMB = SisData->MissileBlock; + + SisData->num_blasters = 0; + for (i = 0; i < NUM_MODULE_SLOTS; ++i) + { + COUNT which_gun; + + if (i == 3) + i = NUM_MODULE_SLOTS - 1; + + which_gun = ModuleSlots[(NUM_MODULE_SLOTS - 1) - i]; + + if (which_gun < GUN_WEAPON || which_gun > CANNON_WEAPON) + continue; /* not a gun */ + + which_gun -= GUN_WEAPON - 1; + RaceDescPtr->characteristics.weapon_energy_cost += + which_gun * 2; + + lpMB->flags = IGNORE_SIMILAR; + lpMB->blast_offs = BLASTER_OFFSET; + lpMB->speed = BLASTER_SPEED; + lpMB->preprocess_func = blaster_preprocess; + lpMB->hit_points = BLASTER_HITS * which_gun; + lpMB->damage = BLASTER_DAMAGE * which_gun; + lpMB->life = BLASTER_LIFE + ((BLASTER_LIFE >> 2) * (which_gun - 1)); + + if (which_gun == 1) + lpMB->index = 0; + else if (which_gun == 2) + lpMB->index = 9; + else + lpMB->index = 16; + + switch (i) + { + case 0: /* NOSE WEAPON */ + RaceDescPtr->ship_info.ship_flags |= FIRES_FORE; + lpMB->pixoffs = SIS_VERT_OFFSET; + lpMB->face = 0; + break; + case 1: /* SPREAD WEAPON */ + RaceDescPtr->ship_info.ship_flags |= FIRES_FORE; + lpMB->pixoffs = SIS_VERT_OFFSET; + lpMB->face = +1; + /* copy it because there are two */ + lpMB[1] = lpMB[0]; + ++lpMB; + ++SisData->num_blasters; + lpMB->face = NORMALIZE_FACING (-1); + break; + case 2: /* SIDE WEAPON */ + RaceDescPtr->ship_info.ship_flags |= + FIRES_LEFT | FIRES_RIGHT; + lpMB->pixoffs = SIS_HORZ_OFFSET; + lpMB->face = ANGLE_TO_FACING (QUADRANT); + /* copy it because there are two */ + lpMB[1] = lpMB[0]; + ++lpMB; + ++SisData->num_blasters; + lpMB->face = NORMALIZE_FACING (-ANGLE_TO_FACING (QUADRANT)); + break; + case NUM_MODULE_SLOTS - 1: /* TAIL WEAPON */ + RaceDescPtr->ship_info.ship_flags |= FIRES_AFT; + lpMB->pixoffs = SIS_VERT_OFFSET; + lpMB->face = ANGLE_TO_FACING (HALF_CIRCLE); + break; + } + + ++lpMB; + ++SisData->num_blasters; + } +} + +static void +InitModuleSlots (RACE_DESC *RaceDescPtr, const BYTE *ModuleSlots) +{ + COUNT i; + COUNT num_trackers; + SIS_DATA *SisData = GetCustomShipData (RaceDescPtr); + + RaceDescPtr->ship_info.max_crew = 0; + num_trackers = 0; + for (i = 0; i < NUM_MODULE_SLOTS; ++i) + { + BYTE which_mod; + + which_mod = ModuleSlots[(NUM_MODULE_SLOTS - 1) - i]; + switch (which_mod) + { + case CREW_POD: + RaceDescPtr->ship_info.max_crew += CREW_POD_CAPACITY; + break; + case TRACKING_SYSTEM: + ++num_trackers; + break; + case ANTIMISSILE_DEFENSE: + RaceDescPtr->characteristics.special_energy_cost += + ANTIMISSILE_ENERGY_INC; + break; + case SHIVA_FURNACE: + RaceDescPtr->characteristics.energy_regeneration += + SHIVA_ENERGY_REGEN_INC; + break; + case DYNAMO_UNIT: + RaceDescPtr->characteristics.energy_wait -= + DYNAMO_UNIT_ENERGY_WAIT_DEC; + if (RaceDescPtr->characteristics.energy_wait < MIN_ENERGY_WAIT) + RaceDescPtr->characteristics.energy_wait = MIN_ENERGY_WAIT; + break; + } + } + + if (num_trackers > MAX_TRACKING) + num_trackers = MAX_TRACKING; + RaceDescPtr->characteristics.weapon_energy_cost += + num_trackers * TRACKER_ENERGY_COST; + SisData->num_trackers = num_trackers; + if (RaceDescPtr->characteristics.special_energy_cost) + { + RaceDescPtr->ship_info.ship_flags |= POINT_DEFENSE; + if (RaceDescPtr->characteristics.special_energy_cost > MAX_DEFENSE) + RaceDescPtr->characteristics.special_energy_cost = MAX_DEFENSE; + } +} + +static void +InitDriveSlots (RACE_DESC *RaceDescPtr, const BYTE *DriveSlots) +{ + COUNT i; + + // NB. RaceDescPtr->characteristics.max_thrust is already initialised. + RaceDescPtr->characteristics.thrust_wait = 0; + for (i = 0; i < NUM_DRIVE_SLOTS; ++i) + { + switch (DriveSlots[i]) + { + case FUSION_THRUSTER: + RaceDescPtr->characteristics.max_thrust += 2; + ++RaceDescPtr->characteristics.thrust_wait; + break; + } + } + RaceDescPtr->characteristics.thrust_wait = (BYTE)( + THRUST_WAIT - (RaceDescPtr->characteristics.thrust_wait >> 1)); + RaceDescPtr->characteristics.max_thrust = + ((RaceDescPtr->characteristics.max_thrust / + RaceDescPtr->characteristics.thrust_increment) + 1) + * RaceDescPtr->characteristics.thrust_increment; +} + +static void +InitJetSlots (RACE_DESC *RaceDescPtr, const BYTE *JetSlots) +{ + COUNT i; + + for (i = 0; i < NUM_JET_SLOTS; ++i) + { + switch (JetSlots[i]) + { + case TURNING_JETS: + RaceDescPtr->characteristics.turn_wait -= 2; + break; + } + } +} + +RACE_DESC* +init_sis (void) +{ + RACE_DESC *RaceDescPtr; + COUNT i; + // The caller of this func will copy the struct + static RACE_DESC new_sis_desc; + SIS_DATA empty_data; + memset (&empty_data, 0, sizeof (empty_data)); + + /* copy initial ship settings to new_sis_desc */ + new_sis_desc = sis_desc; + + new_sis_desc.uninit_func = uninit_sis; + + if (inHQSpace ()) + { + for (i = 0; i < NUM_VIEWS; ++i) + { + new_sis_desc.ship_data.ship_rsc[i] = NULL_RESOURCE; + new_sis_desc.ship_data.weapon_rsc[i] = NULL_RESOURCE; + new_sis_desc.ship_data.special_rsc[i] = NULL_RESOURCE; + } + new_sis_desc.ship_info.icons_rsc = NULL_RESOURCE; + new_sis_desc.ship_data.captain_control.captain_rsc = NULL_RESOURCE; + new_sis_desc.ship_data.victory_ditty_rsc = NULL_RESOURCE; + new_sis_desc.ship_data.ship_sounds_rsc = NULL_RESOURCE; + + new_sis_desc.ship_data.ship_rsc[0] = SIS_HYPER_MASK_PMAP_ANIM; + + new_sis_desc.preprocess_func = sis_hyper_preprocess; + new_sis_desc.postprocess_func = sis_hyper_postprocess; + + new_sis_desc.characteristics.max_thrust -= 4; + } + else + { + new_sis_desc.preprocess_func = sis_battle_preprocess; + new_sis_desc.postprocess_func = sis_battle_postprocess; + new_sis_desc.init_weapon_func = initialize_blasters; + new_sis_desc.cyborg_control.intelligence_func = sis_intelligence; + + if (GET_GAME_STATE (CHMMR_BOMB_STATE) == 3) + SET_GAME_STATE (BOMB_CARRIER, 1); + } + + SetCustomShipData (&new_sis_desc, &empty_data); + InitModuleSlots (&new_sis_desc, GLOBAL_SIS (ModuleSlots)); + InitWeaponSlots (&new_sis_desc, GLOBAL_SIS (ModuleSlots)); + InitDriveSlots (&new_sis_desc, GLOBAL_SIS (DriveSlots)); + InitJetSlots (&new_sis_desc, GLOBAL_SIS (JetSlots)); + + if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE) + { + new_sis_desc.ship_info.crew_level = new_sis_desc.ship_info.max_crew; + } + else + { + // Count the captain too. + new_sis_desc.ship_info.max_crew++; + new_sis_desc.ship_info.crew_level = GLOBAL_SIS (CrewEnlisted) + 1; + new_sis_desc.ship_info.ship_flags |= PLAYER_CAPTAIN; + } + + new_sis_desc.ship_info.energy_level = new_sis_desc.ship_info.max_energy; + + RaceDescPtr = &new_sis_desc; + + return (RaceDescPtr); +} + +static void +uninit_sis (RACE_DESC *pRaceDesc) +{ + if (!inHQSpace ()) + { + GLOBAL_SIS (CrewEnlisted) = pRaceDesc->ship_info.crew_level; + if (pRaceDesc->ship_info.ship_flags & PLAYER_CAPTAIN) + GLOBAL_SIS (CrewEnlisted)--; + } + + SetCustomShipData (pRaceDesc, NULL); +} + + diff --git a/src/uqm/ships/sis_ship/sis_ship.h b/src/uqm/ships/sis_ship/sis_ship.h new file mode 100644 index 0000000..ffe0776 --- /dev/null +++ b/src/uqm/ships/sis_ship/sis_ship.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef SIS_SHIP_H +#define SIS_SHIP_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_sis (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* SIS_SHIP_H */ + diff --git a/src/uqm/ships/slylandr/Makeinfo b/src/uqm/ships/slylandr/Makeinfo new file mode 100644 index 0000000..309b1d4 --- /dev/null +++ b/src/uqm/ships/slylandr/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="slylandr.c" +uqm_HFILES="icode.h resinst.h slylandr.h" diff --git a/src/uqm/ships/slylandr/icode.h b/src/uqm/ships/slylandr/icode.h new file mode 100644 index 0000000..9897234 --- /dev/null +++ b/src/uqm/ships/slylandr/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SLYLANDRO_CODE "ship.slylandro.code" diff --git a/src/uqm/ships/slylandr/resinst.h b/src/uqm/ships/slylandr/resinst.h new file mode 100644 index 0000000..00df833 --- /dev/null +++ b/src/uqm/ships/slylandr/resinst.h @@ -0,0 +1,13 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SLYLANDRO_BIG_MASK_PMAP_ANIM "ship.slylandro.graphics.probe.large" +#define SLYLANDRO_CAPTAIN_MASK_PMAP_ANIM "ship.slylandro.graphics.captain" +#define SLYLANDRO_ICON_MASK_PMAP_ANIM "ship.slylandro.icons" +#define SLYLANDRO_MED_MASK_PMAP_ANIM "ship.slylandro.graphics.probe.medium" +#define SLYLANDRO_MICON_MASK_PMAP_ANIM "ship.slylandro.meleeicons" +#define SLYLANDRO_RACE_STRINGS "ship.slylandro.text" +#define SLYLANDRO_SHIP_SOUNDS "ship.slylandro.sounds" +#define SLYLANDRO_SML_MASK_PMAP_ANIM "ship.slylandro.graphics.probe.small" +#define SLYLANDRO_VICTORY_SONG "ship.slylandro.ditty" diff --git a/src/uqm/ships/slylandr/slylandr.c b/src/uqm/ships/slylandr/slylandr.c new file mode 100644 index 0000000..8c4ca95 --- /dev/null +++ b/src/uqm/ships/slylandr/slylandr.c @@ -0,0 +1,438 @@ +//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 "slylandr.h" +#include "resinst.h" + +#include "uqm/globdata.h" +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 12 +#define MAX_ENERGY 20 +#define ENERGY_REGENERATION 0 +#define ENERGY_WAIT 10 +#define MAX_THRUST 60 +#define THRUST_INCREMENT MAX_THRUST +#define THRUST_WAIT 0 +#define TURN_WAIT 0 +#define SHIP_MASS 1 + +// Lightning weapon +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 17 +#define SLYLANDRO_OFFSET 9 +#define LASER_LENGTH 32 + /* Total length of lighting bolts. Actual range is usually less than + * this, since the lightning rarely is straight. */ + +// Harvester +#define SPECIAL_ENERGY_COST 0 +#define SPECIAL_WAIT 20 +#define HARVEST_RANGE (208 * 3 / 8) + /* Was originally (SPACE_HEIGHT * 3 / 8) */ + +static RACE_DESC slylandro_desc = +{ + { /* SHIP_INFO */ + SEEKING_WEAPON | CREW_IMMUNE, + 17, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + SLYLANDRO_RACE_STRINGS, + SLYLANDRO_ICON_MASK_PMAP_ANIM, + SLYLANDRO_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + INFINITE_RADIUS, /* Initial sphere of influence radius */ + { /* Known location (center of SoI) */ + 333, 9812, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + SLYLANDRO_BIG_MASK_PMAP_ANIM, + SLYLANDRO_MED_MASK_PMAP_ANIM, + SLYLANDRO_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + SLYLANDRO_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + SLYLANDRO_VICTORY_SONG, + SLYLANDRO_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + CLOSE_RANGE_WEAPON << 1, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static COUNT initialize_lightning (ELEMENT *ElementPtr, + HELEMENT LaserArray[]); + +static void +lightning_postprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->turn_wait + && !(ElementPtr->state_flags & COLLISION)) + { + HELEMENT Lightning; + + initialize_lightning (ElementPtr, &Lightning); + if (Lightning) + PutElement (Lightning); + } +} + +static void +lightning_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr0, &StarShipPtr); + if (StarShipPtr->weapon_counter > WEAPON_WAIT >> 1) + StarShipPtr->weapon_counter = + WEAPON_WAIT - StarShipPtr->weapon_counter; + StarShipPtr->weapon_counter -= ElementPtr0->turn_wait; + ElementPtr0->turn_wait = 0; + + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); +} + +static COUNT +initialize_lightning (ELEMENT *ElementPtr, HELEMENT LaserArray[]) +{ + LASER_BLOCK LaserBlock; + + LaserBlock.cx = ElementPtr->next.location.x; + LaserBlock.cy = ElementPtr->next.location.y; + LaserBlock.ex = 0; + LaserBlock.ey = 0; + + LaserBlock.sender = ElementPtr->playerNr; + LaserBlock.flags = IGNORE_SIMILAR; + LaserBlock.face = 0; + LaserBlock.pixoffs = 0; + LaserArray[0] = initialize_laser (&LaserBlock); + + if (LaserArray[0]) + { + SIZE delta; + COUNT angle, facing; + DWORD rand_val; + ELEMENT *LaserPtr; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + + LockElement (LaserArray[0], &LaserPtr); + LaserPtr->postprocess_func = lightning_postprocess; + LaserPtr->collision_func = lightning_collision; + + rand_val = TFB_Random (); + + if (!(ElementPtr->state_flags & PLAYER_SHIP)) + { + angle = GetVelocityTravelAngle (&ElementPtr->velocity); + facing = NORMALIZE_FACING (ANGLE_TO_FACING (angle)); + delta = TrackShip (ElementPtr, &facing); + + LaserPtr->turn_wait = ElementPtr->turn_wait - 1; + + SetPrimColor (&(GLOBAL (DisplayArray))[LaserPtr->PrimIndex], + GetPrimColor (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex])); + } + else + { + facing = StarShipPtr->ShipFacing; + ElementPtr->hTarget = 0; + delta = TrackShip (ElementPtr, &facing); + ElementPtr->hTarget = 0; + angle = FACING_TO_ANGLE (facing); + + if ((LaserPtr->turn_wait = StarShipPtr->weapon_counter) == 0) + LaserPtr->turn_wait = WEAPON_WAIT; + + if (LaserPtr->turn_wait > WEAPON_WAIT >> 1) + LaserPtr->turn_wait = WEAPON_WAIT - LaserPtr->turn_wait; + + switch (HIBYTE (LOWORD (rand_val)) & 3) + { + case 0: + SetPrimColor ( + &(GLOBAL (DisplayArray))[LaserPtr->PrimIndex], + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F) + ); + break; + case 1: + SetPrimColor ( + &(GLOBAL (DisplayArray))[LaserPtr->PrimIndex], + BUILD_COLOR (MAKE_RGB15 (0x16, 0x17, 0x1F), 0x42) + ); + break; + case 2: + SetPrimColor ( + &(GLOBAL (DisplayArray))[LaserPtr->PrimIndex], + BUILD_COLOR (MAKE_RGB15 (0x06, 0x07, 0x1F), 0x4A) + ); + break; + case 3: + SetPrimColor ( + &(GLOBAL (DisplayArray))[LaserPtr->PrimIndex], + BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x18), 0x50) + ); + break; + } + } + + if (delta == -1 || delta == ANGLE_TO_FACING (HALF_CIRCLE)) + angle += LOWORD (rand_val); + else if (delta == 0) + angle += LOWORD (rand_val) & 1 ? -1 : 1; + else if (delta < ANGLE_TO_FACING (HALF_CIRCLE)) + angle += LOWORD (rand_val) & (QUADRANT - 1); + else + angle -= LOWORD (rand_val) & (QUADRANT - 1); + delta = WORLD_TO_VELOCITY ( + DISPLAY_TO_WORLD ((HIWORD (rand_val) & (LASER_LENGTH - 1)) + 4) + ); + SetVelocityComponents (&LaserPtr->velocity, + COSINE (angle, delta), SINE (angle, delta)); + + SetElementStarShip (LaserPtr, StarShipPtr); + UnlockElement (LaserArray[0]); + } + + return (1); +} + +static void +slylandro_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + EVALUATE_DESC *lpEvalDesc; + STARSHIP *StarShipPtr; + + if (LOBYTE (GLOBAL (CurrentActivity)) == IN_ENCOUNTER) + /* no dodging in role playing game */ + ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr = 0; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + + GetElementStarShip (ShipPtr, &StarShipPtr); + if (StarShipPtr->special_counter == 0 + && StarShipPtr->RaceDescPtr->ship_info.energy_level == 0 + && ObjectsOfConcern[GRAVITY_MASS_INDEX].ObjectPtr == 0) + ConcernCounter = FIRST_EMPTY_INDEX + 1; + if (lpEvalDesc->ObjectPtr && lpEvalDesc->MoveState == PURSUE + && lpEvalDesc->which_turn <= 6) + lpEvalDesc->MoveState = ENTICE; + + ++ShipPtr->thrust_wait; + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + --ShipPtr->thrust_wait; + + if (lpEvalDesc->ObjectPtr && lpEvalDesc->which_turn <= 14) + StarShipPtr->ship_input_state |= WEAPON; + else + StarShipPtr->ship_input_state &= ~WEAPON; + + StarShipPtr->ship_input_state &= ~SPECIAL; + if (StarShipPtr->RaceDescPtr->ship_info.energy_level < + StarShipPtr->RaceDescPtr->ship_info.max_energy) + { + lpEvalDesc = &ObjectsOfConcern[FIRST_EMPTY_INDEX]; + if (lpEvalDesc->ObjectPtr && lpEvalDesc->which_turn <= 14) + StarShipPtr->ship_input_state |= SPECIAL; + } +} + +static BOOLEAN +harvest_space_junk (ELEMENT *ElementPtr) +{ + BOOLEAN retval; + HELEMENT hElement, hNextElement; + + retval = FALSE; + for (hElement = GetHeadElement (); + hElement; hElement = hNextElement) + { + ELEMENT *ObjPtr; + + LockElement (hElement, &ObjPtr); + hNextElement = GetSuccElement (ObjPtr); + + if (!(ObjPtr->state_flags & (APPEARING | PLAYER_SHIP | FINITE_LIFE)) + && ObjPtr->playerNr == NEUTRAL_PLAYER_NUM + && !GRAVITY_MASS (ObjPtr->mass_points) + && CollisionPossible (ObjPtr, ElementPtr)) + { + SIZE dx, dy; + + if ((dx = ObjPtr->next.location.x + - ElementPtr->next.location.x) < 0) + dx = -dx; + if ((dy = ObjPtr->next.location.y + - ElementPtr->next.location.y) < 0) + dy = -dy; + dx = WORLD_TO_DISPLAY (dx); + dy = WORLD_TO_DISPLAY (dy); + if (dx <= HARVEST_RANGE && dy <= HARVEST_RANGE + && dx * dx + dy * dy <= HARVEST_RANGE * HARVEST_RANGE) + { + ObjPtr->life_span = 0; + ObjPtr->state_flags |= NONSOLID; + + if (!retval) + { + STARSHIP *StarShipPtr; + + retval = TRUE; + + GetElementStarShip (ElementPtr, &StarShipPtr); + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + DeltaEnergy (ElementPtr, MAX_ENERGY); + } + } + } + + UnlockElement (hElement); + } + + return (retval); +} + +static void +slylandro_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (StarShipPtr->weapon_counter + && StarShipPtr->weapon_counter < WEAPON_WAIT) + { + HELEMENT Lightning; + + initialize_lightning (ElementPtr, &Lightning); + if (Lightning) + PutElement (Lightning); + } + + if (StarShipPtr->special_counter == 0 + && (StarShipPtr->cur_status_flags & SPECIAL) + && harvest_space_junk (ElementPtr)) + { + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } +} + +static void +slylandro_preprocess (ELEMENT *ElementPtr) +{ + if (!(ElementPtr->state_flags & (APPEARING | NONSOLID))) + { + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & THRUST) + && !(StarShipPtr->old_status_flags & THRUST)) + StarShipPtr->ShipFacing += ANGLE_TO_FACING (HALF_CIRCLE); + + if (ElementPtr->turn_wait == 0) + { + ElementPtr->turn_wait += + StarShipPtr->RaceDescPtr->characteristics.turn_wait + 1; + if (StarShipPtr->cur_status_flags & LEFT) + --StarShipPtr->ShipFacing; + else if (StarShipPtr->cur_status_flags & RIGHT) + ++StarShipPtr->ShipFacing; + } + + StarShipPtr->ShipFacing = NORMALIZE_FACING (StarShipPtr->ShipFacing); + + if (ElementPtr->thrust_wait == 0) + { + ElementPtr->thrust_wait += + StarShipPtr->RaceDescPtr->characteristics.thrust_wait + 1; + + SetVelocityVector (&ElementPtr->velocity, + StarShipPtr->RaceDescPtr->characteristics.max_thrust, + StarShipPtr->ShipFacing); + StarShipPtr->cur_status_flags |= SHIP_AT_MAX_SPEED; + StarShipPtr->cur_status_flags &= ~SHIP_IN_GRAVITY_WELL; + } + + ElementPtr->next.image.frame = IncFrameIndex (ElementPtr->next.image.frame); + ElementPtr->state_flags |= CHANGING; + } +} + +RACE_DESC* +init_slylandro (void) +{ + RACE_DESC *RaceDescPtr; + + slylandro_desc.preprocess_func = slylandro_preprocess; + slylandro_desc.postprocess_func = slylandro_postprocess; + slylandro_desc.init_weapon_func = initialize_lightning; + slylandro_desc.cyborg_control.intelligence_func = slylandro_intelligence; + + RaceDescPtr = &slylandro_desc; + + return (RaceDescPtr); +} diff --git a/src/uqm/ships/slylandr/slylandr.h b/src/uqm/ships/slylandr/slylandr.h new file mode 100644 index 0000000..a55362d --- /dev/null +++ b/src/uqm/ships/slylandr/slylandr.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef SLYLANDR_H +#define SLYLANDR_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_slylandro (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* SLYLANDR_H */ + diff --git a/src/uqm/ships/spathi/Makeinfo b/src/uqm/ships/spathi/Makeinfo new file mode 100644 index 0000000..48dc3f9 --- /dev/null +++ b/src/uqm/ships/spathi/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="spathi.c" +uqm_HFILES="icode.h resinst.h spathi.h" diff --git a/src/uqm/ships/spathi/icode.h b/src/uqm/ships/spathi/icode.h new file mode 100644 index 0000000..aa5f6ef --- /dev/null +++ b/src/uqm/ships/spathi/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SPATHI_CODE "ship.spathi.code" diff --git a/src/uqm/ships/spathi/resinst.h b/src/uqm/ships/spathi/resinst.h new file mode 100644 index 0000000..1d4ecf6 --- /dev/null +++ b/src/uqm/ships/spathi/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define DISCRIM_BIG_MASK_PMAP_ANIM "ship.spathi.graphics.butt.large" +#define DISCRIM_MED_MASK_PMAP_ANIM "ship.spathi.graphics.butt.medium" +#define DISCRIM_SML_MASK_PMAP_ANIM "ship.spathi.graphics.butt.small" +#define MISSILE_BIG_MASK_PMAP_ANIM "ship.spathi.graphics.missile.large" +#define MISSILE_MED_MASK_PMAP_ANIM "ship.spathi.graphics.missile.medium" +#define MISSILE_SML_MASK_PMAP_ANIM "ship.spathi.graphics.missile.small" +#define SPATHI_BIG_MASK_PMAP_ANIM "ship.spathi.graphics.eluder.large" +#define SPATHI_CAPTAIN_MASK_PMAP_ANIM "ship.spathi.graphics.captain" +#define SPATHI_ICON_MASK_PMAP_ANIM "ship.spathi.icons" +#define SPATHI_MED_MASK_PMAP_ANIM "ship.spathi.graphics.eluder.medium" +#define SPATHI_MICON_MASK_PMAP_ANIM "ship.spathi.meleeicons" +#define SPATHI_RACE_STRINGS "ship.spathi.text" +#define SPATHI_SHIP_SOUNDS "ship.spathi.sounds" +#define SPATHI_SML_MASK_PMAP_ANIM "ship.spathi.graphics.eluder.small" +#define SPATHI_VICTORY_SONG "ship.spathi.ditty" diff --git a/src/uqm/ships/spathi/spathi.c b/src/uqm/ships/spathi/spathi.c new file mode 100644 index 0000000..aa4bd00 --- /dev/null +++ b/src/uqm/ships/spathi/spathi.c @@ -0,0 +1,301 @@ +//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 "spathi.h" +#include "resinst.h" + +// Core characteristics +#define MAX_CREW 30 +#define MAX_ENERGY 10 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 10 +#define MAX_THRUST 48 +#define THRUST_INCREMENT 12 +#define THRUST_WAIT 1 +#define TURN_WAIT 1 +#define SHIP_MASS 5 + +// Forward gun +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 0 +#define SPATHI_FORWARD_OFFSET 16 +#define MISSILE_SPEED DISPLAY_TO_WORLD (30) +#define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define MISSILE_OFFSET 1 +#define MISSILE_RANGE (MISSILE_SPEED * MISSILE_LIFE) + /* This is for the cyborg only. */ + +// B.U.T.T. +#define SPECIAL_ENERGY_COST 3 +#define SPECIAL_WAIT 7 +#define SPATHI_REAR_OFFSET 20 +#define DISCRIMINATOR_SPEED DISPLAY_TO_WORLD (8) +#define DISCRIMINATOR_LIFE 30 +#define DISCRIMINATOR_HITS 1 +#define DISCRIMINATOR_DAMAGE 2 +#define DISCRIMINATOR_OFFSET 4 +#define TRACK_WAIT 1 + +static RACE_DESC spathi_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | FIRES_AFT | SEEKING_SPECIAL | DONT_CHASE, + 18, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + SPATHI_RACE_STRINGS, + SPATHI_ICON_MASK_PMAP_ANIM, + SPATHI_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 1000 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 2549, 3600, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + SPATHI_BIG_MASK_PMAP_ANIM, + SPATHI_MED_MASK_PMAP_ANIM, + SPATHI_SML_MASK_PMAP_ANIM, + }, + { + MISSILE_BIG_MASK_PMAP_ANIM, + MISSILE_MED_MASK_PMAP_ANIM, + MISSILE_SML_MASK_PMAP_ANIM, + }, + { + DISCRIM_BIG_MASK_PMAP_ANIM, + DISCRIM_MED_MASK_PMAP_ANIM, + DISCRIM_SML_MASK_PMAP_ANIM, + }, + { + SPATHI_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + SPATHI_VICTORY_SONG, + SPATHI_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + MISSILE_RANGE, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +butt_missile_preprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->turn_wait > 0) + --ElementPtr->turn_wait; + else + { + COUNT facing; + + facing = GetFrameIndex (ElementPtr->next.image.frame); + if (TrackShip (ElementPtr, &facing) > 0) + { + ElementPtr->next.image.frame = + SetAbsFrameIndex (ElementPtr->next.image.frame, + facing); + ElementPtr->state_flags |= CHANGING; + + SetVelocityVector (&ElementPtr->velocity, + DISCRIMINATOR_SPEED, facing); + } + + ElementPtr->turn_wait = TRACK_WAIT; + } +} + +static void +spawn_butt_missile (ELEMENT *ShipPtr) +{ + HELEMENT ButtMissile; + STARSHIP *StarShipPtr; + MISSILE_BLOCK ButtMissileBlock; + + GetElementStarShip (ShipPtr, &StarShipPtr); + ButtMissileBlock.cx = ShipPtr->next.location.x; + ButtMissileBlock.cy = ShipPtr->next.location.y; + ButtMissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.special; + ButtMissileBlock.face = ButtMissileBlock.index = + NORMALIZE_FACING (StarShipPtr->ShipFacing + + ANGLE_TO_FACING (HALF_CIRCLE)); + ButtMissileBlock.sender = ShipPtr->playerNr; + ButtMissileBlock.flags = 0; + ButtMissileBlock.pixoffs = SPATHI_REAR_OFFSET; + ButtMissileBlock.speed = DISCRIMINATOR_SPEED; + ButtMissileBlock.hit_points = DISCRIMINATOR_HITS; + ButtMissileBlock.damage = DISCRIMINATOR_DAMAGE; + ButtMissileBlock.life = DISCRIMINATOR_LIFE; + ButtMissileBlock.preprocess_func = butt_missile_preprocess; + ButtMissileBlock.blast_offs = DISCRIMINATOR_OFFSET; + ButtMissile = initialize_missile (&ButtMissileBlock); + if (ButtMissile) + { + ELEMENT *ButtPtr; + + LockElement (ButtMissile, &ButtPtr); + ButtPtr->turn_wait = TRACK_WAIT; + SetElementStarShip (ButtPtr, StarShipPtr); + + ProcessSound (SetAbsSoundIndex ( + /* LAUNCH_BUTT_MISSILE */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ButtPtr); + + UnlockElement (ButtMissile); + PutElement (ButtMissile); + } +} + +static void +spathi_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + STARSHIP *StarShipPtr; + EVALUATE_DESC *lpEvalDesc; + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + GetElementStarShip (ShipPtr, &StarShipPtr); + StarShipPtr->ship_input_state &= ~SPECIAL; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (StarShipPtr->special_counter == 0 + && lpEvalDesc->ObjectPtr + && lpEvalDesc->which_turn <= 24) + { + COUNT travel_facing, direction_facing; + SIZE delta_x, delta_y; + + travel_facing = NORMALIZE_FACING ( + ANGLE_TO_FACING (GetVelocityTravelAngle (&ShipPtr->velocity) + + HALF_CIRCLE) + ); + delta_x = lpEvalDesc->ObjectPtr->current.location.x + - ShipPtr->current.location.x; + delta_y = lpEvalDesc->ObjectPtr->current.location.y + - ShipPtr->current.location.y; + direction_facing = NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) + ); + + if (NORMALIZE_FACING (direction_facing + - (StarShipPtr->ShipFacing + ANGLE_TO_FACING (HALF_CIRCLE)) + + ANGLE_TO_FACING (QUADRANT)) + <= ANGLE_TO_FACING (HALF_CIRCLE) + && (lpEvalDesc->which_turn <= 8 + || NORMALIZE_FACING (direction_facing + + ANGLE_TO_FACING (HALF_CIRCLE) + - ANGLE_TO_FACING (GetVelocityTravelAngle ( + &lpEvalDesc->ObjectPtr->velocity + )) + + ANGLE_TO_FACING (QUADRANT)) + <= ANGLE_TO_FACING (HALF_CIRCLE)) + && (!(StarShipPtr->cur_status_flags & + (SHIP_BEYOND_MAX_SPEED | SHIP_IN_GRAVITY_WELL)) + || NORMALIZE_FACING (direction_facing + - travel_facing + ANGLE_TO_FACING (QUADRANT)) + <= ANGLE_TO_FACING (HALF_CIRCLE))) + StarShipPtr->ship_input_state |= SPECIAL; + } +} + +static COUNT +initialize_standard_missile (ELEMENT *ShipPtr, HELEMENT MissileArray[]) +{ + 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; + MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = SPATHI_FORWARD_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); + + return (1); +} + +static void +spathi_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + spawn_butt_missile (ElementPtr); + + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } +} + +RACE_DESC* +init_spathi (void) +{ + RACE_DESC *RaceDescPtr; + + spathi_desc.postprocess_func = spathi_postprocess; + spathi_desc.init_weapon_func = initialize_standard_missile; + spathi_desc.cyborg_control.intelligence_func = spathi_intelligence; + + RaceDescPtr = &spathi_desc; + + return (RaceDescPtr); +} diff --git a/src/uqm/ships/spathi/spathi.h b/src/uqm/ships/spathi/spathi.h new file mode 100644 index 0000000..900d05c --- /dev/null +++ b/src/uqm/ships/spathi/spathi.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef SPATHI_H +#define SPATHI_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_spathi (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* SPATHI_H */ + diff --git a/src/uqm/ships/supox/Makeinfo b/src/uqm/ships/supox/Makeinfo new file mode 100644 index 0000000..9105cf6 --- /dev/null +++ b/src/uqm/ships/supox/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="supox.c" +uqm_HFILES="icode.h resinst.h supox.h" diff --git a/src/uqm/ships/supox/icode.h b/src/uqm/ships/supox/icode.h new file mode 100644 index 0000000..d2f82f9 --- /dev/null +++ b/src/uqm/ships/supox/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SUPOX_CODE "ship.supox.code" diff --git a/src/uqm/ships/supox/resinst.h b/src/uqm/ships/supox/resinst.h new file mode 100644 index 0000000..8984c6c --- /dev/null +++ b/src/uqm/ships/supox/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define GOB_BIG_MASK_PMAP_ANIM "ship.supox.graphics.glob.large" +#define GOB_MED_MASK_PMAP_ANIM "ship.supox.graphics.glob.medium" +#define GOB_SML_MASK_PMAP_ANIM "ship.supox.graphics.glob.small" +#define SUPOX_BIG_MASK_PMAP_ANIM "ship.supox.graphics.blade.large" +#define SUPOX_CAPTAIN_MASK_PMAP_ANIM "ship.supox.graphics.captain" +#define SUPOX_ICON_MASK_PMAP_ANIM "ship.supox.icons" +#define SUPOX_MED_MASK_PMAP_ANIM "ship.supox.graphics.blade.medium" +#define SUPOX_MICON_MASK_PMAP_ANIM "ship.supox.meleeicons" +#define SUPOX_RACE_STRINGS "ship.supox.text" +#define SUPOX_SHIP_SOUNDS "ship.supox.sounds" +#define SUPOX_SML_MASK_PMAP_ANIM "ship.supox.graphics.blade.small" +#define SUPOX_VICTORY_SONG "ship.supox.ditty" diff --git a/src/uqm/ships/supox/supox.c b/src/uqm/ships/supox/supox.c new file mode 100644 index 0000000..854c5b3 --- /dev/null +++ b/src/uqm/ships/supox/supox.c @@ -0,0 +1,288 @@ +//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 "supox.h" +#include "resinst.h" + +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 12 +#define MAX_ENERGY 16 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 4 +#define MAX_THRUST 40 +#define THRUST_INCREMENT 8 +#define THRUST_WAIT 0 +#define TURN_WAIT 1 +#define SHIP_MASS 4 + +// Gob launcher +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 2 +#define SUPOX_OFFSET 23 +#define MISSILE_OFFSET 2 +#define MISSILE_SPEED DISPLAY_TO_WORLD (30) +#define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 + +// Lateral/reverse thrust +#define SPECIAL_ENERGY_COST 1 + /* Unused - uncomment below to enable. */ +#define SPECIAL_WAIT 0 + /* Unused except to initialize supox_desc.special_wait */ + +static RACE_DESC supox_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 16, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + SUPOX_RACE_STRINGS, + SUPOX_ICON_MASK_PMAP_ANIM, + SUPOX_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 333 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 7468, 9246, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + SUPOX_BIG_MASK_PMAP_ANIM, + SUPOX_MED_MASK_PMAP_ANIM, + SUPOX_SML_MASK_PMAP_ANIM, + }, + { + GOB_BIG_MASK_PMAP_ANIM, + GOB_MED_MASK_PMAP_ANIM, + GOB_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + SUPOX_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + SUPOX_VICTORY_SONG, + SUPOX_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + (MISSILE_SPEED * MISSILE_LIFE) >> 1, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +supox_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + STARSHIP *StarShipPtr; + EVALUATE_DESC *lpEvalDesc; + + GetElementStarShip (ShipPtr, &StarShipPtr); + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (StarShipPtr->special_counter || lpEvalDesc->ObjectPtr == 0) + StarShipPtr->ship_input_state &= ~SPECIAL; + else + { + BOOLEAN LinedUp; + COUNT direction_angle; + SIZE delta_x, delta_y; + + delta_x = lpEvalDesc->ObjectPtr->next.location.x + - ShipPtr->next.location.x; + delta_y = lpEvalDesc->ObjectPtr->next.location.y + - ShipPtr->next.location.y; + direction_angle = ARCTAN (delta_x, delta_y); + + LinedUp = (BOOLEAN)(NORMALIZE_ANGLE (NORMALIZE_ANGLE (direction_angle + - FACING_TO_ANGLE (StarShipPtr->ShipFacing)) + + QUADRANT) <= HALF_CIRCLE); + + if (!LinedUp + || lpEvalDesc->which_turn > 20 + || NORMALIZE_ANGLE ( + lpEvalDesc->facing + - (FACING_TO_ANGLE (StarShipPtr->ShipFacing) + + HALF_CIRCLE) + OCTANT + ) > QUADRANT) + StarShipPtr->ship_input_state &= ~SPECIAL; + else if (LinedUp && lpEvalDesc->which_turn <= 12) + StarShipPtr->ship_input_state |= SPECIAL; + + if (StarShipPtr->ship_input_state & SPECIAL) + lpEvalDesc->MoveState = PURSUE; + } + + ship_intelligence (ShipPtr, + ObjectsOfConcern, ConcernCounter); + + if (StarShipPtr->ship_input_state & SPECIAL) + StarShipPtr->ship_input_state |= THRUST | WEAPON; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + if (StarShipPtr->special_counter == 0 + && lpEvalDesc->ObjectPtr + && lpEvalDesc->MoveState == AVOID + && ShipPtr->turn_wait == 0) + { + StarShipPtr->ship_input_state &= ~THRUST; + StarShipPtr->ship_input_state |= SPECIAL; + if (!(StarShipPtr->cur_status_flags & (LEFT | RIGHT))) + StarShipPtr->ship_input_state |= 1 << ((BYTE)TFB_Random () & 1); + else + StarShipPtr->ship_input_state |= + StarShipPtr->cur_status_flags & (LEFT | RIGHT); + } +} + +static COUNT +initialize_horn (ELEMENT *ShipPtr, HELEMENT HornArray[]) +{ + 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; + MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = SUPOX_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; + HornArray[0] = initialize_missile (&MissileBlock); + return (1); +} + +static void +supox_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) +/* + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST) +*/ + ) + { + SIZE add_facing; + + add_facing = 0; + if (StarShipPtr->cur_status_flags & THRUST) + { + if (ElementPtr->thrust_wait == 0) + ++ElementPtr->thrust_wait; + + add_facing = ANGLE_TO_FACING (HALF_CIRCLE); + } + if (StarShipPtr->cur_status_flags & LEFT) + { + if (ElementPtr->turn_wait == 0) + ++ElementPtr->turn_wait; + + if (add_facing) + add_facing += ANGLE_TO_FACING (OCTANT); + else + add_facing = -ANGLE_TO_FACING (QUADRANT); + } + else if (StarShipPtr->cur_status_flags & RIGHT) + { + if (ElementPtr->turn_wait == 0) + ++ElementPtr->turn_wait; + + if (add_facing) + add_facing -= ANGLE_TO_FACING (OCTANT); + else + add_facing = ANGLE_TO_FACING (QUADRANT); + } + + if (add_facing) + { + COUNT facing; + STATUS_FLAGS thrust_status; + + facing = StarShipPtr->ShipFacing; + StarShipPtr->ShipFacing = NORMALIZE_FACING ( + facing + add_facing + ); + thrust_status = inertial_thrust (ElementPtr); + StarShipPtr->cur_status_flags &= + ~(SHIP_AT_MAX_SPEED + | SHIP_BEYOND_MAX_SPEED + | SHIP_IN_GRAVITY_WELL); + StarShipPtr->cur_status_flags |= thrust_status; + StarShipPtr->ShipFacing = facing; + } + } +} + +RACE_DESC* +init_supox (void) +{ + RACE_DESC *RaceDescPtr; + + supox_desc.preprocess_func = supox_preprocess; + supox_desc.init_weapon_func = initialize_horn; + supox_desc.cyborg_control.intelligence_func = supox_intelligence; + + RaceDescPtr = &supox_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/supox/supox.h b/src/uqm/ships/supox/supox.h new file mode 100644 index 0000000..b066320 --- /dev/null +++ b/src/uqm/ships/supox/supox.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef SUPOX_H +#define SUPOX_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_supox (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* SUPOX_H */ + diff --git a/src/uqm/ships/syreen/Makeinfo b/src/uqm/ships/syreen/Makeinfo new file mode 100644 index 0000000..9485c78 --- /dev/null +++ b/src/uqm/ships/syreen/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="syreen.c" +uqm_HFILES="icode.h resinst.h syreen.h" diff --git a/src/uqm/ships/syreen/icode.h b/src/uqm/ships/syreen/icode.h new file mode 100644 index 0000000..66f3ca4 --- /dev/null +++ b/src/uqm/ships/syreen/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SYREEN_CODE "ship.syreen.code" diff --git a/src/uqm/ships/syreen/resinst.h b/src/uqm/ships/syreen/resinst.h new file mode 100644 index 0000000..7a7cc24 --- /dev/null +++ b/src/uqm/ships/syreen/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define DAGGER_BIG_MASK_PMAP_ANIM "ship.syreen.graphics.dagger.large" +#define DAGGER_MED_MASK_PMAP_ANIM "ship.syreen.graphics.dagger.medium" +#define DAGGER_SML_MASK_PMAP_ANIM "ship.syreen.graphics.dagger.small" +#define SYREEN_BIG_MASK_PMAP_ANIM "ship.syreen.graphics.penetrator.large" +#define SYREEN_CAPTAIN_MASK_PMAP_ANIM "ship.syreen.graphics.captain" +#define SYREEN_ICON_MASK_PMAP_ANIM "ship.syreen.icons" +#define SYREEN_MED_MASK_PMAP_ANIM "ship.syreen.graphics.penetrator.medium" +#define SYREEN_MICON_MASK_PMAP_ANIM "ship.syreen.meleeicons" +#define SYREEN_RACE_STRINGS "ship.syreen.text" +#define SYREEN_SHIP_SOUNDS "ship.syreen.sounds" +#define SYREEN_SML_MASK_PMAP_ANIM "ship.syreen.graphics.penetrator.small" +#define SYREEN_VICTORY_SONG "ship.syreen.ditty" diff --git a/src/uqm/ships/syreen/syreen.c b/src/uqm/ships/syreen/syreen.c new file mode 100644 index 0000000..c65ecd2 --- /dev/null +++ b/src/uqm/ships/syreen/syreen.c @@ -0,0 +1,284 @@ +//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 "syreen.h" +#include "resinst.h" + +#include "libs/mathlib.h" + +// Core characteristics +#define SYREEN_MAX_CREW_SIZE MAX_CREW_SIZE +#define MAX_CREW 12 +#define MAX_ENERGY 16 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 6 +#define MAX_THRUST /* DISPLAY_TO_WORLD (8) */ 36 +#define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 9 +#define THRUST_WAIT 1 +#define TURN_WAIT 1 +#define SHIP_MASS 2 + +// Particle Beam Stiletto +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 8 +#define SYREEN_OFFSET 30 +#define MISSILE_SPEED DISPLAY_TO_WORLD (30) +#define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 2 +#define MISSILE_OFFSET 3 + +// Syreen song +#define SPECIAL_ENERGY_COST 5 +#define SPECIAL_WAIT 20 +#define ABANDONER_RANGE 208 /* originally SPACE_HEIGHT */ +#define MAX_ABANDONERS 8 + +static RACE_DESC syreen_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 13, /* Super Melee cost */ + MAX_CREW, SYREEN_MAX_CREW_SIZE, + MAX_ENERGY, MAX_ENERGY, + SYREEN_RACE_STRINGS, + SYREEN_ICON_MASK_PMAP_ANIM, + SYREEN_MICON_MASK_PMAP_ANIM, + 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, + }, + { + { + SYREEN_BIG_MASK_PMAP_ANIM, + SYREEN_MED_MASK_PMAP_ANIM, + SYREEN_SML_MASK_PMAP_ANIM, + }, + { + DAGGER_BIG_MASK_PMAP_ANIM, + DAGGER_MED_MASK_PMAP_ANIM, + DAGGER_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + SYREEN_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + SYREEN_VICTORY_SONG, + SYREEN_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + (MISSILE_SPEED * MISSILE_LIFE * 2 / 3), + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static COUNT +initialize_dagger (ELEMENT *ShipPtr, HELEMENT DaggerArray[]) +{ + 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; + MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = SYREEN_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; + DaggerArray[0] = initialize_missile (&MissileBlock); + + return (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); + 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; + + 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 +syreen_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + EVALUATE_DESC *lpEvalDesc; + + ship_intelligence (ShipPtr, + ObjectsOfConcern, ConcernCounter); + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (lpEvalDesc->ObjectPtr != NULL) + { + STARSHIP *StarShipPtr; + STARSHIP *EnemyStarShipPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); + if (!(EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags & CREW_IMMUNE) + && StarShipPtr->special_counter == 0 + && lpEvalDesc->ObjectPtr->crew_level > 1 + && lpEvalDesc->which_turn <= 14) + StarShipPtr->ship_input_state |= SPECIAL; + else + StarShipPtr->ship_input_state &= ~SPECIAL; + } +} + +static void +syreen_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + ProcessSound (SetAbsSoundIndex ( + /* SYREEN_SONG */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + spawn_crew (ElementPtr); + + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } +} + +RACE_DESC* +init_syreen (void) +{ + RACE_DESC *RaceDescPtr; + + syreen_desc.postprocess_func = syreen_postprocess; + syreen_desc.init_weapon_func = initialize_dagger; + syreen_desc.cyborg_control.intelligence_func = syreen_intelligence; + + RaceDescPtr = &syreen_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/syreen/syreen.h b/src/uqm/ships/syreen/syreen.h new file mode 100644 index 0000000..1930a1a --- /dev/null +++ b/src/uqm/ships/syreen/syreen.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef SYREEN_H +#define SYREEN_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_syreen (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* SYREEN_H */ + diff --git a/src/uqm/ships/thradd/Makeinfo b/src/uqm/ships/thradd/Makeinfo new file mode 100644 index 0000000..f555509 --- /dev/null +++ b/src/uqm/ships/thradd/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="thradd.c" +uqm_HFILES="icode.h resinst.h thradd.h" diff --git a/src/uqm/ships/thradd/icode.h b/src/uqm/ships/thradd/icode.h new file mode 100644 index 0000000..070353a --- /dev/null +++ b/src/uqm/ships/thradd/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define THRADDASH_CODE "ship.thraddash.code" diff --git a/src/uqm/ships/thradd/resinst.h b/src/uqm/ships/thradd/resinst.h new file mode 100644 index 0000000..191d263 --- /dev/null +++ b/src/uqm/ships/thradd/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define HORN_BIG_MASK_PMAP_ANIM "ship.thraddash.graphics.horn.large" +#define HORN_MED_MASK_PMAP_ANIM "ship.thraddash.graphics.horn.medium" +#define HORN_SML_MASK_PMAP_ANIM "ship.thraddash.graphics.horn.small" +#define NAPALM_BIG_MASK_PMAP_ANIM "ship.thraddash.graphics.napalm.large" +#define NAPALM_MED_MASK_PMAP_ANIM "ship.thraddash.graphics.napalm.medium" +#define NAPALM_SML_MASK_PMAP_ANIM "ship.thraddash.graphics.napalm.small" +#define THRADDASH_BIG_MASK_PMAP_ANIM "ship.thraddash.graphics.torch.large" +#define THRADDASH_CAPTAIN_MASK_PMAP_ANIM "ship.thraddash.graphics.captain" +#define THRADDASH_ICON_MASK_PMAP_ANIM "ship.thraddash.icons" +#define THRADDASH_MED_MASK_PMAP_ANIM "ship.thraddash.graphics.torch.medium" +#define THRADDASH_MICON_MASK_PMAP_ANIM "ship.thraddash.meleeicons" +#define THRADDASH_RACE_STRINGS "ship.thraddash.text" +#define THRADDASH_SHIP_SOUNDS "ship.thraddash.sounds" +#define THRADDASH_SML_MASK_PMAP_ANIM "ship.thraddash.graphics.torch.small" +#define THRADDASH_VICTORY_SONG "ship.thraddash.ditty" diff --git a/src/uqm/ships/thradd/thradd.c b/src/uqm/ships/thradd/thradd.c new file mode 100644 index 0000000..0d7a8e2 --- /dev/null +++ b/src/uqm/ships/thradd/thradd.c @@ -0,0 +1,400 @@ +//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 "thradd.h" +#include "resinst.h" + +#include "uqm/globdata.h" + +// Core characteristics +#define MAX_CREW 8 +#define MAX_ENERGY 24 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 6 +#define MAX_THRUST 28 +#define THRUST_INCREMENT 7 +#define THRUST_WAIT 0 +#define TURN_WAIT 1 +#define SHIP_MASS 7 + +// Ion Blasters +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 12 +#define MISSILE_SPEED DISPLAY_TO_WORLD (30) +#define MISSILE_LIFE 15 +#define MISSILE_OFFSET 3 +#define THRADDASH_OFFSET 9 +#define MISSILE_HITS 2 +#define MISSILE_DAMAGE 1 + +// Afterburner +#define SPECIAL_ENERGY_COST 1 +#define SPECIAL_WAIT 0 +#define SPECIAL_THRUST_INCREMENT 12 +#define SPECIAL_MAX_THRUST 72 +#define NAPALM_LIFE 48 +#define NAPALM_OFFSET 0 +#define NAPALM_HITS 1 +#define NAPALM_DAMAGE 2 +#define NAPALM_DECAY_RATE 5 + /* Controls the speed of the afterburner "decay" animation; it will + * decay one step (one animation frame) per NAPALM_DECAY_RATE + * frames. */ +#define NUM_NAPALM_FADES 6 + + +static RACE_DESC thraddash_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 10, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + THRADDASH_RACE_STRINGS, + THRADDASH_ICON_MASK_PMAP_ANIM, + THRADDASH_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 833 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 2535, 8358, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + THRADDASH_BIG_MASK_PMAP_ANIM, + THRADDASH_MED_MASK_PMAP_ANIM, + THRADDASH_SML_MASK_PMAP_ANIM, + }, + { + HORN_BIG_MASK_PMAP_ANIM, + HORN_MED_MASK_PMAP_ANIM, + HORN_SML_MASK_PMAP_ANIM, + }, + { + NAPALM_BIG_MASK_PMAP_ANIM, + NAPALM_MED_MASK_PMAP_ANIM, + NAPALM_SML_MASK_PMAP_ANIM, + }, + { + THRADDASH_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + THRADDASH_VICTORY_SONG, + THRADDASH_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + (MISSILE_SPEED * MISSILE_LIFE) >> 1, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +thraddash_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + + STARSHIP *StarShipPtr; + EVALUATE_DESC *lpEvalDesc; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (lpEvalDesc->ObjectPtr) + { +#define STATIONARY_SPEED WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (4)) + SIZE dx, dy; + + GetCurrentVelocityComponents ( + &lpEvalDesc->ObjectPtr->velocity, &dx, &dy + ); + if (lpEvalDesc->which_turn > 8 + || (long)dx * dx + (long)dy * dy <= + (long)STATIONARY_SPEED * STATIONARY_SPEED) + lpEvalDesc->MoveState = PURSUE; + else + lpEvalDesc->MoveState = ENTICE; + } + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + GetElementStarShip (ShipPtr, &StarShipPtr); + if (StarShipPtr->special_counter == 0) + { + StarShipPtr->ship_input_state &= ~SPECIAL; + if (ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr + && ObjectsOfConcern[ENEMY_WEAPON_INDEX].MoveState == ENTICE) + { + if ((StarShipPtr->ship_input_state & THRUST) + || (ShipPtr->turn_wait == 0 + && !(StarShipPtr->ship_input_state & (LEFT | RIGHT))) + || NORMALIZE_FACING (ANGLE_TO_FACING ( + GetVelocityTravelAngle ( + &ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr->velocity + ) + HALF_CIRCLE + OCTANT) + - StarShipPtr->ShipFacing) > ANGLE_TO_FACING (QUADRANT)) + StarShipPtr->ship_input_state |= SPECIAL; + } + else if (lpEvalDesc->ObjectPtr) + { + if (lpEvalDesc->MoveState == PURSUE) + { + if (StarShipPtr->RaceDescPtr->ship_info.energy_level >= WEAPON_ENERGY_COST + + SPECIAL_ENERGY_COST + && ShipPtr->turn_wait == 0 + && !(StarShipPtr->ship_input_state & (LEFT | RIGHT)) + && (!(StarShipPtr->cur_status_flags & SPECIAL) + || !(StarShipPtr->cur_status_flags + & (SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED)))) + StarShipPtr->ship_input_state |= SPECIAL; + } + else if (lpEvalDesc->MoveState == ENTICE) + { + COUNT direction_angle; + SIZE delta_x, delta_y; + + delta_x = lpEvalDesc->ObjectPtr->next.location.x + - ShipPtr->next.location.x; + delta_y = lpEvalDesc->ObjectPtr->next.location.y + - ShipPtr->next.location.y; + direction_angle = ARCTAN (delta_x, delta_y); + + if ((lpEvalDesc->which_turn > 24 + && !(StarShipPtr->ship_input_state & (LEFT | RIGHT))) + || (lpEvalDesc->which_turn <= 16 + && NORMALIZE_ANGLE (direction_angle + - (FACING_TO_ANGLE (StarShipPtr->ShipFacing) + HALF_CIRCLE) + + QUADRANT) <= HALF_CIRCLE + && (lpEvalDesc->which_turn < 12 + || NORMALIZE_ANGLE (direction_angle + - (GetVelocityTravelAngle ( + &lpEvalDesc->ObjectPtr->velocity + ) + HALF_CIRCLE) + + (OCTANT + 2)) <= ((OCTANT + 2) << 1)))) + StarShipPtr->ship_input_state |= SPECIAL; + } + } + + if ((StarShipPtr->ship_input_state & SPECIAL) + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= + SPECIAL_ENERGY_COST) + StarShipPtr->ship_input_state &= ~THRUST; + } +} + +static void +flame_napalm_preprocess (ELEMENT *ElementPtr) +{ + ZeroVelocityComponents (&ElementPtr->velocity); + + if (ElementPtr->state_flags & NONSOLID) + { + ElementPtr->state_flags &= ~NONSOLID; + ElementPtr->state_flags |= APPEARING; + SetPrimType (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], + STAMP_PRIM); + + InitIntersectStartPoint (ElementPtr); + InitIntersectEndPoint (ElementPtr); + InitIntersectFrame (ElementPtr); + } + /* turn_wait is abused here to store the speed of the decay animation */ + else if (ElementPtr->turn_wait > 0) + --ElementPtr->turn_wait; + else + { + if (ElementPtr->life_span <= NUM_NAPALM_FADES * (NAPALM_DECAY_RATE + 1) + || GetFrameIndex ( + ElementPtr->current.image.frame + ) != NUM_NAPALM_FADES) + ElementPtr->next.image.frame = + DecFrameIndex (ElementPtr->current.image.frame); + else if (ElementPtr->life_span > NUM_NAPALM_FADES * (NAPALM_DECAY_RATE + 1)) + ElementPtr->next.image.frame = SetAbsFrameIndex ( + ElementPtr->current.image.frame, + GetFrameCount (ElementPtr->current.image.frame) - 1 + ); + + /* turn_wait is abused here to store the speed of the decay + * animation. */ + ElementPtr->turn_wait = NAPALM_DECAY_RATE; + ElementPtr->state_flags |= CHANGING; + } +} + +static COUNT +initialize_horn (ELEMENT *ShipPtr, HELEMENT HornArray[]) +{ + 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; + MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = THRADDASH_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; + HornArray[0] = initialize_missile (&MissileBlock); + + return (1); +} + +static void +thraddash_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (!(StarShipPtr->cur_status_flags & SPECIAL)) + { + if ((StarShipPtr->old_status_flags & SPECIAL) + && (StarShipPtr->cur_status_flags & SHIP_AT_MAX_SPEED)) + StarShipPtr->cur_status_flags |= SHIP_BEYOND_MAX_SPEED; + } + else if (DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + COUNT max_thrust, thrust_increment; + STATUS_FLAGS thrust_status; + HELEMENT hTrailElement; + + if (!(StarShipPtr->old_status_flags & SPECIAL)) + StarShipPtr->cur_status_flags &= + ~(SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED); + + if (ElementPtr->thrust_wait == 0) + ++ElementPtr->thrust_wait; + + thrust_increment = + StarShipPtr->RaceDescPtr->characteristics.thrust_increment; + max_thrust = StarShipPtr->RaceDescPtr->characteristics.max_thrust; + StarShipPtr->RaceDescPtr->characteristics.thrust_increment = + SPECIAL_THRUST_INCREMENT; + StarShipPtr->RaceDescPtr->characteristics.max_thrust = + SPECIAL_MAX_THRUST; + + thrust_status = inertial_thrust (ElementPtr); + StarShipPtr->cur_status_flags &= + ~(SHIP_AT_MAX_SPEED + | SHIP_BEYOND_MAX_SPEED + | SHIP_IN_GRAVITY_WELL); + StarShipPtr->cur_status_flags |= thrust_status; + + StarShipPtr->RaceDescPtr->characteristics.thrust_increment = + thrust_increment; + StarShipPtr->RaceDescPtr->characteristics.max_thrust = max_thrust; + + { + MISSILE_BLOCK MissileBlock; + + MissileBlock.cx = ElementPtr->next.location.x; + MissileBlock.cy = ElementPtr->next.location.y; + MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.special; + MissileBlock.face = 0; + MissileBlock.index = GetFrameCount ( + StarShipPtr->RaceDescPtr->ship_data.special[0] + ) - 1; + MissileBlock.sender = ElementPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = 0; + MissileBlock.speed = 0; + MissileBlock.hit_points = NAPALM_HITS; + MissileBlock.damage = NAPALM_DAMAGE; + MissileBlock.life = NAPALM_LIFE; + MissileBlock.preprocess_func = flame_napalm_preprocess; + MissileBlock.blast_offs = NAPALM_OFFSET; + + hTrailElement = initialize_missile (&MissileBlock); + if (hTrailElement) + { + ELEMENT *TrailElementPtr; + + LockElement (hTrailElement, &TrailElementPtr); + SetElementStarShip (TrailElementPtr, StarShipPtr); + TrailElementPtr->hTarget = 0; + + /* turn_wait is abused here to store the speed of the decay + * animation */ + TrailElementPtr->turn_wait = NAPALM_DECAY_RATE; + + TrailElementPtr->state_flags |= NONSOLID; + SetPrimType ( + &(GLOBAL (DisplayArray))[TrailElementPtr->PrimIndex], + NO_PRIM + ); + + /* normally done during preprocess, but because + * object is being inserted at head rather than + * appended after tail it may never get preprocessed. + */ + TrailElementPtr->next = TrailElementPtr->current; + TrailElementPtr->state_flags |= PRE_PROCESS; + + UnlockElement (hTrailElement); + InsertElement (hTrailElement, GetHeadElement ()); + + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + } + } + } +} + +RACE_DESC* +init_thraddash (void) +{ + RACE_DESC *RaceDescPtr; + + thraddash_desc.preprocess_func = thraddash_preprocess; + thraddash_desc.init_weapon_func = initialize_horn; + thraddash_desc.cyborg_control.intelligence_func = thraddash_intelligence; + + RaceDescPtr = &thraddash_desc; + + return (RaceDescPtr); +} diff --git a/src/uqm/ships/thradd/thradd.h b/src/uqm/ships/thradd/thradd.h new file mode 100644 index 0000000..fb2a542 --- /dev/null +++ b/src/uqm/ships/thradd/thradd.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef THRADD_H +#define THRADD_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_thraddash (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* THRADD_H */ + diff --git a/src/uqm/ships/umgah/Makeinfo b/src/uqm/ships/umgah/Makeinfo new file mode 100644 index 0000000..a66b4ce --- /dev/null +++ b/src/uqm/ships/umgah/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="umgah.c" +uqm_HFILES="icode.h resinst.h umgah.h" diff --git a/src/uqm/ships/umgah/icode.h b/src/uqm/ships/umgah/icode.h new file mode 100644 index 0000000..103f5d2 --- /dev/null +++ b/src/uqm/ships/umgah/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define UMGAH_CODE "ship.umgah.code" diff --git a/src/uqm/ships/umgah/resinst.h b/src/uqm/ships/umgah/resinst.h new file mode 100644 index 0000000..4df4b07 --- /dev/null +++ b/src/uqm/ships/umgah/resinst.h @@ -0,0 +1,17 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define CONE_BIG_MASK_ANIM "ship.umgah.graphics.cone.large" +#define CONE_MED_MASK_ANIM "ship.umgah.graphics.cone.medium" +#define CONE_SML_MASK_ANIM "ship.umgah.graphics.cone.small" +#define SPRITZ_MASK_PMAP_ANIM "ship.umgah.graphics.spritz" +#define UMGAH_BIG_MASK_PMAP_ANIM "ship.umgah.graphics.drone.large" +#define UMGAH_CAPTAIN_MASK_PMAP_ANIM "ship.umgah.graphics.captain" +#define UMGAH_ICON_MASK_PMAP_ANIM "ship.umgah.icons" +#define UMGAH_MED_MASK_PMAP_ANIM "ship.umgah.graphics.drone.medium" +#define UMGAH_MICON_MASK_PMAP_ANIM "ship.umgah.meleeicons" +#define UMGAH_RACE_STRINGS "ship.umgah.text" +#define UMGAH_SHIP_SOUNDS "ship.umgah.sounds" +#define UMGAH_SML_MASK_PMAP_ANIM "ship.umgah.graphics.drone.small" +#define UMGAH_VICTORY_SONG "ship.umgah.ditty" diff --git a/src/uqm/ships/umgah/umgah.c b/src/uqm/ships/umgah/umgah.c new file mode 100644 index 0000000..370ad40 --- /dev/null +++ b/src/uqm/ships/umgah/umgah.c @@ -0,0 +1,434 @@ +//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 "umgah.h" +#include "resinst.h" + +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 10 +#define MAX_ENERGY 30 +#define ENERGY_REGENERATION MAX_ENERGY +#define ENERGY_WAIT 150 +#define MAX_THRUST /* DISPLAY_TO_WORLD (5) */ 18 +#define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 6 +#define THRUST_WAIT 3 +#define TURN_WAIT 4 +#define SHIP_MASS 1 + +// Antimatter cone +#define WEAPON_ENERGY_COST 0 +#define WEAPON_WAIT 0 +#define UMGAH_OFFSET 0 +#define CONE_OFFSET 0 +#define CONE_SPEED 0 +#define CONE_HITS 100 +#define CONE_DAMAGE 1 +#define CONE_LIFE 1 + +// Retropropulsion +#define SPECIAL_ENERGY_COST 1 +#define SPECIAL_WAIT 2 +#define JUMP_DIST DISPLAY_TO_WORLD (40) + +static RACE_DESC umgah_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | IMMEDIATE_WEAPON, + 7, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + UMGAH_RACE_STRINGS, + UMGAH_ICON_MASK_PMAP_ANIM, + UMGAH_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 833 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 1798, 6000, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + UMGAH_BIG_MASK_PMAP_ANIM, + UMGAH_MED_MASK_PMAP_ANIM, + UMGAH_SML_MASK_PMAP_ANIM, + }, + { + SPRITZ_MASK_PMAP_ANIM, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + CONE_BIG_MASK_ANIM, + CONE_MED_MASK_ANIM, + CONE_SML_MASK_ANIM, + }, + { + UMGAH_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + UMGAH_VICTORY_SONG, + UMGAH_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + (LONG_RANGE_WEAPON << 2), + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + + +// Private per-instance ship data +typedef struct +{ + UWORD prevFacing; +} UMGAH_DATA; + +// Local typedef +typedef UMGAH_DATA CustomShipData_t; + +// Retrieve race-specific ship data from a race desc +static CustomShipData_t * +GetCustomShipData (RACE_DESC *pRaceDesc) +{ + return pRaceDesc->data; +} + +// Set the race-specific data in a race desc +// (Re)Allocates its own storage for the data. +static void +SetCustomShipData (RACE_DESC *pRaceDesc, const CustomShipData_t *data) +{ + if (pRaceDesc->data == data) + return; // no-op + + if (pRaceDesc->data) // Out with the old + { + HFree (pRaceDesc->data); + pRaceDesc->data = NULL; + } + + if (data) // In with the new + { + CustomShipData_t* newData = HMalloc (sizeof (*data)); + *newData = *data; + pRaceDesc->data = newData; + } +} + + +static void +cone_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + StarShipPtr->RaceDescPtr->ship_data.special[0] = + SetRelFrameIndex (StarShipPtr->RaceDescPtr->ship_data.special[0], + ANGLE_TO_FACING (FULL_CIRCLE)); + + ElementPtr->state_flags |= APPEARING; +} + +static void +cone_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + HELEMENT hBlastElement; + + hBlastElement = weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + if (hBlastElement) + { + RemoveElement (hBlastElement); + FreeElement (hBlastElement); + + ElementPtr0->state_flags &= ~DISAPPEARING; + } +} + +static void +umgah_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + EVALUATE_DESC *lpEvalDesc; + STARSHIP *StarShipPtr; + STARSHIP *EnemyStarShipPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + if (lpEvalDesc->ObjectPtr && lpEvalDesc->MoveState == ENTICE) + { + if (lpEvalDesc->which_turn > 3 + || (StarShipPtr->old_status_flags & SPECIAL)) + lpEvalDesc->ObjectPtr = 0; + else if ((lpEvalDesc->ObjectPtr->state_flags & FINITE_LIFE) + && !(lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT)) + lpEvalDesc->MoveState = AVOID; + else + lpEvalDesc->MoveState = PURSUE; + } + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (StarShipPtr->special_counter + || ObjectsOfConcern[GRAVITY_MASS_INDEX].ObjectPtr + || lpEvalDesc->ObjectPtr == 0) + { + StarShipPtr->RaceDescPtr->cyborg_control.WeaponRange = CLOSE_RANGE_WEAPON; + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + if (lpEvalDesc->which_turn < 16) + StarShipPtr->ship_input_state |= WEAPON; + StarShipPtr->ship_input_state &= ~SPECIAL; + } + else + { + BYTE this_turn; + SIZE delta_x, delta_y; + BOOLEAN EnemyBehind, EnoughJuice; + + if (lpEvalDesc->which_turn >= 0xFF + 1) + this_turn = 0xFF; + else + this_turn = (BYTE)lpEvalDesc->which_turn; + + EnoughJuice = (BOOLEAN)(WORLD_TO_TURN ( + JUMP_DIST * StarShipPtr->RaceDescPtr->ship_info.energy_level + / SPECIAL_ENERGY_COST + ) > this_turn); + delta_x = lpEvalDesc->ObjectPtr->next.location.x - + ShipPtr->next.location.x; + delta_y = lpEvalDesc->ObjectPtr->next.location.y - + ShipPtr->next.location.y; + EnemyBehind = (BOOLEAN)(NORMALIZE_ANGLE ( + ARCTAN (delta_x, delta_y) + - (FACING_TO_ANGLE (StarShipPtr->ShipFacing) + + HALF_CIRCLE) + (OCTANT + (OCTANT >> 2)) + ) <= ((OCTANT + (OCTANT >> 2)) << 1)); + + GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); + if (EnoughJuice + && ((StarShipPtr->old_status_flags & SPECIAL) + || EnemyBehind + || (this_turn > 6 + && MANEUVERABILITY ( + &EnemyStarShipPtr->RaceDescPtr->cyborg_control + ) <= SLOW_SHIP) + || (this_turn >= 16 && this_turn <= 24))) + StarShipPtr->RaceDescPtr->cyborg_control.WeaponRange = (LONG_RANGE_WEAPON << 3); + else + StarShipPtr->RaceDescPtr->cyborg_control.WeaponRange = CLOSE_RANGE_WEAPON; + + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + + if (StarShipPtr->RaceDescPtr->cyborg_control.WeaponRange == CLOSE_RANGE_WEAPON) + StarShipPtr->ship_input_state &= ~SPECIAL; + else + { + BOOLEAN LinedUp; + + StarShipPtr->ship_input_state &= ~THRUST; + LinedUp = (BOOLEAN)(ShipPtr->turn_wait == 0 + && !(StarShipPtr->old_status_flags & (LEFT | RIGHT))); + if (((StarShipPtr->old_status_flags & SPECIAL) + && this_turn <= StarShipPtr->RaceDescPtr->characteristics.special_wait) + || (!(StarShipPtr->old_status_flags & SPECIAL) + && EnemyBehind && (LinedUp || this_turn < 16))) + { + StarShipPtr->ship_input_state |= SPECIAL; + StarShipPtr->RaceDescPtr->characteristics.special_wait = this_turn; + + /* don't want him backing straight into ship */ + if (this_turn <= 8 && LinedUp) + { + if (TFB_Random () & 1) + StarShipPtr->ship_input_state |= LEFT; + else + StarShipPtr->ship_input_state |= RIGHT; + } + } + else if (StarShipPtr->old_status_flags & SPECIAL) + { + StarShipPtr->ship_input_state &= ~(SPECIAL | LEFT | RIGHT); + StarShipPtr->ship_input_state |= THRUST; + } + } + + if (this_turn < 16 && !EnemyBehind) + StarShipPtr->ship_input_state |= WEAPON; + } + + if (!(StarShipPtr->ship_input_state & SPECIAL)) + StarShipPtr->RaceDescPtr->characteristics.special_wait = 0xFF; +} + +static COUNT +initialize_cone (ELEMENT *ShipPtr, HELEMENT ConeArray[]) +{ + STARSHIP *StarShipPtr; + UMGAH_DATA* UmgahData; + MISSILE_BLOCK MissileBlock; + + GetElementStarShip (ShipPtr, &StarShipPtr); + MissileBlock.cx = ShipPtr->next.location.x; + MissileBlock.cy = ShipPtr->next.location.y; + MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.special; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = UMGAH_OFFSET; + MissileBlock.speed = CONE_SPEED; + MissileBlock.hit_points = CONE_HITS; + MissileBlock.damage = CONE_DAMAGE; + MissileBlock.life = CONE_LIFE; + MissileBlock.preprocess_func = cone_preprocess; + MissileBlock.blast_offs = CONE_OFFSET; + + // This func is called every frame while the player is holding down WEAPON + // Don't reset the cone FRAME to the first image every time + UmgahData = GetCustomShipData (StarShipPtr->RaceDescPtr); + if (!UmgahData || StarShipPtr->ShipFacing != UmgahData->prevFacing) + { + const UMGAH_DATA shipData = {StarShipPtr->ShipFacing}; + + SetCustomShipData (StarShipPtr->RaceDescPtr, &shipData); + + StarShipPtr->RaceDescPtr->ship_data.special[0] = + SetAbsFrameIndex ( + StarShipPtr->RaceDescPtr->ship_data.special[0], + StarShipPtr->ShipFacing); + } + + MissileBlock.index = GetFrameIndex (StarShipPtr->RaceDescPtr->ship_data.special[0]); + ConeArray[0] = initialize_missile (&MissileBlock); + + if (ConeArray[0]) + { + ELEMENT *ConePtr; + + LockElement (ConeArray[0], &ConePtr); + ConePtr->collision_func = cone_collision; + ConePtr->state_flags &= ~APPEARING; + ConePtr->next = ConePtr->current; + InitIntersectStartPoint (ConePtr); + InitIntersectEndPoint (ConePtr); + ConePtr->IntersectControl.IntersectStamp.frame = + StarShipPtr->RaceDescPtr->ship_data.special[0]; + UnlockElement (ConeArray[0]); + } + + return (1); +} + +static void +umgah_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (StarShipPtr->special_counter > 0) + { + StarShipPtr->special_counter = 0; + + ZeroVelocityComponents (&ElementPtr->velocity); + } +} + +static void +umgah_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + + if (ElementPtr->state_flags & APPEARING) + { + // Reset the value just in case + SetCustomShipData (StarShipPtr->RaceDescPtr, NULL); + } + else + { + if (ElementPtr->thrust_wait == 0 + && (StarShipPtr->cur_status_flags & SPECIAL) + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + COUNT facing; + + ProcessSound (SetAbsSoundIndex ( + /* ZIP_BACKWARDS */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + facing = FACING_TO_ANGLE (StarShipPtr->ShipFacing) + HALF_CIRCLE; + DeltaVelocityComponents (&ElementPtr->velocity, + COSINE (facing, WORLD_TO_VELOCITY (JUMP_DIST)), + SINE (facing, WORLD_TO_VELOCITY (JUMP_DIST))); + StarShipPtr->cur_status_flags &= + ~(SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED); + + StarShipPtr->special_counter = SPECIAL_WAIT; + } + } +} + +static void +uninit_umgah (RACE_DESC *pRaceDesc) +{ + SetCustomShipData (pRaceDesc, NULL); +} + +RACE_DESC* +init_umgah (void) +{ + RACE_DESC *RaceDescPtr; + + umgah_desc.uninit_func = uninit_umgah; + umgah_desc.preprocess_func = umgah_preprocess; + umgah_desc.postprocess_func = umgah_postprocess; + umgah_desc.init_weapon_func = initialize_cone; + umgah_desc.cyborg_control.intelligence_func = umgah_intelligence; + + RaceDescPtr = &umgah_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/umgah/umgah.h b/src/uqm/ships/umgah/umgah.h new file mode 100644 index 0000000..8c706bb --- /dev/null +++ b/src/uqm/ships/umgah/umgah.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef UMGAH_H +#define UMGAH_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_umgah (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* UMGAH_H */ + diff --git a/src/uqm/ships/urquan/Makeinfo b/src/uqm/ships/urquan/Makeinfo new file mode 100644 index 0000000..a1d130d --- /dev/null +++ b/src/uqm/ships/urquan/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="urquan.c" +uqm_HFILES="icode.h resinst.h urquan.h" diff --git a/src/uqm/ships/urquan/icode.h b/src/uqm/ships/urquan/icode.h new file mode 100644 index 0000000..b26e84a --- /dev/null +++ b/src/uqm/ships/urquan/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define URQUAN_CODE "ship.urquan.code" diff --git a/src/uqm/ships/urquan/resinst.h b/src/uqm/ships/urquan/resinst.h new file mode 100644 index 0000000..a7b9ecd --- /dev/null +++ b/src/uqm/ships/urquan/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define FIGHTER_BIG_MASK_PMAP_ANIM "ship.urquan.graphics.fighter.large" +#define FIGHTER_MED_MASK_PMAP_ANIM "ship.urquan.graphics.fighter.medium" +#define FIGHTER_SML_MASK_PMAP_ANIM "ship.urquan.graphics.fighter.small" +#define FUSION_BIG_MASK_PMAP_ANIM "ship.urquan.graphics.fusion.large" +#define FUSION_MED_MASK_PMAP_ANIM "ship.urquan.graphics.fusion.medium" +#define FUSION_SML_MASK_PMAP_ANIM "ship.urquan.graphics.fusion.small" +#define URQUAN_BIG_MASK_PMAP_ANIM "ship.urquan.graphics.dreadnought.large" +#define URQUAN_CAPTAIN_MASK_PMAP_ANIM "ship.urquan.graphics.captain" +#define URQUAN_ICON_MASK_PMAP_ANIM "ship.urquan.icons" +#define URQUAN_MED_MASK_PMAP_ANIM "ship.urquan.graphics.dreadnought.medium" +#define URQUAN_MICON_MASK_PMAP_ANIM "ship.urquan.meleeicons" +#define URQUAN_RACE_STRINGS "ship.urquan.text" +#define URQUAN_SHIP_SOUNDS "ship.urquan.sounds" +#define URQUAN_SML_MASK_PMAP_ANIM "ship.urquan.graphics.dreadnought.small" +#define URQUAN_VICTORY_SONG "ship.urquan.ditty" diff --git a/src/uqm/ships/urquan/urquan.c b/src/uqm/ships/urquan/urquan.c new file mode 100644 index 0000000..9df87d0 --- /dev/null +++ b/src/uqm/ships/urquan/urquan.c @@ -0,0 +1,554 @@ +//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 "urquan.h" +#include "resinst.h" + +#include "uqm/globdata.h" + +#include <stdlib.h> + +// Core characteristics +#define MAX_CREW MAX_CREW_SIZE +#define MAX_ENERGY MAX_ENERGY_SIZE +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 4 +#define MAX_THRUST 30 +#define THRUST_INCREMENT 6 +#define THRUST_WAIT 6 +#define TURN_WAIT 4 +#define SHIP_MASS 10 + +// Fusion blast +#define WEAPON_ENERGY_COST 6 +#define WEAPON_WAIT 6 +#define MISSILE_SPEED DISPLAY_TO_WORLD (20) +#define MISSILE_LIFE 20 +#define MISSILE_HITS 10 +#define MISSILE_DAMAGE 6 +#define MISSILE_OFFSET 8 +#define URQUAN_OFFSET 32 + +// Fighters +#define SPECIAL_ENERGY_COST 8 +#define SPECIAL_WAIT 9 +#define FIGHTER_OFFSET 4 +#define FIGHTER_SPEED DISPLAY_TO_WORLD (8) +#define ONE_WAY_FLIGHT 125 +#define TRACK_THRESHOLD 6 +#define FIGHTER_LIFE (ONE_WAY_FLIGHT + ONE_WAY_FLIGHT + 150) +#define FIGHTER_HITS 1 +#define FIGHTER_MASS 0 +#define FIGHTER_WEAPON_WAIT 8 +#define FIGHTER_LASER_RANGE DISPLAY_TO_WORLD (40 + FIGHTER_OFFSET) + +static RACE_DESC urquan_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | SEEKING_SPECIAL, + 30, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + URQUAN_RACE_STRINGS, + URQUAN_ICON_MASK_PMAP_ANIM, + URQUAN_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 2666 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 5750, 6000, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + URQUAN_BIG_MASK_PMAP_ANIM, + URQUAN_MED_MASK_PMAP_ANIM, + URQUAN_SML_MASK_PMAP_ANIM, + }, + { + FUSION_BIG_MASK_PMAP_ANIM, + FUSION_MED_MASK_PMAP_ANIM, + FUSION_SML_MASK_PMAP_ANIM, + }, + { + FIGHTER_BIG_MASK_PMAP_ANIM, + FIGHTER_MED_MASK_PMAP_ANIM, + FIGHTER_SML_MASK_PMAP_ANIM, + }, + { + URQUAN_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + URQUAN_VICTORY_SONG, + URQUAN_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 COUNT +initialize_fusion (ELEMENT *ShipPtr, HELEMENT FusionArray[]) +{ + 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; + MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = URQUAN_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; + FusionArray[0] = initialize_missile (&MissileBlock); + + return (1); +} + +static void +fighter_postprocess (ELEMENT *ElementPtr) +{ + HELEMENT Laser; + STARSHIP *StarShipPtr; + LASER_BLOCK LaserBlock; + + GetElementStarShip (ElementPtr, &StarShipPtr); + LaserBlock.cx = ElementPtr->next.location.x; + LaserBlock.cy = ElementPtr->next.location.y; + LaserBlock.face = ElementPtr->thrust_wait; + LaserBlock.ex = COSINE (FACING_TO_ANGLE (LaserBlock.face), FIGHTER_LASER_RANGE); + LaserBlock.ey = SINE (FACING_TO_ANGLE (LaserBlock.face), FIGHTER_LASER_RANGE); + LaserBlock.sender = ElementPtr->playerNr; + LaserBlock.flags = IGNORE_SIMILAR; + LaserBlock.pixoffs = FIGHTER_OFFSET; + LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x0A), 0x0E); + Laser = initialize_laser (&LaserBlock); + if (Laser) + { + ELEMENT *LaserPtr; + + LockElement (Laser, &LaserPtr); + SetElementStarShip (LaserPtr, StarShipPtr); + + ProcessSound (SetAbsSoundIndex ( + /* FIGHTER_ZAP */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), LaserPtr); + + UnlockElement (Laser); + PutElement (Laser); + } + + ElementPtr->postprocess_func = 0; + ElementPtr->thrust_wait = FIGHTER_WEAPON_WAIT; +} + +static void +fighter_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + + ++StarShipPtr->RaceDescPtr->characteristics.special_wait; + if (FIGHTER_LIFE - ElementPtr->life_span > TRACK_THRESHOLD + && !(ElementPtr->state_flags & CHANGING)) + { + BOOLEAN Enroute; + COUNT orig_facing, facing; + SIZE delta_x, delta_y; + ELEMENT *eptr; + + Enroute = TRUE; + + delta_x = StarShipPtr->RaceDescPtr->ship_info.crew_level; + delta_y = ElementPtr->life_span; + + orig_facing = facing = + GetFrameIndex (ElementPtr->current.image.frame); + if (((delta_y & 1) || ElementPtr->hTarget + || TrackShip (ElementPtr, &facing) >= 0) + && (delta_x == 0 || delta_y >= ONE_WAY_FLIGHT)) + ElementPtr->state_flags |= IGNORE_SIMILAR; + else if (delta_x) + { + LockElement (StarShipPtr->hShip, &eptr); + delta_x = eptr->current.location.x + - ElementPtr->current.location.x; + delta_y = eptr->current.location.y + - ElementPtr->current.location.y; + UnlockElement (StarShipPtr->hShip); + delta_x = WRAP_DELTA_X (delta_x); + delta_y = WRAP_DELTA_Y (delta_y); + facing = NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) + ); + +#ifdef NEVER + if (delta_x < 0) + delta_x = -delta_x; + if (delta_y < 0) + delta_y = -delta_y; + if (delta_x <= LASER_RANGE && delta_y <= LASER_RANGE) +#endif /* NEVER */ + ElementPtr->state_flags &= ~IGNORE_SIMILAR; + + Enroute = FALSE; + } + + if (ElementPtr->thrust_wait > 0) + --ElementPtr->thrust_wait; + + if (ElementPtr->hTarget) + { + LockElement (ElementPtr->hTarget, &eptr); + delta_x = eptr->current.location.x + - ElementPtr->current.location.x; + delta_y = eptr->current.location.y + - ElementPtr->current.location.y; + UnlockElement (ElementPtr->hTarget); + delta_x = WRAP_DELTA_X (delta_x); + delta_y = WRAP_DELTA_Y (delta_y); + + if (ElementPtr->thrust_wait == 0 + && abs (delta_x) < FIGHTER_LASER_RANGE * 3 / 4 + && abs (delta_y) < FIGHTER_LASER_RANGE * 3 / 4 + && delta_x * delta_x + delta_y * delta_y < + (FIGHTER_LASER_RANGE * 3 / 4) * (FIGHTER_LASER_RANGE * 3 / 4)) + { + ElementPtr->thrust_wait = + (BYTE)NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) + ); + ElementPtr->postprocess_func = fighter_postprocess; + } + + if (Enroute) + { + facing = GetFrameIndex (eptr->current.image.frame); + if (ElementPtr->turn_wait & LEFT) + { + delta_x += COSINE (FACING_TO_ANGLE (facing - 4), + DISPLAY_TO_WORLD (30)); + delta_y += SINE (FACING_TO_ANGLE (facing - 4), + DISPLAY_TO_WORLD (30)); + } + else + { + delta_x += COSINE (FACING_TO_ANGLE (facing + 4), + DISPLAY_TO_WORLD (30)); + delta_y += SINE (FACING_TO_ANGLE (facing + 4), + DISPLAY_TO_WORLD (30)); + } + facing = NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) + ); + } + } + ElementPtr->state_flags |= CHANGING; + + if (facing != orig_facing) + ElementPtr->next.image.frame = SetAbsFrameIndex ( + ElementPtr->next.image.frame, facing + ); + SetVelocityVector ( + &ElementPtr->velocity, FIGHTER_SPEED, facing + ); + } +} + +static void +fighter_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr0, &StarShipPtr); + if (GRAVITY_MASS (ElementPtr1->mass_points)) + { + HELEMENT hFighterElement; + + hFighterElement = AllocElement (); + if (hFighterElement) + { + COUNT primIndex, travel_facing; + SIZE delta_facing; + ELEMENT *FighterElementPtr; + + LockElement (hFighterElement, &FighterElementPtr); + primIndex = FighterElementPtr->PrimIndex; + *FighterElementPtr = *ElementPtr0; + FighterElementPtr->PrimIndex = primIndex; + (GLOBAL (DisplayArray))[primIndex] = + (GLOBAL (DisplayArray))[ElementPtr0->PrimIndex]; + FighterElementPtr->state_flags &= ~PRE_PROCESS; + FighterElementPtr->state_flags |= CHANGING; + FighterElementPtr->next = FighterElementPtr->current; + travel_facing = GetVelocityTravelAngle ( + &FighterElementPtr->velocity + ); + delta_facing = NORMALIZE_ANGLE ( + ARCTAN (pPt1->x - pPt0->x, pPt1->y - pPt0->y) + - travel_facing); + if (delta_facing == 0) + { + if (FighterElementPtr->turn_wait & LEFT) + travel_facing -= QUADRANT; + else + travel_facing += QUADRANT; + } + else if (delta_facing <= HALF_CIRCLE) + travel_facing -= QUADRANT; + else + travel_facing += QUADRANT; + + travel_facing = NORMALIZE_FACING (ANGLE_TO_FACING ( + NORMALIZE_ANGLE (travel_facing) + )); + FighterElementPtr->next.image.frame = + SetAbsFrameIndex (FighterElementPtr->next.image.frame, + travel_facing); + SetVelocityVector (&FighterElementPtr->velocity, + FIGHTER_SPEED, travel_facing); + UnlockElement (hFighterElement); + + PutElement (hFighterElement); + } + + ElementPtr0->state_flags |= DISAPPEARING | COLLISION; + } + else if (ElementPtr0->pParent != ElementPtr1->pParent) + { + ElementPtr0->blast_offset = 0; + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + ElementPtr0->state_flags |= DISAPPEARING | COLLISION; + } + else if (ElementPtr1->state_flags & PLAYER_SHIP) + { + ProcessSound (SetAbsSoundIndex ( + /* FIGHTERS_RETURN */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 3), ElementPtr1); + DeltaCrew (ElementPtr1, 1); + ElementPtr0->state_flags |= DISAPPEARING | COLLISION; + } + + if (ElementPtr0->state_flags & DISAPPEARING) + { + ElementPtr0->state_flags &= ~DISAPPEARING; + + ElementPtr0->hit_points = 0; + ElementPtr0->life_span = 0; + ElementPtr0->state_flags |= NONSOLID; + + --StarShipPtr->RaceDescPtr->characteristics.special_wait; + } +} + +static void +spawn_fighters (ELEMENT *ElementPtr) +{ + SIZE i; + COUNT facing; + SIZE delta_x, delta_y; + HELEMENT hFighterElement; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + facing = StarShipPtr->ShipFacing + ANGLE_TO_FACING (HALF_CIRCLE); + delta_x = COSINE (FACING_TO_ANGLE (facing), DISPLAY_TO_WORLD (14)); + delta_y = SINE (FACING_TO_ANGLE (facing), DISPLAY_TO_WORLD (14)); + + i = ElementPtr->crew_level > 2 ? 2 : 1; + while (i-- && (hFighterElement = AllocElement ())) + { + SIZE sx, sy; + COUNT fighter_facing; + ELEMENT *FighterElementPtr; + + DeltaCrew (ElementPtr, -1); + + PutElement (hFighterElement); + LockElement (hFighterElement, &FighterElementPtr); + FighterElementPtr->hit_points = FIGHTER_HITS; + FighterElementPtr->mass_points = FIGHTER_MASS; + FighterElementPtr->thrust_wait = TRACK_THRESHOLD + 1; + FighterElementPtr->playerNr = ElementPtr->playerNr; + FighterElementPtr->state_flags = APPEARING | FINITE_LIFE + | CREW_OBJECT | IGNORE_SIMILAR; + FighterElementPtr->life_span = FIGHTER_LIFE; + SetPrimType (&(GLOBAL (DisplayArray))[FighterElementPtr->PrimIndex], + STAMP_PRIM); + { + FighterElementPtr->preprocess_func = fighter_preprocess; + FighterElementPtr->postprocess_func = 0; + FighterElementPtr->collision_func = fighter_collision; + FighterElementPtr->death_func = NULL; + } + + FighterElementPtr->current.location = ElementPtr->next.location; + if (i == 1) + { + FighterElementPtr->turn_wait = LEFT; + fighter_facing = NORMALIZE_FACING (facing + 2); + FighterElementPtr->current.location.x += delta_x - delta_y; + FighterElementPtr->current.location.y += delta_y + delta_x; + } + else + { + FighterElementPtr->turn_wait = RIGHT; + fighter_facing = NORMALIZE_FACING (facing - 2); + FighterElementPtr->current.location.x += delta_x + delta_y; + FighterElementPtr->current.location.y += delta_y - delta_x; + } + sx = COSINE (FACING_TO_ANGLE (fighter_facing), + WORLD_TO_VELOCITY (FIGHTER_SPEED)); + sy = SINE (FACING_TO_ANGLE (fighter_facing), + WORLD_TO_VELOCITY (FIGHTER_SPEED)); + SetVelocityComponents (&FighterElementPtr->velocity, sx, sy); + FighterElementPtr->current.location.x -= VELOCITY_TO_WORLD (sx); + FighterElementPtr->current.location.y -= VELOCITY_TO_WORLD (sy); + + FighterElementPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; + FighterElementPtr->current.image.frame = + SetAbsFrameIndex (StarShipPtr->RaceDescPtr->ship_data.special[0], + fighter_facing); + SetElementStarShip (FighterElementPtr, StarShipPtr); + UnlockElement (hFighterElement); + } +} + +static void +urquan_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + EVALUATE_DESC *lpEvalDesc; + STARSHIP *StarShipPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + + ObjectsOfConcern[ENEMY_SHIP_INDEX].MoveState = PURSUE; + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + if (lpEvalDesc->ObjectPtr + && lpEvalDesc->MoveState == ENTICE + && (!(lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT) + || lpEvalDesc->which_turn <= 8) + && (!(lpEvalDesc->ObjectPtr->state_flags & FINITE_LIFE) + || (lpEvalDesc->ObjectPtr->mass_points >= 4 + && lpEvalDesc->which_turn == 2 + && ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn > 16))) + lpEvalDesc->MoveState = PURSUE; + + ship_intelligence (ShipPtr, + ObjectsOfConcern, ConcernCounter); + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + { + STARSHIP *EnemyStarShipPtr = NULL; + + if (lpEvalDesc->ObjectPtr) + GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); + if (StarShipPtr->special_counter == 0 + && lpEvalDesc->ObjectPtr + && StarShipPtr->RaceDescPtr->ship_info.crew_level > + (StarShipPtr->RaceDescPtr->ship_info.max_crew >> 2) + && !(EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags + & POINT_DEFENSE) + && (StarShipPtr->RaceDescPtr->characteristics.special_wait < 6 + || (MANEUVERABILITY ( + &EnemyStarShipPtr->RaceDescPtr->cyborg_control + ) <= SLOW_SHIP + && !(EnemyStarShipPtr->cur_status_flags & SHIP_BEYOND_MAX_SPEED)) + || (lpEvalDesc->which_turn <= 12 + && (StarShipPtr->ship_input_state & (LEFT | RIGHT)) + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= + (BYTE)(StarShipPtr->RaceDescPtr->ship_info.max_energy >> 1)))) + StarShipPtr->ship_input_state |= SPECIAL; + else + StarShipPtr->ship_input_state &= ~SPECIAL; + } + + StarShipPtr->RaceDescPtr->characteristics.special_wait = 0; +} + +static void +urquan_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && ElementPtr->crew_level > 1 + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + ProcessSound (SetAbsSoundIndex ( + /* LAUNCH_FIGHTERS */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + spawn_fighters (ElementPtr); + + StarShipPtr->special_counter = SPECIAL_WAIT; + } +} + +RACE_DESC* +init_urquan (void) +{ + RACE_DESC *RaceDescPtr; + + urquan_desc.postprocess_func = urquan_postprocess; + urquan_desc.init_weapon_func = initialize_fusion; + urquan_desc.cyborg_control.intelligence_func = urquan_intelligence; + + RaceDescPtr = &urquan_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/urquan/urquan.h b/src/uqm/ships/urquan/urquan.h new file mode 100644 index 0000000..937d93f --- /dev/null +++ b/src/uqm/ships/urquan/urquan.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef URQUAN_H +#define URQUAN_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_urquan (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* URQUAN_H */ + diff --git a/src/uqm/ships/utwig/Makeinfo b/src/uqm/ships/utwig/Makeinfo new file mode 100644 index 0000000..84b1d8c --- /dev/null +++ b/src/uqm/ships/utwig/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="utwig.c" +uqm_HFILES="icode.h resinst.h utwig.h" diff --git a/src/uqm/ships/utwig/icode.h b/src/uqm/ships/utwig/icode.h new file mode 100644 index 0000000..4762b89 --- /dev/null +++ b/src/uqm/ships/utwig/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define UTWIG_CODE "ship.utwig.code" diff --git a/src/uqm/ships/utwig/resinst.h b/src/uqm/ships/utwig/resinst.h new file mode 100644 index 0000000..384862e --- /dev/null +++ b/src/uqm/ships/utwig/resinst.h @@ -0,0 +1,16 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define LANCE_BIG_MASK_PMAP_ANIM "ship.utwig.graphics.lance.large" +#define LANCE_MED_MASK_PMAP_ANIM "ship.utwig.graphics.lance.medium" +#define LANCE_SML_MASK_PMAP_ANIM "ship.utwig.graphics.lance.small" +#define UTWIG_BIG_MASK_PMAP_ANIM "ship.utwig.graphics.jugger.large" +#define UTWIG_CAPTAIN_MASK_PMAP_ANIM "ship.utwig.graphics.captain" +#define UTWIG_ICON_MASK_PMAP_ANIM "ship.utwig.icons" +#define UTWIG_MED_MASK_PMAP_ANIM "ship.utwig.graphics.jugger.medium" +#define UTWIG_MICON_MASK_PMAP_ANIM "ship.utwig.meleeicons" +#define UTWIG_RACE_STRINGS "ship.utwig.text" +#define UTWIG_SHIP_SOUNDS "ship.utwig.sounds" +#define UTWIG_SML_MASK_PMAP_ANIM "ship.utwig.graphics.jugger.small" +#define UTWIG_VICTORY_SONG "ship.utwig.ditty" diff --git a/src/uqm/ships/utwig/utwig.c b/src/uqm/ships/utwig/utwig.c new file mode 100644 index 0000000..cb5f2fd --- /dev/null +++ b/src/uqm/ships/utwig/utwig.c @@ -0,0 +1,380 @@ +//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 "utwig.h" +#include "resinst.h" + +#include "uqm/globdata.h" +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 20 +#define MAX_ENERGY 20 +#define ENERGY_REGENERATION 0 +#define ENERGY_WAIT 255 +#define MAX_THRUST 36 +#define THRUST_INCREMENT 6 +#define THRUST_WAIT 6 +#define TURN_WAIT 1 +#define SHIP_MASS 8 + +// Weapon +#define WEAPON_ENERGY_COST 0 +#define WEAPON_WAIT 7 +#define UTWIG_OFFSET 9 +#define MISSILE_SPEED DISPLAY_TO_WORLD (30) +#define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define MISSILE_OFFSET 1 +#define LAUNCH_XOFFS0 DISPLAY_TO_WORLD (5) +#define LAUNCH_YOFFS0 -DISPLAY_TO_WORLD (18) +#define LAUNCH_XOFFS1 DISPLAY_TO_WORLD (13) +#define LAUNCH_YOFFS1 -DISPLAY_TO_WORLD (9) +#define LAUNCH_XOFFS2 DISPLAY_TO_WORLD (17) +#define LAUNCH_YOFFS2 -DISPLAY_TO_WORLD (4) + +// Shield +#define SPECIAL_ENERGY_COST 1 +#define SPECIAL_WAIT 12 + +static RACE_DESC utwig_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | POINT_DEFENSE | SHIELD_DEFENSE, + 22, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY >> 1, MAX_ENERGY, + UTWIG_RACE_STRINGS, + UTWIG_ICON_MASK_PMAP_ANIM, + UTWIG_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 666 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 8534, 8797, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + UTWIG_BIG_MASK_PMAP_ANIM, + UTWIG_MED_MASK_PMAP_ANIM, + UTWIG_SML_MASK_PMAP_ANIM, + }, + { + LANCE_BIG_MASK_PMAP_ANIM, + LANCE_MED_MASK_PMAP_ANIM, + LANCE_SML_MASK_PMAP_ANIM, + }, + { + NULL_RESOURCE, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + UTWIG_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + UTWIG_VICTORY_SONG, + UTWIG_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + CLOSE_RANGE_WEAPON, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static COUNT +initialize_lance (ELEMENT *ShipPtr, HELEMENT WeaponArray[]) +{ + COUNT i; + STARSHIP *StarShipPtr; + MISSILE_BLOCK MissileBlock; + + GetElementStarShip (ShipPtr, &StarShipPtr); + MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; + MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + 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; + MissileBlock.pixoffs = 0; + + for (i = 0; i < 3; ++i) + { + COUNT angle; + SIZE sin0 = 0, cos0 = 0; + SIZE sin1sin0, cos1sin0, cos1cos0, sin1cos0; + + switch (i) + { + case 0: + cos0 = LAUNCH_XOFFS0; + sin0 = LAUNCH_YOFFS0; + break; + case 1: + cos0 = LAUNCH_XOFFS1; + sin0 = LAUNCH_YOFFS1; + break; + case 2: + cos0 = LAUNCH_XOFFS2; + sin0 = LAUNCH_YOFFS2; + break; + } + angle = FACING_TO_ANGLE (MissileBlock.face) + QUADRANT; + cos1cos0 = COSINE (angle, cos0); + sin1sin0 = SINE (angle, sin0); + sin1cos0 = SINE (angle, cos0); + cos1sin0 = COSINE (angle, sin0); + + cos0 = cos1cos0 - sin1sin0; + sin0 = sin1cos0 + cos1sin0; + MissileBlock.cx = ShipPtr->next.location.x + cos0; + MissileBlock.cy = ShipPtr->next.location.y + sin0; + WeaponArray[(i << 1)] = initialize_missile (&MissileBlock); + + cos0 = -cos1cos0 - sin1sin0; + sin0 = -sin1cos0 + cos1sin0; + MissileBlock.cx = ShipPtr->next.location.x + cos0; + MissileBlock.cy = ShipPtr->next.location.y + sin0; + WeaponArray[(i << 1) + 1] = initialize_missile (&MissileBlock); + } + + return (6); +} + +static void +utwig_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + SIZE ShieldStatus; + STARSHIP *StarShipPtr; + EVALUATE_DESC *lpEvalDesc; + + GetElementStarShip (ShipPtr, &StarShipPtr); + + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + if (StarShipPtr->RaceDescPtr->ship_info.energy_level == 0) + ShieldStatus = 0; + else + { + ShieldStatus = -1; + if (lpEvalDesc->ObjectPtr && lpEvalDesc->MoveState == ENTICE) + { + ShieldStatus = 0; + if (!(lpEvalDesc->ObjectPtr->state_flags & FINITE_LIFE)) + lpEvalDesc->MoveState = PURSUE; + else if (lpEvalDesc->ObjectPtr->mass_points + || (lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT)) + { + if ((lpEvalDesc->which_turn >>= 1) == 0) + lpEvalDesc->which_turn = 1; + + if (lpEvalDesc->ObjectPtr->mass_points) + lpEvalDesc->ObjectPtr = 0; + else + lpEvalDesc->MoveState = PURSUE; + ShieldStatus = 1; + } + } + } + + if (StarShipPtr->special_counter == 0) + { + StarShipPtr->ship_input_state &= ~SPECIAL; + if (ShieldStatus) + { + if ((ShieldStatus > 0 || lpEvalDesc->ObjectPtr) + && lpEvalDesc->which_turn <= 2 + && (ShieldStatus > 0 + || (lpEvalDesc->ObjectPtr->state_flags + & PLAYER_SHIP) /* means IMMEDIATE WEAPON */ + || PlotIntercept (lpEvalDesc->ObjectPtr, + ShipPtr, 2, 0)) + && (TFB_Random () & 3)) + { + StarShipPtr->ship_input_state |= SPECIAL; + StarShipPtr->ship_input_state &= ~WEAPON; + } + + lpEvalDesc->ObjectPtr = 0; + } + } + + if (StarShipPtr->RaceDescPtr->ship_info.energy_level + && (lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX])->ObjectPtr) + { + STARSHIP *EnemyStarShipPtr; + + GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); + if (!(EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags + & IMMEDIATE_WEAPON)) + lpEvalDesc->MoveState = PURSUE; + } + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); +} + +static void +utwig_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + if (ElementPtr0->life_span > NORMAL_LIFE + && (ElementPtr1->state_flags & FINITE_LIFE) + && ElementPtr1->mass_points) + ElementPtr0->life_span += ElementPtr1->mass_points; + + collision (ElementPtr0, pPt0, ElementPtr1, pPt1); +} + +static void +utwig_preprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + PRIMITIVE *lpPrim; + + if (ElementPtr->state_flags & APPEARING) + { + ElementPtr->collision_func = utwig_collision; + } + + GetElementStarShip (ElementPtr, &StarShipPtr); + if (ElementPtr->life_span > (NORMAL_LIFE + 1)) + { + DeltaEnergy (ElementPtr, + ElementPtr->life_span - (NORMAL_LIFE + 1)); + + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), + ElementPtr); + } + + if (!(StarShipPtr->cur_status_flags & SPECIAL)) + StarShipPtr->special_counter = 0; + else if (StarShipPtr->special_counter % (SPECIAL_WAIT >> 1) == 0) + { + if (!DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + StarShipPtr->RaceDescPtr->ship_info.ship_flags &= + ~(POINT_DEFENSE | SHIELD_DEFENSE); + else if (StarShipPtr->special_counter == 0) + { + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + ProcessSound (SetAbsSoundIndex ( + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), + ElementPtr); + } + } + + lpPrim = &(GLOBAL (DisplayArray))[ElementPtr->PrimIndex]; + if (StarShipPtr->special_counter == 0) + { + // The shield is off. + SetPrimColor (lpPrim, + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1C, 0x00), 0x78)); + ElementPtr->colorCycleIndex = 0; + ElementPtr->life_span = NORMAL_LIFE; + SetPrimType (lpPrim, STAMP_PRIM); + } + else + { + // The shield is on. + + /* 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, + * but I am not sure that the old behavior was intended. - SvdB + */ + 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 colorTableCount = + sizeof colorTable / sizeof colorTable[0]; + + if (StarShipPtr->weapon_counter == 0) + ++StarShipPtr->weapon_counter; + + // colorCycleIndex is actually 1 higher than the entry in colorTable + // which is currently used, as it is 0 when the shield is off, + // and we don't want to skip over the first entry of the table. + ElementPtr->colorCycleIndex++; + if (ElementPtr->colorCycleIndex == colorTableCount + 1) + ElementPtr->colorCycleIndex = 1; + + SetPrimColor (lpPrim, colorTable[ElementPtr->colorCycleIndex - 1]); + + ElementPtr->life_span = NORMAL_LIFE + 1; + SetPrimType (lpPrim, STAMPFILL_PRIM); + } +} + +RACE_DESC* +init_utwig (void) +{ + RACE_DESC *RaceDescPtr; + + utwig_desc.preprocess_func = utwig_preprocess; + utwig_desc.init_weapon_func = initialize_lance; + utwig_desc.cyborg_control.intelligence_func = utwig_intelligence; + + RaceDescPtr = &utwig_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/utwig/utwig.h b/src/uqm/ships/utwig/utwig.h new file mode 100644 index 0000000..83ab97e --- /dev/null +++ b/src/uqm/ships/utwig/utwig.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef UTWIG_H +#define UTWIG_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_utwig (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* UTWIG_H */ + diff --git a/src/uqm/ships/vux/Makeinfo b/src/uqm/ships/vux/Makeinfo new file mode 100644 index 0000000..13c9264 --- /dev/null +++ b/src/uqm/ships/vux/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="vux.c" +uqm_HFILES="icode.h resinst.h vux.h" diff --git a/src/uqm/ships/vux/icode.h b/src/uqm/ships/vux/icode.h new file mode 100644 index 0000000..0bd37d7 --- /dev/null +++ b/src/uqm/ships/vux/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define VUX_CODE "ship.vux.code" diff --git a/src/uqm/ships/vux/resinst.h b/src/uqm/ships/vux/resinst.h new file mode 100644 index 0000000..c3e04bf --- /dev/null +++ b/src/uqm/ships/vux/resinst.h @@ -0,0 +1,17 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define LIMPETS_BIG_MASK_PMAP_ANIM "ship.vux.graphics.limpets.large" +#define LIMPETS_MED_MASK_PMAP_ANIM "ship.vux.graphics.limpets.medium" +#define LIMPETS_SML_MASK_PMAP_ANIM "ship.vux.graphics.limpets.small" +#define SLIME_MASK_PMAP_ANIM "ship.vux.graphics.slime" +#define VUX_BIG_MASK_PMAP_ANIM "ship.vux.graphics.intruder.large" +#define VUX_CAPTAIN_MASK_PMAP_ANIM "ship.vux.graphics.captain" +#define VUX_ICON_MASK_PMAP_ANIM "ship.vux.icons" +#define VUX_MED_MASK_PMAP_ANIM "ship.vux.graphics.intruder.medium" +#define VUX_MICON_MASK_PMAP_ANIM "ship.vux.meleeicons" +#define VUX_RACE_STRINGS "ship.vux.text" +#define VUX_SHIP_SOUNDS "ship.vux.sounds" +#define VUX_SML_MASK_PMAP_ANIM "ship.vux.graphics.intruder.small" +#define VUX_VICTORY_SONG "ship.vux.ditty" diff --git a/src/uqm/ships/vux/vux.c b/src/uqm/ships/vux/vux.c new file mode 100644 index 0000000..83e6c47 --- /dev/null +++ b/src/uqm/ships/vux/vux.c @@ -0,0 +1,398 @@ +//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 "vux.h" +#include "resinst.h" + +#include "uqm/globdata.h" +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 20 +#define MAX_ENERGY 40 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 8 +#define MAX_THRUST /* DISPLAY_TO_WORLD (5) */ 21 +#define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 7 +#define THRUST_WAIT 4 +#define TURN_WAIT 6 +#define SHIP_MASS 6 + +// Laser +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define VUX_OFFSET 12 +#define LASER_BASE 150 +#define LASER_RANGE DISPLAY_TO_WORLD (LASER_BASE + VUX_OFFSET) + +// Limpet +#define SPECIAL_ENERGY_COST 2 +#define SPECIAL_WAIT 7 +#define LIMPET_SPEED 25 +#define LIMPET_OFFSET 8 +#define LIMPET_LIFE 80 +#define LIMPET_HITS 1 +#define LIMPET_DAMAGE 0 +#define MIN_THRUST_INCREMENT DISPLAY_TO_WORLD (1) + +// Aggressive Entry +#define WARP_OFFSET 46 + /* How far outside of the laser range can the ship warp in. */ +#define MAXX_ENTRY_DIST DISPLAY_TO_WORLD ((LASER_BASE + VUX_OFFSET + WARP_OFFSET) << 1) +#define MAXY_ENTRY_DIST DISPLAY_TO_WORLD ((LASER_BASE + VUX_OFFSET + WARP_OFFSET) << 1) + /* Originally, the warp distance was: + * DISPLAY_TO_WORLD (SPACE_HEIGHT << 1) + * where SPACE_HEIGHT = SCREEN_HEIGHT - (SAFE_Y * 2) + * But in reality this should be relative to the laser-range. */ + +static RACE_DESC vux_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | SEEKING_SPECIAL | IMMEDIATE_WEAPON, + 12, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + VUX_RACE_STRINGS, + VUX_ICON_MASK_PMAP_ANIM, + VUX_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 900 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 4412, 1558, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + VUX_BIG_MASK_PMAP_ANIM, + VUX_MED_MASK_PMAP_ANIM, + VUX_SML_MASK_PMAP_ANIM, + }, + { + SLIME_MASK_PMAP_ANIM, + NULL_RESOURCE, + NULL_RESOURCE, + }, + { + LIMPETS_BIG_MASK_PMAP_ANIM, + LIMPETS_MED_MASK_PMAP_ANIM, + LIMPETS_SML_MASK_PMAP_ANIM, + }, + { + VUX_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + VUX_VICTORY_SONG, + VUX_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + CLOSE_RANGE_WEAPON, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + + +static void +limpet_preprocess (ELEMENT *ElementPtr) +{ + COUNT facing, orig_facing; + SIZE delta_facing; + + facing = orig_facing = NORMALIZE_FACING (ANGLE_TO_FACING ( + GetVelocityTravelAngle (&ElementPtr->velocity) + )); + if ((delta_facing = TrackShip (ElementPtr, &facing)) > 0) + { + facing = orig_facing + delta_facing; + SetVelocityVector (&ElementPtr->velocity, LIMPET_SPEED, facing); + } + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->next.image.frame); + + ElementPtr->state_flags |= CHANGING; +} + +static void +limpet_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + if (ElementPtr1->state_flags & PLAYER_SHIP) + { + STAMP s; + STARSHIP *StarShipPtr; + RACE_DESC *RDPtr; + + GetElementStarShip (ElementPtr1, &StarShipPtr); + RDPtr = StarShipPtr->RaceDescPtr; + + if (++RDPtr->characteristics.turn_wait == 0) + --RDPtr->characteristics.turn_wait; + if (++RDPtr->characteristics.thrust_wait == 0) + --RDPtr->characteristics.thrust_wait; + if (RDPtr->characteristics.thrust_increment <= MIN_THRUST_INCREMENT) + { + RDPtr->characteristics.max_thrust = + RDPtr->characteristics.thrust_increment << 1; + } + else + { + COUNT num_thrusts; + + num_thrusts = RDPtr->characteristics.max_thrust / + RDPtr->characteristics.thrust_increment; + --RDPtr->characteristics.thrust_increment; + RDPtr->characteristics.max_thrust = + RDPtr->characteristics.thrust_increment * num_thrusts; + } + RDPtr->cyborg_control.ManeuverabilityIndex = 0; + + GetElementStarShip (ElementPtr0, &StarShipPtr); + ProcessSound (SetAbsSoundIndex ( + /* LIMPET_AFFIXES */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), ElementPtr1); + s.frame = SetAbsFrameIndex ( + StarShipPtr->RaceDescPtr->ship_data.weapon[0], (COUNT)TFB_Random () + ); + ModifySilhouette (ElementPtr1, &s, MODIFY_IMAGE); + } + + ElementPtr0->hit_points = 0; + ElementPtr0->life_span = 0; + ElementPtr0->state_flags |= COLLISION | DISAPPEARING; + + (void) pPt0; /* Satisfying compiler (unused parameter) */ + (void) pPt1; /* Satisfying compiler (unused parameter) */ +} + +static void +spawn_limpets (ELEMENT *ElementPtr) +{ + HELEMENT Limpet; + STARSHIP *StarShipPtr; + MISSILE_BLOCK MissileBlock; + + GetElementStarShip (ElementPtr, &StarShipPtr); + MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.special; + MissileBlock.face = StarShipPtr->ShipFacing + HALF_CIRCLE; + MissileBlock.index = 0; + MissileBlock.sender = ElementPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = LIMPET_OFFSET; + MissileBlock.speed = LIMPET_SPEED; + MissileBlock.hit_points = LIMPET_HITS; + MissileBlock.damage = LIMPET_DAMAGE; + MissileBlock.life = LIMPET_LIFE; + MissileBlock.preprocess_func = limpet_preprocess; + MissileBlock.blast_offs = 0; + + MissileBlock.cx = ElementPtr->next.location.x; + MissileBlock.cy = ElementPtr->next.location.y; + Limpet = initialize_missile (&MissileBlock); + if (Limpet) + { + ELEMENT *LimpetPtr; + + LockElement (Limpet, &LimpetPtr); + LimpetPtr->collision_func = limpet_collision; + SetElementStarShip (LimpetPtr, StarShipPtr); + UnlockElement (Limpet); + + PutElement (Limpet); + } +} + +static COUNT +initialize_horrific_laser (ELEMENT *ShipPtr, HELEMENT LaserArray[]) +{ + STARSHIP *StarShipPtr; + LASER_BLOCK LaserBlock; + + GetElementStarShip (ShipPtr, &StarShipPtr); + LaserBlock.face = StarShipPtr->ShipFacing; + LaserBlock.cx = ShipPtr->next.location.x; + LaserBlock.cy = ShipPtr->next.location.y; + LaserBlock.ex = COSINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); + LaserBlock.ey = SINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); + LaserBlock.sender = ShipPtr->playerNr; + LaserBlock.flags = IGNORE_SIMILAR; + LaserBlock.pixoffs = VUX_OFFSET; + LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x0A, 0x1F, 0x0A), 0x0A); + LaserArray[0] = initialize_laser (&LaserBlock); + + return (1); +} + +static void +vux_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + EVALUATE_DESC *lpEvalDesc; + STARSHIP *StarShipPtr; + + lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + lpEvalDesc->MoveState = PURSUE; + if (ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr != 0 + && ObjectsOfConcern[ENEMY_WEAPON_INDEX].MoveState == ENTICE) + { + if ((ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr->state_flags + & FINITE_LIFE) + && !(ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr->state_flags + & CREW_OBJECT)) + ObjectsOfConcern[ENEMY_WEAPON_INDEX].MoveState = AVOID; + else + ObjectsOfConcern[ENEMY_WEAPON_INDEX].MoveState = PURSUE; + } + + ship_intelligence (ShipPtr, + ObjectsOfConcern, ConcernCounter); + + GetElementStarShip (ShipPtr, &StarShipPtr); + if (StarShipPtr->special_counter == 0 + && lpEvalDesc->ObjectPtr != 0 + && lpEvalDesc->which_turn <= 12 + && (StarShipPtr->ship_input_state & (LEFT | RIGHT)) + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= + (BYTE)(StarShipPtr->RaceDescPtr->ship_info.max_energy >> 1)) + StarShipPtr->ship_input_state |= SPECIAL; + else + StarShipPtr->ship_input_state &= ~SPECIAL; +} + +static void +vux_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + ProcessSound (SetAbsSoundIndex ( + /* LAUNCH_LIMPET */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + spawn_limpets (ElementPtr); + + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } +} + +static void +vux_preprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->state_flags & APPEARING) + { + COUNT facing; + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + facing = StarShipPtr->ShipFacing; + if (LOBYTE (GLOBAL (CurrentActivity)) != IN_ENCOUNTER + && TrackShip (ElementPtr, &facing) >= 0) + { + ELEMENT *OtherShipPtr; + + LockElement (ElementPtr->hTarget, &OtherShipPtr); + + do + { + SIZE dx, dy; + + ElementPtr->current.location.x = + (OtherShipPtr->current.location.x - + (MAXX_ENTRY_DIST >> 1)) + + ((COUNT)TFB_Random () % MAXX_ENTRY_DIST); + ElementPtr->current.location.y = + (OtherShipPtr->current.location.y - + (MAXY_ENTRY_DIST >> 1)) + + ((COUNT)TFB_Random () % MAXY_ENTRY_DIST); + dx = OtherShipPtr->current.location.x - + ElementPtr->current.location.x; + dy = OtherShipPtr->current.location.y - + ElementPtr->current.location.y; + facing = NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (dx, dy)) + ); + ElementPtr->current.image.frame = + SetAbsFrameIndex (ElementPtr->current.image.frame, + facing); + + ElementPtr->current.location.x = + WRAP_X (DISPLAY_ALIGN (ElementPtr->current.location.x)); + ElementPtr->current.location.y = + WRAP_Y (DISPLAY_ALIGN (ElementPtr->current.location.y)); + } while (CalculateGravity (ElementPtr) + || TimeSpaceMatterConflict (ElementPtr)); + + UnlockElement (ElementPtr->hTarget); + ElementPtr->hTarget = 0; + + ElementPtr->next = ElementPtr->current; + InitIntersectStartPoint (ElementPtr); + InitIntersectEndPoint (ElementPtr); + InitIntersectFrame (ElementPtr); + + StarShipPtr->ShipFacing = facing; + } + + StarShipPtr->RaceDescPtr->preprocess_func = 0; + } +} + +RACE_DESC* +init_vux (void) +{ + RACE_DESC *RaceDescPtr; + + vux_desc.preprocess_func = vux_preprocess; + vux_desc.postprocess_func = vux_postprocess; + vux_desc.init_weapon_func = initialize_horrific_laser; + vux_desc.cyborg_control.intelligence_func = vux_intelligence; + + RaceDescPtr = &vux_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/vux/vux.h b/src/uqm/ships/vux/vux.h new file mode 100644 index 0000000..3fa2f3f --- /dev/null +++ b/src/uqm/ships/vux/vux.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef VUX_H +#define VUX_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_vux (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* VUX_H */ + diff --git a/src/uqm/ships/yehat/Makeinfo b/src/uqm/ships/yehat/Makeinfo new file mode 100644 index 0000000..73d70c3 --- /dev/null +++ b/src/uqm/ships/yehat/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="yehat.c" +uqm_HFILES="icode.h resinst.h yehat.h" diff --git a/src/uqm/ships/yehat/icode.h b/src/uqm/ships/yehat/icode.h new file mode 100644 index 0000000..81cac0e --- /dev/null +++ b/src/uqm/ships/yehat/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define YEHAT_CODE "ship.yehat.code" diff --git a/src/uqm/ships/yehat/resinst.h b/src/uqm/ships/yehat/resinst.h new file mode 100644 index 0000000..ad325a5 --- /dev/null +++ b/src/uqm/ships/yehat/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SHIELD_BIG_MASK_ANIM "ship.yehat.graphics.shield.large" +#define SHIELD_MED_MASK_ANIM "ship.yehat.graphics.shield.medium" +#define SHIELD_SML_MASK_ANIM "ship.yehat.graphics.shield.small" +#define YEHAT_BIG_MASK_PMAP_ANIM "ship.yehat.graphics.terminator.large" +#define YEHAT_CANNON_BIG_MASK_PMAP_ANIM "ship.yehat.graphics.missile.large" +#define YEHAT_CANNON_MED_MASK_PMAP_ANIM "ship.yehat.graphics.missile.medium" +#define YEHAT_CANNON_SML_MASK_PMAP_ANIM "ship.yehat.graphics.missile.small" +#define YEHAT_CAPTAIN_MASK_PMAP_ANIM "ship.yehat.graphics.captain" +#define YEHAT_ICON_MASK_PMAP_ANIM "ship.yehat.icons" +#define YEHAT_MED_MASK_PMAP_ANIM "ship.yehat.graphics.terminator.medium" +#define YEHAT_MICON_MASK_PMAP_ANIM "ship.yehat.meleeicons" +#define YEHAT_RACE_STRINGS "ship.yehat.text" +#define YEHAT_SHIP_SOUNDS "ship.yehat.sounds" +#define YEHAT_SML_MASK_PMAP_ANIM "ship.yehat.graphics.terminator.small" +#define YEHAT_VICTORY_SONG "ship.yehat.ditty" diff --git a/src/uqm/ships/yehat/yehat.c b/src/uqm/ships/yehat/yehat.c new file mode 100644 index 0000000..f3d0fb8 --- /dev/null +++ b/src/uqm/ships/yehat/yehat.c @@ -0,0 +1,369 @@ +//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 "yehat.h" +#include "resinst.h" + +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 20 +#define MAX_ENERGY 10 +#define ENERGY_REGENERATION 2 +#define ENERGY_WAIT 6 +#define MAX_THRUST 30 +#define THRUST_INCREMENT 6 +#define THRUST_WAIT 2 +#define TURN_WAIT 2 +#define SHIP_MASS 3 + +// Twin Pulse Cannon +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define YEHAT_OFFSET 16 +#define LAUNCH_OFFS DISPLAY_TO_WORLD (8) +#define MISSILE_SPEED DISPLAY_TO_WORLD (20) +#define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define MISSILE_OFFSET 1 + +// Force Shield +#define SPECIAL_ENERGY_COST 3 +#define SPECIAL_WAIT 2 +#define SHIELD_LIFE 10 + +static RACE_DESC yehat_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE | SHIELD_DEFENSE, + 23, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + YEHAT_RACE_STRINGS, + YEHAT_ICON_MASK_PMAP_ANIM, + YEHAT_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 750 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 4970, 40, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + YEHAT_BIG_MASK_PMAP_ANIM, + YEHAT_MED_MASK_PMAP_ANIM, + YEHAT_SML_MASK_PMAP_ANIM, + }, + { + YEHAT_CANNON_BIG_MASK_PMAP_ANIM, + YEHAT_CANNON_MED_MASK_PMAP_ANIM, + YEHAT_CANNON_SML_MASK_PMAP_ANIM, + }, + { + SHIELD_BIG_MASK_ANIM, + SHIELD_MED_MASK_ANIM, + SHIELD_SML_MASK_ANIM, + }, + { + YEHAT_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + YEHAT_VICTORY_SONG, + YEHAT_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + MISSILE_SPEED * MISSILE_LIFE / 3, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static COUNT +initialize_standard_missiles (ELEMENT *ShipPtr, HELEMENT MissileArray[]) +{ + SIZE offs_x, offs_y; + STARSHIP *StarShipPtr; + MISSILE_BLOCK MissileBlock; + + GetElementStarShip (ShipPtr, &StarShipPtr); + MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; + MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = YEHAT_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; + + offs_x = -SINE (FACING_TO_ANGLE (MissileBlock.face), LAUNCH_OFFS); + offs_y = COSINE (FACING_TO_ANGLE (MissileBlock.face), LAUNCH_OFFS); + + MissileBlock.cx = ShipPtr->next.location.x + offs_x; + MissileBlock.cy = ShipPtr->next.location.y + offs_y; + MissileArray[0] = initialize_missile (&MissileBlock); + + MissileBlock.cx = ShipPtr->next.location.x - offs_x; + MissileBlock.cy = ShipPtr->next.location.y - offs_y; + MissileArray[1] = initialize_missile (&MissileBlock); + + return (2); +} + +static void +yehat_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + SIZE ShieldStatus; + STARSHIP *StarShipPtr; + EVALUATE_DESC *lpEvalDesc; + + ShieldStatus = -1; + lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; + if (lpEvalDesc->ObjectPtr && lpEvalDesc->MoveState == ENTICE) + { + ShieldStatus = 0; + if (!(lpEvalDesc->ObjectPtr->state_flags & (FINITE_LIFE | CREW_OBJECT))) + lpEvalDesc->MoveState = PURSUE; + else if (lpEvalDesc->ObjectPtr->mass_points + || (lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT)) + { + if (!(lpEvalDesc->ObjectPtr->state_flags & FINITE_LIFE)) + lpEvalDesc->which_turn <<= 1; + else + { + if ((lpEvalDesc->which_turn >>= 1) == 0) + lpEvalDesc->which_turn = 1; + + if (lpEvalDesc->ObjectPtr->mass_points) + lpEvalDesc->ObjectPtr = 0; + else + lpEvalDesc->MoveState = PURSUE; + } + ShieldStatus = 1; + } + } + + GetElementStarShip (ShipPtr, &StarShipPtr); + if (StarShipPtr->special_counter == 0) + { + StarShipPtr->ship_input_state &= ~SPECIAL; + if (ShieldStatus) + { + if (ShipPtr->life_span <= NORMAL_LIFE + 1 + && (ShieldStatus > 0 || lpEvalDesc->ObjectPtr) + && lpEvalDesc->which_turn <= 2 + && (ShieldStatus > 0 + || (lpEvalDesc->ObjectPtr->state_flags + & PLAYER_SHIP) /* means IMMEDIATE WEAPON */ + || PlotIntercept (lpEvalDesc->ObjectPtr, + ShipPtr, 2, 0)) + && (TFB_Random () & 3)) + StarShipPtr->ship_input_state |= SPECIAL; + + if (lpEvalDesc->ObjectPtr + && !(lpEvalDesc->ObjectPtr->state_flags & CREW_OBJECT)) + lpEvalDesc->ObjectPtr = 0; + } + } + + if ((lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX])->ObjectPtr) + { + STARSHIP *EnemyStarShipPtr; + + GetElementStarShip (lpEvalDesc->ObjectPtr, &EnemyStarShipPtr); + if (!(EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags + & IMMEDIATE_WEAPON)) + lpEvalDesc->MoveState = PURSUE; + } + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); +/* + if (StarShipPtr->RaceDescPtr->ship_info.energy_level <= SPECIAL_ENERGY_COST) + StarShipPtr->ship_input_state &= ~WEAPON; +*/ +} + +static void +yehat_postprocess (ELEMENT *ElementPtr) +{ + if (!(ElementPtr->state_flags & NONSOLID)) + { + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + /* take care of shield effect */ + if (StarShipPtr->special_counter > 0) + { + if (ElementPtr->life_span == NORMAL_LIFE) + StarShipPtr->special_counter = 0; + else + { +#ifdef OLD + SetPrimColor ( + &(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], + BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F) + ); + SetPrimType ( + &(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], + STAMPFILL_PRIM + ); +#endif /* OLD */ + + ProcessSound (SetAbsSoundIndex ( + /* YEHAT_SHIELD_ON */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST); + } + } + +#ifdef OLD + if (ElementPtr->life_span > NORMAL_LIFE) + { + HELEMENT hShipElement; + + if (hShipElement = AllocElement ()) + { + ELEMENT *ShipElementPtr; + + InsertElement (hShipElement, GetSuccElement (ElementPtr)); + LockElement (hShipElement, &ShipElementPtr); + ShipElementPtr->playerNr = ElementPtr->playerNr; + ShipElementPtr->state_flags = + /* in place of APPEARING */ + (CHANGING | PRE_PROCESS | POST_PROCESS) + | FINITE_LIFE | NONSOLID; + SetPrimType ( + &(GLOBAL (DisplayArray))[ShipElementPtr->PrimIndex], + STAMP_PRIM + ); + + ShipElementPtr->life_span = 0; /* because preprocessing + * will not be done + */ + ShipElementPtr->current.location = ElementPtr->next.location; + ShipElementPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.ship; + ShipElementPtr->current.image.frame = + SetAbsFrameIndex (StarShipPtr->RaceDescPtr->ship_data.ship[0], + StarShipPtr->ShipFacing); + ShipElementPtr->next = ShipElementPtr->current; + ShipElementPtr->preprocess_func = + ShipElementPtr->postprocess_func = + ShipElementPtr->death_func = NULL; + ZeroVelocityComponents (&ShipElementPtr->velocity); + + UnlockElement (hShipElement); + } + } +#endif /* OLD */ + } +} + +static void +yehat_preprocess (ELEMENT *ElementPtr) +{ + if (!(ElementPtr->state_flags & APPEARING)) + { + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((ElementPtr->life_span > NORMAL_LIFE + /* take care of shield effect */ + && --ElementPtr->life_span == NORMAL_LIFE) + || (ElementPtr->life_span == NORMAL_LIFE + && ElementPtr->next.image.farray + == StarShipPtr->RaceDescPtr->ship_data.special)) + { +#ifdef NEVER + SetPrimType ( + &(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], + STAMP_PRIM + ); +#endif /* NEVER */ + + ElementPtr->next.image.farray = StarShipPtr->RaceDescPtr->ship_data.ship; + ElementPtr->next.image.frame = + SetEquFrameIndex (StarShipPtr->RaceDescPtr->ship_data.ship[0], + ElementPtr->next.image.frame); + ElementPtr->state_flags |= CHANGING; + } + + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0) + { + if (StarShipPtr->RaceDescPtr->ship_info.energy_level < SPECIAL_ENERGY_COST) + DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST); /* so text will flash */ + else + { + ElementPtr->life_span = SHIELD_LIFE + NORMAL_LIFE; + + ElementPtr->next.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; + ElementPtr->next.image.frame = + SetEquFrameIndex (StarShipPtr->RaceDescPtr->ship_data.special[0], + ElementPtr->next.image.frame); + ElementPtr->state_flags |= CHANGING; + + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } + } + } +} + +RACE_DESC* +init_yehat (void) +{ + RACE_DESC *RaceDescPtr; + + yehat_desc.preprocess_func = yehat_preprocess; + yehat_desc.postprocess_func = yehat_postprocess; + yehat_desc.init_weapon_func = initialize_standard_missiles; + yehat_desc.cyborg_control.intelligence_func = yehat_intelligence; + + RaceDescPtr = &yehat_desc; + + return (RaceDescPtr); +} diff --git a/src/uqm/ships/yehat/yehat.h b/src/uqm/ships/yehat/yehat.h new file mode 100644 index 0000000..8b3dd5a --- /dev/null +++ b/src/uqm/ships/yehat/yehat.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef YEHAT_H +#define YEHAT_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_yehat (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* YEHAT_H */ + diff --git a/src/uqm/ships/zoqfot/Makeinfo b/src/uqm/ships/zoqfot/Makeinfo new file mode 100644 index 0000000..e795e78 --- /dev/null +++ b/src/uqm/ships/zoqfot/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="zoqfot.c" +uqm_HFILES="icode.h resinst.h zoqfot.h" diff --git a/src/uqm/ships/zoqfot/icode.h b/src/uqm/ships/zoqfot/icode.h new file mode 100644 index 0000000..0fe635f --- /dev/null +++ b/src/uqm/ships/zoqfot/icode.h @@ -0,0 +1,5 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define ZOQFOTPIK_CODE "ship.zoqfotpik.code" diff --git a/src/uqm/ships/zoqfot/resinst.h b/src/uqm/ships/zoqfot/resinst.h new file mode 100644 index 0000000..5939142 --- /dev/null +++ b/src/uqm/ships/zoqfot/resinst.h @@ -0,0 +1,19 @@ +/* This file was auto-generated by the gen_resfiles utility and + should not be edited directly. Modify the master resource list + instead and regenerate. */ + +#define SPIT_BIG_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.spit.large" +#define SPIT_MED_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.spit.medium" +#define SPIT_SML_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.spit.small" +#define STINGER_BIG_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.proboscis.large" +#define STINGER_MED_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.proboscis.medium" +#define STINGER_SML_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.proboscis.small" +#define ZOQFOTPIK_BIG_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.stinger.large" +#define ZOQFOTPIK_CAPTAIN_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.captain" +#define ZOQFOTPIK_ICON_MASK_PMAP_ANIM "ship.zoqfotpik.icons" +#define ZOQFOTPIK_MED_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.stinger.medium" +#define ZOQFOTPIK_MICON_MASK_PMAP_ANIM "ship.zoqfotpik.meleeicons" +#define ZOQFOTPIK_RACE_STRINGS "ship.zoqfotpik.text" +#define ZOQFOTPIK_SHIP_SOUNDS "ship.zoqfotpik.sounds" +#define ZOQFOTPIK_SML_MASK_PMAP_ANIM "ship.zoqfotpik.graphics.stinger.small" +#define ZOQFOTPIK_VICTORY_SONG "ship.zoqfotpik.ditty" diff --git a/src/uqm/ships/zoqfot/zoqfot.c b/src/uqm/ships/zoqfot/zoqfot.c new file mode 100644 index 0000000..15a6024 --- /dev/null +++ b/src/uqm/ships/zoqfot/zoqfot.c @@ -0,0 +1,377 @@ +//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 "zoqfot.h" +#include "resinst.h" + +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 10 +#define MAX_ENERGY 10 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 4 +#define MAX_THRUST 40 +#define THRUST_INCREMENT 10 +#define THRUST_WAIT 0 +#define TURN_WAIT 1 +#define SHIP_MASS 5 + +// Main weapon +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define ZOQFOTPIK_OFFSET 13 +#define MISSILE_OFFSET 0 +#define MISSILE_SPEED DISPLAY_TO_WORLD (10) + /* Used by the cyborg only. */ +#define MISSILE_LIFE 10 +#define MISSILE_RANGE (MISSILE_SPEED * MISSILE_LIFE) +#define MISSILE_DAMAGE 1 +#define MISSILE_HITS 1 +#define SPIT_WAIT 2 + /* Controls the main weapon color change animation's speed. + * The animation advances one frame every SPIT_WAIT frames. */ + +// Tongue +#define SPECIAL_ENERGY_COST (MAX_ENERGY * 3 / 4) +#define SPECIAL_WAIT 6 +#define TONGUE_SPEED 0 +#define TONGUE_HITS 1 +#define TONGUE_DAMAGE 12 +#define TONGUE_OFFSET 4 + +static RACE_DESC zoqfotpik_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 6, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + ZOQFOTPIK_RACE_STRINGS, + ZOQFOTPIK_ICON_MASK_PMAP_ANIM, + ZOQFOTPIK_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 320 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 3761, 5333, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + ZOQFOTPIK_BIG_MASK_PMAP_ANIM, + ZOQFOTPIK_MED_MASK_PMAP_ANIM, + ZOQFOTPIK_SML_MASK_PMAP_ANIM, + }, + { + SPIT_BIG_MASK_PMAP_ANIM, + SPIT_MED_MASK_PMAP_ANIM, + SPIT_SML_MASK_PMAP_ANIM, + }, + { + STINGER_BIG_MASK_PMAP_ANIM, + STINGER_MED_MASK_PMAP_ANIM, + STINGER_SML_MASK_PMAP_ANIM, + }, + { + ZOQFOTPIK_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + ZOQFOTPIK_VICTORY_SONG, + ZOQFOTPIK_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + MISSILE_RANGE, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +spit_preprocess (ELEMENT *ElementPtr) +{ + /* turn_wait is abused here to control the animation speed. */ + if (ElementPtr->turn_wait > 0) + --ElementPtr->turn_wait; + else + { + COUNT index, angle, speed; + + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->next.image.frame); + angle = GetVelocityTravelAngle (&ElementPtr->velocity); + if ((index = GetFrameIndex (ElementPtr->next.image.frame)) == 1) + angle = angle + (((COUNT)TFB_Random () % 3) - 1); + + speed = WORLD_TO_VELOCITY (DISPLAY_TO_WORLD ( + GetFrameCount (ElementPtr->next.image.frame) - index) << 1); + SetVelocityComponents (&ElementPtr->velocity, + (SIZE)COSINE (angle, speed), + (SIZE)SINE (angle, speed)); + + /* turn_wait is abused here to control the animation speed. */ + ElementPtr->turn_wait = SPIT_WAIT; + ElementPtr->state_flags |= CHANGING; + } +} + +static COUNT +initialize_spit (ELEMENT *ShipPtr, HELEMENT SpitArray[]) +{ + 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; + MissileBlock.face = StarShipPtr->ShipFacing; + MissileBlock.index = 0; + MissileBlock.sender = ShipPtr->playerNr; + MissileBlock.flags = IGNORE_SIMILAR; + MissileBlock.pixoffs = ZOQFOTPIK_OFFSET; + MissileBlock.speed = DISPLAY_TO_WORLD ( + GetFrameCount (StarShipPtr->RaceDescPtr->ship_data.weapon[0])) << 1; + MissileBlock.hit_points = MISSILE_HITS; + MissileBlock.damage = MISSILE_DAMAGE; + MissileBlock.life = MISSILE_LIFE; + MissileBlock.preprocess_func = spit_preprocess; + MissileBlock.blast_offs = MISSILE_OFFSET; + SpitArray[0] = initialize_missile (&MissileBlock); + + return (1); +} + +static void spawn_tongue (ELEMENT *ElementPtr); + +static void +tongue_postprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->turn_wait) + spawn_tongue (ElementPtr); +} + +static void +tongue_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr0, &StarShipPtr); + if (StarShipPtr->special_counter == + StarShipPtr->RaceDescPtr->characteristics.special_wait) + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + + StarShipPtr->special_counter -= ElementPtr0->turn_wait; + ElementPtr0->turn_wait = 0; + ElementPtr0->state_flags |= NONSOLID; +} + +static void +spawn_tongue (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + MISSILE_BLOCK TongueBlock; + HELEMENT Tongue; + + GetElementStarShip (ElementPtr, &StarShipPtr); + TongueBlock.cx = ElementPtr->next.location.x; + TongueBlock.cy = ElementPtr->next.location.y; + TongueBlock.farray = StarShipPtr->RaceDescPtr->ship_data.special; + TongueBlock.face = TongueBlock.index = StarShipPtr->ShipFacing; + TongueBlock.sender = ElementPtr->playerNr; + TongueBlock.flags = IGNORE_SIMILAR; + TongueBlock.pixoffs = 0; + TongueBlock.speed = TONGUE_SPEED; + TongueBlock.hit_points = TONGUE_HITS; + TongueBlock.damage = TONGUE_DAMAGE; + TongueBlock.life = 1; + TongueBlock.preprocess_func = 0; + TongueBlock.blast_offs = TONGUE_OFFSET; + Tongue = initialize_missile (&TongueBlock); + if (Tongue) + { + ELEMENT *TonguePtr; + + LockElement (Tongue, &TonguePtr); + TonguePtr->postprocess_func = tongue_postprocess; + TonguePtr->collision_func = tongue_collision; + if (ElementPtr->state_flags & PLAYER_SHIP) + TonguePtr->turn_wait = StarShipPtr->special_counter; + else + { + COUNT angle; + RECT r; + SIZE x_offs, y_offs; + + TonguePtr->turn_wait = ElementPtr->turn_wait - 1; + + GetFrameRect (TonguePtr->current.image.frame, &r); + x_offs = DISPLAY_TO_WORLD (r.extent.width >> 1); + y_offs = DISPLAY_TO_WORLD (r.extent.height >> 1); + + angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); + if (angle > HALF_CIRCLE && angle < FULL_CIRCLE) + TonguePtr->current.location.x -= x_offs; + else if (angle > 0 && angle < HALF_CIRCLE) + TonguePtr->current.location.x += x_offs; + if (angle < QUADRANT || angle > FULL_CIRCLE - QUADRANT) + TonguePtr->current.location.y -= y_offs; + else if (angle > QUADRANT && angle < FULL_CIRCLE - QUADRANT) + TonguePtr->current.location.y += y_offs; + } + + SetElementStarShip (TonguePtr, StarShipPtr); + UnlockElement (Tongue); + PutElement (Tongue); + } +} + +static void +zoqfotpik_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + BOOLEAN GiveTongueJob; + STARSHIP *StarShipPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + + GiveTongueJob = FALSE; + if (StarShipPtr->special_counter == 0) + { + EVALUATE_DESC *lpEnemyEvalDesc; + + StarShipPtr->ship_input_state &= ~SPECIAL; + + lpEnemyEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (lpEnemyEvalDesc->ObjectPtr + && lpEnemyEvalDesc->which_turn <= 4 +#ifdef NEVER + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= SPECIAL_ENERGY_COST +#endif /* NEVER */ + ) + { + SIZE delta_x, delta_y; + + GiveTongueJob = TRUE; + + lpEnemyEvalDesc->MoveState = PURSUE; + delta_x = lpEnemyEvalDesc->ObjectPtr->next.location.x + - ShipPtr->next.location.x; + delta_y = lpEnemyEvalDesc->ObjectPtr->next.location.y + - ShipPtr->next.location.y; + if (StarShipPtr->ShipFacing == NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) + )) + StarShipPtr->ship_input_state |= SPECIAL; + } + } + + ++StarShipPtr->weapon_counter; + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + --StarShipPtr->weapon_counter; + + if (StarShipPtr->weapon_counter == 0) + { + StarShipPtr->ship_input_state &= ~WEAPON; + if (!GiveTongueJob) + { + ObjectsOfConcern += ConcernCounter; + while (ConcernCounter--) + { + --ObjectsOfConcern; + if (ObjectsOfConcern->ObjectPtr + && (ConcernCounter == ENEMY_SHIP_INDEX + || (ConcernCounter == ENEMY_WEAPON_INDEX + && ObjectsOfConcern->MoveState != AVOID +#ifdef NEVER + && !(StarShipPtr->control & STANDARD_RATING) +#endif /* NEVER */ + )) + && ship_weapons (ShipPtr, + ObjectsOfConcern->ObjectPtr, DISPLAY_TO_WORLD (20))) + { + StarShipPtr->ship_input_state |= WEAPON; + break; + } + } + } + } +} + +static void +zoqfotpik_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + ProcessSound (SetAbsSoundIndex ( + /* STICK_OUT_TONGUE */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } + + if (StarShipPtr->special_counter) + spawn_tongue (ElementPtr); +} + +RACE_DESC* +init_zoqfotpik (void) +{ + RACE_DESC *RaceDescPtr; + + zoqfotpik_desc.postprocess_func = zoqfotpik_postprocess; + zoqfotpik_desc.init_weapon_func = initialize_spit; + zoqfotpik_desc.cyborg_control.intelligence_func = zoqfotpik_intelligence; + + RaceDescPtr = &zoqfotpik_desc; + + return (RaceDescPtr); +} + diff --git a/src/uqm/ships/zoqfot/zoqfot.h b/src/uqm/ships/zoqfot/zoqfot.h new file mode 100644 index 0000000..1bdcc85 --- /dev/null +++ b/src/uqm/ships/zoqfot/zoqfot.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef ZOQFOT_H +#define ZOQFOT_H + +#if defined(__cplusplus) +extern "C" { +#endif + +RACE_DESC *init_zoqfotpik (void); + +#if defined(__cplusplus) +} +#endif + +#endif /* ZOQFOT_H */ + |