diff options
Diffstat (limited to 'src/uqm/ships/blackurq/blackurq.c')
-rw-r--r-- | src/uqm/ships/blackurq/blackurq.c | 567 |
1 files changed, 567 insertions, 0 deletions
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); +} |