From 7f6002caba3f0a6749820c2772161caf55b8d267 Mon Sep 17 00:00:00 2001 From: neonloop Date: Fri, 7 May 2021 20:00:12 +0000 Subject: Initial commit (uqm-0.8.0) --- src/uqm/ships/utwig/utwig.c | 380 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 src/uqm/ships/utwig/utwig.c (limited to 'src/uqm/ships/utwig/utwig.c') 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); +} + -- cgit v1.2.3