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