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