summaryrefslogtreecommitdiff
path: root/src/uqm/ships
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/ships')
-rw-r--r--src/uqm/ships/Makeinfo5
-rw-r--r--src/uqm/ships/androsyn/Makeinfo2
-rw-r--r--src/uqm/ships/androsyn/androsyn.c528
-rw-r--r--src/uqm/ships/androsyn/androsyn.h31
-rw-r--r--src/uqm/ships/androsyn/icode.h5
-rw-r--r--src/uqm/ships/androsyn/resinst.h19
-rw-r--r--src/uqm/ships/arilou/Makeinfo2
-rw-r--r--src/uqm/ships/arilou/arilou.c303
-rw-r--r--src/uqm/ships/arilou/arilou.h31
-rw-r--r--src/uqm/ships/arilou/icode.h5
-rw-r--r--src/uqm/ships/arilou/resinst.h16
-rw-r--r--src/uqm/ships/blackurq/Makeinfo2
-rw-r--r--src/uqm/ships/blackurq/blackurq.c567
-rw-r--r--src/uqm/ships/blackurq/blackurq.h31
-rw-r--r--src/uqm/ships/blackurq/icode.h5
-rw-r--r--src/uqm/ships/blackurq/resinst.h19
-rw-r--r--src/uqm/ships/chenjesu/Makeinfo2
-rw-r--r--src/uqm/ships/chenjesu/chenjesu.c588
-rw-r--r--src/uqm/ships/chenjesu/chenjesu.h31
-rw-r--r--src/uqm/ships/chenjesu/icode.h5
-rw-r--r--src/uqm/ships/chenjesu/resinst.h19
-rw-r--r--src/uqm/ships/chmmr/Makeinfo2
-rw-r--r--src/uqm/ships/chmmr/chmmr.c790
-rw-r--r--src/uqm/ships/chmmr/chmmr.h31
-rw-r--r--src/uqm/ships/chmmr/icode.h5
-rw-r--r--src/uqm/ships/chmmr/resinst.h19
-rw-r--r--src/uqm/ships/druuge/Makeinfo2
-rw-r--r--src/uqm/ships/druuge/druuge.c324
-rw-r--r--src/uqm/ships/druuge/druuge.h31
-rw-r--r--src/uqm/ships/druuge/icode.h5
-rw-r--r--src/uqm/ships/druuge/resinst.h16
-rw-r--r--src/uqm/ships/human/Makeinfo2
-rw-r--r--src/uqm/ships/human/human.c360
-rw-r--r--src/uqm/ships/human/human.h31
-rw-r--r--src/uqm/ships/human/icode.h5
-rw-r--r--src/uqm/ships/human/resinst.h16
-rw-r--r--src/uqm/ships/ilwrath/Makeinfo2
-rw-r--r--src/uqm/ships/ilwrath/icode.h5
-rw-r--r--src/uqm/ships/ilwrath/ilwrath.c409
-rw-r--r--src/uqm/ships/ilwrath/ilwrath.h31
-rw-r--r--src/uqm/ships/ilwrath/resinst.h16
-rw-r--r--src/uqm/ships/lastbat/Makeinfo2
-rw-r--r--src/uqm/ships/lastbat/icode.h5
-rw-r--r--src/uqm/ships/lastbat/lastbat.c926
-rw-r--r--src/uqm/ships/lastbat/lastbat.h31
-rw-r--r--src/uqm/ships/lastbat/resinst.h16
-rw-r--r--src/uqm/ships/melnorme/Makeinfo2
-rw-r--r--src/uqm/ships/melnorme/icode.h5
-rw-r--r--src/uqm/ships/melnorme/melnorme.c658
-rw-r--r--src/uqm/ships/melnorme/melnorme.h31
-rw-r--r--src/uqm/ships/melnorme/resinst.h19
-rw-r--r--src/uqm/ships/mmrnmhrm/Makeinfo2
-rw-r--r--src/uqm/ships/mmrnmhrm/icode.h5
-rw-r--r--src/uqm/ships/mmrnmhrm/mmrnmhrm.c527
-rw-r--r--src/uqm/ships/mmrnmhrm/mmrnmhrm.h31
-rw-r--r--src/uqm/ships/mmrnmhrm/resinst.h19
-rw-r--r--src/uqm/ships/mycon/Makeinfo2
-rw-r--r--src/uqm/ships/mycon/icode.h5
-rw-r--r--src/uqm/ships/mycon/mycon.c376
-rw-r--r--src/uqm/ships/mycon/mycon.h31
-rw-r--r--src/uqm/ships/mycon/resinst.h16
-rw-r--r--src/uqm/ships/orz/Makeinfo2
-rw-r--r--src/uqm/ships/orz/icode.h5
-rw-r--r--src/uqm/ships/orz/orz.c1083
-rw-r--r--src/uqm/ships/orz/orz.h35
-rw-r--r--src/uqm/ships/orz/resinst.h19
-rw-r--r--src/uqm/ships/pkunk/Makeinfo2
-rw-r--r--src/uqm/ships/pkunk/icode.h5
-rw-r--r--src/uqm/ships/pkunk/pkunk.c640
-rw-r--r--src/uqm/ships/pkunk/pkunk.h31
-rw-r--r--src/uqm/ships/pkunk/resinst.h16
-rw-r--r--src/uqm/ships/probe/Makeinfo2
-rw-r--r--src/uqm/ships/probe/icode.h5
-rw-r--r--src/uqm/ships/probe/probe.c118
-rw-r--r--src/uqm/ships/probe/probe.h31
-rw-r--r--src/uqm/ships/probe/resinst.h5
-rw-r--r--src/uqm/ships/ship.h37
-rw-r--r--src/uqm/ships/shofixti/Makeinfo2
-rw-r--r--src/uqm/ships/shofixti/icode.h5
-rw-r--r--src/uqm/ships/shofixti/resinst.h23
-rw-r--r--src/uqm/ships/shofixti/shofixti.c521
-rw-r--r--src/uqm/ships/shofixti/shofixti.h31
-rw-r--r--src/uqm/ships/sis_ship/Makeinfo2
-rw-r--r--src/uqm/ships/sis_ship/icode.h5
-rw-r--r--src/uqm/ships/sis_ship/resinst.h15
-rw-r--r--src/uqm/ships/sis_ship/sis_ship.c1002
-rw-r--r--src/uqm/ships/sis_ship/sis_ship.h31
-rw-r--r--src/uqm/ships/slylandr/Makeinfo2
-rw-r--r--src/uqm/ships/slylandr/icode.h5
-rw-r--r--src/uqm/ships/slylandr/resinst.h13
-rw-r--r--src/uqm/ships/slylandr/slylandr.c438
-rw-r--r--src/uqm/ships/slylandr/slylandr.h31
-rw-r--r--src/uqm/ships/spathi/Makeinfo2
-rw-r--r--src/uqm/ships/spathi/icode.h5
-rw-r--r--src/uqm/ships/spathi/resinst.h19
-rw-r--r--src/uqm/ships/spathi/spathi.c301
-rw-r--r--src/uqm/ships/spathi/spathi.h31
-rw-r--r--src/uqm/ships/supox/Makeinfo2
-rw-r--r--src/uqm/ships/supox/icode.h5
-rw-r--r--src/uqm/ships/supox/resinst.h16
-rw-r--r--src/uqm/ships/supox/supox.c288
-rw-r--r--src/uqm/ships/supox/supox.h31
-rw-r--r--src/uqm/ships/syreen/Makeinfo2
-rw-r--r--src/uqm/ships/syreen/icode.h5
-rw-r--r--src/uqm/ships/syreen/resinst.h16
-rw-r--r--src/uqm/ships/syreen/syreen.c284
-rw-r--r--src/uqm/ships/syreen/syreen.h31
-rw-r--r--src/uqm/ships/thradd/Makeinfo2
-rw-r--r--src/uqm/ships/thradd/icode.h5
-rw-r--r--src/uqm/ships/thradd/resinst.h19
-rw-r--r--src/uqm/ships/thradd/thradd.c400
-rw-r--r--src/uqm/ships/thradd/thradd.h31
-rw-r--r--src/uqm/ships/umgah/Makeinfo2
-rw-r--r--src/uqm/ships/umgah/icode.h5
-rw-r--r--src/uqm/ships/umgah/resinst.h17
-rw-r--r--src/uqm/ships/umgah/umgah.c434
-rw-r--r--src/uqm/ships/umgah/umgah.h31
-rw-r--r--src/uqm/ships/urquan/Makeinfo2
-rw-r--r--src/uqm/ships/urquan/icode.h5
-rw-r--r--src/uqm/ships/urquan/resinst.h19
-rw-r--r--src/uqm/ships/urquan/urquan.c554
-rw-r--r--src/uqm/ships/urquan/urquan.h31
-rw-r--r--src/uqm/ships/utwig/Makeinfo2
-rw-r--r--src/uqm/ships/utwig/icode.h5
-rw-r--r--src/uqm/ships/utwig/resinst.h16
-rw-r--r--src/uqm/ships/utwig/utwig.c380
-rw-r--r--src/uqm/ships/utwig/utwig.h31
-rw-r--r--src/uqm/ships/vux/Makeinfo2
-rw-r--r--src/uqm/ships/vux/icode.h5
-rw-r--r--src/uqm/ships/vux/resinst.h17
-rw-r--r--src/uqm/ships/vux/vux.c398
-rw-r--r--src/uqm/ships/vux/vux.h31
-rw-r--r--src/uqm/ships/yehat/Makeinfo2
-rw-r--r--src/uqm/ships/yehat/icode.h5
-rw-r--r--src/uqm/ships/yehat/resinst.h19
-rw-r--r--src/uqm/ships/yehat/yehat.c369
-rw-r--r--src/uqm/ships/yehat/yehat.h31
-rw-r--r--src/uqm/ships/zoqfot/Makeinfo2
-rw-r--r--src/uqm/ships/zoqfot/icode.h5
-rw-r--r--src/uqm/ships/zoqfot/resinst.h19
-rw-r--r--src/uqm/ships/zoqfot/zoqfot.c377
-rw-r--r--src/uqm/ships/zoqfot/zoqfot.h31
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 */
+