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/zoqfot/zoqfot.c | 377 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 src/uqm/ships/zoqfot/zoqfot.c (limited to 'src/uqm/ships/zoqfot/zoqfot.c') diff --git a/src/uqm/ships/zoqfot/zoqfot.c b/src/uqm/ships/zoqfot/zoqfot.c new file mode 100644 index 0000000..15a6024 --- /dev/null +++ b/src/uqm/ships/zoqfot/zoqfot.c @@ -0,0 +1,377 @@ +//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 "zoqfot.h" +#include "resinst.h" + +#include "libs/mathlib.h" + +// Core characteristics +#define MAX_CREW 10 +#define MAX_ENERGY 10 +#define ENERGY_REGENERATION 1 +#define ENERGY_WAIT 4 +#define MAX_THRUST 40 +#define THRUST_INCREMENT 10 +#define THRUST_WAIT 0 +#define TURN_WAIT 1 +#define SHIP_MASS 5 + +// Main weapon +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define ZOQFOTPIK_OFFSET 13 +#define MISSILE_OFFSET 0 +#define MISSILE_SPEED DISPLAY_TO_WORLD (10) + /* Used by the cyborg only. */ +#define MISSILE_LIFE 10 +#define MISSILE_RANGE (MISSILE_SPEED * MISSILE_LIFE) +#define MISSILE_DAMAGE 1 +#define MISSILE_HITS 1 +#define SPIT_WAIT 2 + /* Controls the main weapon color change animation's speed. + * The animation advances one frame every SPIT_WAIT frames. */ + +// Tongue +#define SPECIAL_ENERGY_COST (MAX_ENERGY * 3 / 4) +#define SPECIAL_WAIT 6 +#define TONGUE_SPEED 0 +#define TONGUE_HITS 1 +#define TONGUE_DAMAGE 12 +#define TONGUE_OFFSET 4 + +static RACE_DESC zoqfotpik_desc = +{ + { /* SHIP_INFO */ + FIRES_FORE, + 6, /* Super Melee cost */ + MAX_CREW, MAX_CREW, + MAX_ENERGY, MAX_ENERGY, + ZOQFOTPIK_RACE_STRINGS, + ZOQFOTPIK_ICON_MASK_PMAP_ANIM, + ZOQFOTPIK_MICON_MASK_PMAP_ANIM, + NULL, NULL, NULL + }, + { /* FLEET_STUFF */ + 320 / SPHERE_RADIUS_INCREMENT * 2, /* Initial SoI radius */ + { /* Known location (center of SoI) */ + 3761, 5333, + }, + }, + { + MAX_THRUST, + THRUST_INCREMENT, + ENERGY_REGENERATION, + WEAPON_ENERGY_COST, + SPECIAL_ENERGY_COST, + ENERGY_WAIT, + TURN_WAIT, + THRUST_WAIT, + WEAPON_WAIT, + SPECIAL_WAIT, + SHIP_MASS, + }, + { + { + ZOQFOTPIK_BIG_MASK_PMAP_ANIM, + ZOQFOTPIK_MED_MASK_PMAP_ANIM, + ZOQFOTPIK_SML_MASK_PMAP_ANIM, + }, + { + SPIT_BIG_MASK_PMAP_ANIM, + SPIT_MED_MASK_PMAP_ANIM, + SPIT_SML_MASK_PMAP_ANIM, + }, + { + STINGER_BIG_MASK_PMAP_ANIM, + STINGER_MED_MASK_PMAP_ANIM, + STINGER_SML_MASK_PMAP_ANIM, + }, + { + ZOQFOTPIK_CAPTAIN_MASK_PMAP_ANIM, + NULL, NULL, NULL, NULL, NULL + }, + ZOQFOTPIK_VICTORY_SONG, + ZOQFOTPIK_SHIP_SOUNDS, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + NULL, NULL + }, + { + 0, + MISSILE_RANGE, + NULL, + }, + (UNINIT_FUNC *) NULL, + (PREPROCESS_FUNC *) NULL, + (POSTPROCESS_FUNC *) NULL, + (INIT_WEAPON_FUNC *) NULL, + 0, + 0, /* CodeRef */ +}; + +static void +spit_preprocess (ELEMENT *ElementPtr) +{ + /* turn_wait is abused here to control the animation speed. */ + if (ElementPtr->turn_wait > 0) + --ElementPtr->turn_wait; + else + { + COUNT index, angle, speed; + + ElementPtr->next.image.frame = + IncFrameIndex (ElementPtr->next.image.frame); + angle = GetVelocityTravelAngle (&ElementPtr->velocity); + if ((index = GetFrameIndex (ElementPtr->next.image.frame)) == 1) + angle = angle + (((COUNT)TFB_Random () % 3) - 1); + + speed = WORLD_TO_VELOCITY (DISPLAY_TO_WORLD ( + GetFrameCount (ElementPtr->next.image.frame) - index) << 1); + SetVelocityComponents (&ElementPtr->velocity, + (SIZE)COSINE (angle, speed), + (SIZE)SINE (angle, speed)); + + /* turn_wait is abused here to control the animation speed. */ + ElementPtr->turn_wait = SPIT_WAIT; + ElementPtr->state_flags |= CHANGING; + } +} + +static COUNT +initialize_spit (ELEMENT *ShipPtr, HELEMENT SpitArray[]) +{ + 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 = IGNORE_SIMILAR; + MissileBlock.pixoffs = ZOQFOTPIK_OFFSET; + MissileBlock.speed = DISPLAY_TO_WORLD ( + GetFrameCount (StarShipPtr->RaceDescPtr->ship_data.weapon[0])) << 1; + MissileBlock.hit_points = MISSILE_HITS; + MissileBlock.damage = MISSILE_DAMAGE; + MissileBlock.life = MISSILE_LIFE; + MissileBlock.preprocess_func = spit_preprocess; + MissileBlock.blast_offs = MISSILE_OFFSET; + SpitArray[0] = initialize_missile (&MissileBlock); + + return (1); +} + +static void spawn_tongue (ELEMENT *ElementPtr); + +static void +tongue_postprocess (ELEMENT *ElementPtr) +{ + if (ElementPtr->turn_wait) + spawn_tongue (ElementPtr); +} + +static void +tongue_collision (ELEMENT *ElementPtr0, POINT *pPt0, + ELEMENT *ElementPtr1, POINT *pPt1) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr0, &StarShipPtr); + if (StarShipPtr->special_counter == + StarShipPtr->RaceDescPtr->characteristics.special_wait) + weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); + + StarShipPtr->special_counter -= ElementPtr0->turn_wait; + ElementPtr0->turn_wait = 0; + ElementPtr0->state_flags |= NONSOLID; +} + +static void +spawn_tongue (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + MISSILE_BLOCK TongueBlock; + HELEMENT Tongue; + + GetElementStarShip (ElementPtr, &StarShipPtr); + TongueBlock.cx = ElementPtr->next.location.x; + TongueBlock.cy = ElementPtr->next.location.y; + TongueBlock.farray = StarShipPtr->RaceDescPtr->ship_data.special; + TongueBlock.face = TongueBlock.index = StarShipPtr->ShipFacing; + TongueBlock.sender = ElementPtr->playerNr; + TongueBlock.flags = IGNORE_SIMILAR; + TongueBlock.pixoffs = 0; + TongueBlock.speed = TONGUE_SPEED; + TongueBlock.hit_points = TONGUE_HITS; + TongueBlock.damage = TONGUE_DAMAGE; + TongueBlock.life = 1; + TongueBlock.preprocess_func = 0; + TongueBlock.blast_offs = TONGUE_OFFSET; + Tongue = initialize_missile (&TongueBlock); + if (Tongue) + { + ELEMENT *TonguePtr; + + LockElement (Tongue, &TonguePtr); + TonguePtr->postprocess_func = tongue_postprocess; + TonguePtr->collision_func = tongue_collision; + if (ElementPtr->state_flags & PLAYER_SHIP) + TonguePtr->turn_wait = StarShipPtr->special_counter; + else + { + COUNT angle; + RECT r; + SIZE x_offs, y_offs; + + TonguePtr->turn_wait = ElementPtr->turn_wait - 1; + + GetFrameRect (TonguePtr->current.image.frame, &r); + x_offs = DISPLAY_TO_WORLD (r.extent.width >> 1); + y_offs = DISPLAY_TO_WORLD (r.extent.height >> 1); + + angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); + if (angle > HALF_CIRCLE && angle < FULL_CIRCLE) + TonguePtr->current.location.x -= x_offs; + else if (angle > 0 && angle < HALF_CIRCLE) + TonguePtr->current.location.x += x_offs; + if (angle < QUADRANT || angle > FULL_CIRCLE - QUADRANT) + TonguePtr->current.location.y -= y_offs; + else if (angle > QUADRANT && angle < FULL_CIRCLE - QUADRANT) + TonguePtr->current.location.y += y_offs; + } + + SetElementStarShip (TonguePtr, StarShipPtr); + UnlockElement (Tongue); + PutElement (Tongue); + } +} + +static void +zoqfotpik_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, + COUNT ConcernCounter) +{ + BOOLEAN GiveTongueJob; + STARSHIP *StarShipPtr; + + GetElementStarShip (ShipPtr, &StarShipPtr); + + GiveTongueJob = FALSE; + if (StarShipPtr->special_counter == 0) + { + EVALUATE_DESC *lpEnemyEvalDesc; + + StarShipPtr->ship_input_state &= ~SPECIAL; + + lpEnemyEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; + if (lpEnemyEvalDesc->ObjectPtr + && lpEnemyEvalDesc->which_turn <= 4 +#ifdef NEVER + && StarShipPtr->RaceDescPtr->ship_info.energy_level >= SPECIAL_ENERGY_COST +#endif /* NEVER */ + ) + { + SIZE delta_x, delta_y; + + GiveTongueJob = TRUE; + + lpEnemyEvalDesc->MoveState = PURSUE; + delta_x = lpEnemyEvalDesc->ObjectPtr->next.location.x + - ShipPtr->next.location.x; + delta_y = lpEnemyEvalDesc->ObjectPtr->next.location.y + - ShipPtr->next.location.y; + if (StarShipPtr->ShipFacing == NORMALIZE_FACING ( + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) + )) + StarShipPtr->ship_input_state |= SPECIAL; + } + } + + ++StarShipPtr->weapon_counter; + ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); + --StarShipPtr->weapon_counter; + + if (StarShipPtr->weapon_counter == 0) + { + StarShipPtr->ship_input_state &= ~WEAPON; + if (!GiveTongueJob) + { + ObjectsOfConcern += ConcernCounter; + while (ConcernCounter--) + { + --ObjectsOfConcern; + if (ObjectsOfConcern->ObjectPtr + && (ConcernCounter == ENEMY_SHIP_INDEX + || (ConcernCounter == ENEMY_WEAPON_INDEX + && ObjectsOfConcern->MoveState != AVOID +#ifdef NEVER + && !(StarShipPtr->control & STANDARD_RATING) +#endif /* NEVER */ + )) + && ship_weapons (ShipPtr, + ObjectsOfConcern->ObjectPtr, DISPLAY_TO_WORLD (20))) + { + StarShipPtr->ship_input_state |= WEAPON; + break; + } + } + } + } +} + +static void +zoqfotpik_postprocess (ELEMENT *ElementPtr) +{ + STARSHIP *StarShipPtr; + + GetElementStarShip (ElementPtr, &StarShipPtr); + if ((StarShipPtr->cur_status_flags & SPECIAL) + && StarShipPtr->special_counter == 0 + && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) + { + ProcessSound (SetAbsSoundIndex ( + /* STICK_OUT_TONGUE */ + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), ElementPtr); + + StarShipPtr->special_counter = + StarShipPtr->RaceDescPtr->characteristics.special_wait; + } + + if (StarShipPtr->special_counter) + spawn_tongue (ElementPtr); +} + +RACE_DESC* +init_zoqfotpik (void) +{ + RACE_DESC *RaceDescPtr; + + zoqfotpik_desc.postprocess_func = zoqfotpik_postprocess; + zoqfotpik_desc.init_weapon_func = initialize_spit; + zoqfotpik_desc.cyborg_control.intelligence_func = zoqfotpik_intelligence; + + RaceDescPtr = &zoqfotpik_desc; + + return (RaceDescPtr); +} + -- cgit v1.2.3