summaryrefslogtreecommitdiff
path: root/src/uqm/ships/mmrnmhrm/mmrnmhrm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/ships/mmrnmhrm/mmrnmhrm.c')
-rw-r--r--src/uqm/ships/mmrnmhrm/mmrnmhrm.c527
1 files changed, 527 insertions, 0 deletions
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);
+}
+