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