summaryrefslogtreecommitdiff
path: root/src/uqm/ships/blackurq/blackurq.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/ships/blackurq/blackurq.c')
-rw-r--r--src/uqm/ships/blackurq/blackurq.c567
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);
+}