summaryrefslogtreecommitdiff
path: root/src/uqm/ships/chmmr/chmmr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/ships/chmmr/chmmr.c')
-rw-r--r--src/uqm/ships/chmmr/chmmr.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/src/uqm/ships/chmmr/chmmr.c b/src/uqm/ships/chmmr/chmmr.c
new file mode 100644
index 0000000..8f6abf0
--- /dev/null
+++ b/src/uqm/ships/chmmr/chmmr.c
@@ -0,0 +1,790 @@
+//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 "chmmr.h"
+#include "resinst.h"
+
+#include "uqm/colors.h"
+#include "uqm/globdata.h"
+#include "libs/mathlib.h"
+
+// Core characteristics
+#define MAX_CREW MAX_CREW_SIZE
+#define MAX_ENERGY MAX_ENERGY_SIZE
+#define ENERGY_REGENERATION 1
+#define ENERGY_WAIT 1
+#define MAX_THRUST 35
+#define THRUST_INCREMENT 7
+#define THRUST_WAIT 5
+#define TURN_WAIT 3
+#define SHIP_MASS 10
+
+// Laser
+#define WEAPON_ENERGY_COST 2
+#define WEAPON_WAIT 0
+#define CHMMR_OFFSET 18
+#define LASER_RANGE DISPLAY_TO_WORLD (150)
+#define NUM_CYCLES 4
+
+// Tractor Beam
+#define SPECIAL_ENERGY_COST 1
+#define SPECIAL_WAIT 0
+#define NUM_SHADOWS 5
+
+// Satellites
+#define NUM_SATELLITES 3
+#define SATELLITE_OFFSET DISPLAY_TO_WORLD (64)
+#define SATELLITE_HITPOINTS 10
+#define SATELLITE_MASS 10
+#define DEFENSE_RANGE (UWORD)64
+#define DEFENSE_WAIT 2
+
+static RACE_DESC chmmr_desc =
+{
+ { /* SHIP_INFO */
+ FIRES_FORE | IMMEDIATE_WEAPON | SEEKING_SPECIAL | POINT_DEFENSE,
+ 30, /* Super Melee cost */
+ MAX_CREW, MAX_CREW,
+ MAX_ENERGY, MAX_ENERGY,
+ CHMMR_RACE_STRINGS,
+ CHMMR_ICON_MASK_PMAP_ANIM,
+ CHMMR_MICON_MASK_PMAP_ANIM,
+ NULL, NULL, NULL
+ },
+ { /* FLEET_STUFF */
+ 0, /* Initial sphere of influence radius */
+ { /* Known location (center of SoI) */
+ 0, 0,
+ },
+ },
+ {
+ MAX_THRUST,
+ THRUST_INCREMENT,
+ ENERGY_REGENERATION,
+ WEAPON_ENERGY_COST,
+ SPECIAL_ENERGY_COST,
+ ENERGY_WAIT,
+ TURN_WAIT,
+ THRUST_WAIT,
+ WEAPON_WAIT,
+ SPECIAL_WAIT,
+ SHIP_MASS,
+ },
+ {
+ {
+ CHMMR_BIG_MASK_PMAP_ANIM,
+ CHMMR_MED_MASK_PMAP_ANIM,
+ CHMMR_SML_MASK_PMAP_ANIM,
+ },
+ {
+ MUZZLE_BIG_MASK_PMAP_ANIM,
+ MUZZLE_MED_MASK_PMAP_ANIM,
+ MUZZLE_SML_MASK_PMAP_ANIM,
+ },
+ {
+ SATELLITE_BIG_MASK_PMAP_ANIM,
+ SATELLITE_MED_MASK_PMAP_ANIM,
+ SATELLITE_SML_MASK_PMAP_ANIM,
+ },
+ {
+ CHMMR_CAPTAIN_MASK_PMAP_ANIM,
+ NULL, NULL, NULL, NULL, NULL
+ },
+ CHMMR_VICTORY_SONG,
+ CHMMR_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 void
+animate (ELEMENT *ElementPtr)
+{
+ if (ElementPtr->turn_wait > 0)
+ --ElementPtr->turn_wait;
+ else
+ {
+ ElementPtr->next.image.frame =
+ IncFrameIndex (ElementPtr->current.image.frame);
+ ElementPtr->state_flags |= CHANGING;
+
+ ElementPtr->turn_wait = ElementPtr->next_turn;
+ }
+}
+
+static void
+laser_death (ELEMENT *ElementPtr)
+{
+ STARSHIP *StarShipPtr;
+
+ GetElementStarShip (ElementPtr, &StarShipPtr);
+ StarShipPtr->special_counter = ElementPtr->turn_wait;
+
+ if (StarShipPtr->hShip)
+ {
+ SIZE dx, dy;
+ long dist;
+ HELEMENT hIonSpots;
+ ELEMENT *ShipPtr;
+
+ LockElement (StarShipPtr->hShip, &ShipPtr);
+
+ dx = ElementPtr->current.location.x
+ - ShipPtr->current.location.x;
+ dy = ElementPtr->current.location.y
+ - ShipPtr->current.location.y;
+ if (((BYTE)TFB_Random () & 0x07)
+ && (dist = (long)dx * dx + (long)dy * dy) >=
+ (long)DISPLAY_TO_WORLD (CHMMR_OFFSET + 10)
+ * DISPLAY_TO_WORLD (CHMMR_OFFSET + 10)
+ && (hIonSpots = AllocElement ()))
+ {
+ COUNT angle, magnitude;
+ ELEMENT *IonSpotsPtr;
+
+ LockElement (hIonSpots, &IonSpotsPtr);
+ IonSpotsPtr->playerNr = ElementPtr->playerNr;
+ IonSpotsPtr->state_flags = FINITE_LIFE | NONSOLID
+ | IGNORE_SIMILAR | APPEARING;
+ IonSpotsPtr->turn_wait = IonSpotsPtr->next_turn = 0;
+ IonSpotsPtr->life_span = 9;
+
+ angle = ARCTAN (dx, dy);
+ magnitude = ((COUNT)TFB_Random ()
+ % ((square_root (dist) + 1)
+ - DISPLAY_TO_WORLD (CHMMR_OFFSET + 10)))
+ + DISPLAY_TO_WORLD (CHMMR_OFFSET + 10);
+ IonSpotsPtr->current.location.x =
+ ShipPtr->current.location.x
+ + COSINE (angle, magnitude);
+ IonSpotsPtr->current.location.y =
+ ShipPtr->current.location.y
+ + SINE (angle, magnitude);
+ IonSpotsPtr->current.image.farray =
+ StarShipPtr->RaceDescPtr->ship_data.weapon;
+ IonSpotsPtr->current.image.frame = SetAbsFrameIndex (
+ StarShipPtr->RaceDescPtr->ship_data.weapon[0],
+ ANGLE_TO_FACING (FULL_CIRCLE) << 1
+ );
+
+ IonSpotsPtr->preprocess_func = animate;
+
+ SetElementStarShip (IonSpotsPtr, StarShipPtr);
+
+ SetPrimType (&(GLOBAL (DisplayArray))[
+ IonSpotsPtr->PrimIndex
+ ], STAMP_PRIM);
+
+ UnlockElement (hIonSpots);
+ PutElement (hIonSpots);
+ }
+
+ UnlockElement (StarShipPtr->hShip);
+ }
+}
+
+static COUNT
+initialize_megawatt_laser (ELEMENT *ShipPtr, HELEMENT LaserArray[])
+{
+ RECT r;
+ STARSHIP *StarShipPtr;
+ LASER_BLOCK LaserBlock;
+ static const Color cycle_array[] =
+ {
+ BUILD_COLOR (MAKE_RGB15_INIT (0x17, 0x00, 0x00), 0x2B),
+ BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x03, 0x00), 0x7F),
+ BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x11, 0x00), 0x7B),
+ BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x03, 0x00), 0x7F),
+ };
+
+ GetElementStarShip (ShipPtr, &StarShipPtr);
+ LaserBlock.face = StarShipPtr->ShipFacing;
+ GetFrameRect (SetAbsFrameIndex (
+ StarShipPtr->RaceDescPtr->ship_data.weapon[0], LaserBlock.face
+ ), &r);
+ LaserBlock.cx = DISPLAY_ALIGN (ShipPtr->next.location.x)
+ + DISPLAY_TO_WORLD (r.corner.x);
+ LaserBlock.cy = DISPLAY_ALIGN (ShipPtr->next.location.y)
+ + DISPLAY_TO_WORLD (r.corner.y);
+ LaserBlock.ex = COSINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE);
+ LaserBlock.ey = SINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE);
+ LaserBlock.sender = ShipPtr->playerNr;
+ LaserBlock.flags = IGNORE_SIMILAR;
+ LaserBlock.pixoffs = 0;
+ LaserBlock.color = cycle_array[StarShipPtr->special_counter];
+ LaserArray[0] = initialize_laser (&LaserBlock);
+
+ if (LaserArray[0])
+ {
+ ELEMENT *LaserPtr;
+
+ LockElement (LaserArray[0], &LaserPtr);
+
+ LaserPtr->mass_points = 2;
+ LaserPtr->death_func = laser_death;
+ LaserPtr->turn_wait = (BYTE)((StarShipPtr->special_counter + 1)
+ % NUM_CYCLES);
+
+ UnlockElement (LaserArray[0]);
+ }
+
+ return (1);
+}
+
+static void
+chmmr_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern,
+ COUNT ConcernCounter)
+{
+ STARSHIP *StarShipPtr;
+ EVALUATE_DESC *lpEvalDesc;
+
+ ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter);
+
+ GetElementStarShip (ShipPtr, &StarShipPtr);
+ StarShipPtr->ship_input_state &= ~SPECIAL;
+ lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX];
+ if (StarShipPtr->special_counter == 0
+ && lpEvalDesc->ObjectPtr
+ && !(StarShipPtr->ship_input_state & WEAPON)
+ && lpEvalDesc->which_turn > 12
+ && NORMALIZE_ANGLE (
+ GetVelocityTravelAngle (&ShipPtr->velocity)
+ - (GetVelocityTravelAngle (&lpEvalDesc->ObjectPtr->velocity)
+ + HALF_CIRCLE) + QUADRANT
+ ) > HALF_CIRCLE)
+ StarShipPtr->ship_input_state |= SPECIAL;
+}
+
+static void
+chmmr_postprocess (ELEMENT *ElementPtr)
+{
+ STARSHIP *StarShipPtr;
+
+ GetElementStarShip (ElementPtr, &StarShipPtr);
+
+ if (StarShipPtr->cur_status_flags & WEAPON)
+ {
+ HELEMENT hMuzzleFlash;
+ ELEMENT *MuzzleFlashPtr;
+
+ LockElement (GetTailElement (), &MuzzleFlashPtr);
+ if (MuzzleFlashPtr != ElementPtr
+ && elementsOfSamePlayer (MuzzleFlashPtr, ElementPtr)
+ && (MuzzleFlashPtr->state_flags & APPEARING)
+ && GetPrimType (&(GLOBAL (DisplayArray))[
+ MuzzleFlashPtr->PrimIndex
+ ]) == LINE_PRIM
+ && !(StarShipPtr->special_counter & 1)
+ && (hMuzzleFlash = AllocElement ()))
+ {
+ LockElement (hMuzzleFlash, &MuzzleFlashPtr);
+ MuzzleFlashPtr->playerNr = ElementPtr->playerNr;
+ MuzzleFlashPtr->state_flags = FINITE_LIFE | NONSOLID
+ | IGNORE_SIMILAR | APPEARING;
+ MuzzleFlashPtr->life_span = 1;
+
+ MuzzleFlashPtr->current = ElementPtr->next;
+ MuzzleFlashPtr->current.image.farray =
+ StarShipPtr->RaceDescPtr->ship_data.weapon;
+ MuzzleFlashPtr->current.image.frame = SetAbsFrameIndex (
+ StarShipPtr->RaceDescPtr->ship_data.weapon[0],
+ StarShipPtr->ShipFacing + ANGLE_TO_FACING (FULL_CIRCLE)
+ );
+
+ SetElementStarShip (MuzzleFlashPtr, StarShipPtr);
+
+ SetPrimType (&(GLOBAL (DisplayArray))[
+ MuzzleFlashPtr->PrimIndex
+ ], STAMP_PRIM);
+
+ UnlockElement (hMuzzleFlash);
+ PutElement (hMuzzleFlash);
+ }
+ UnlockElement (GetTailElement ());
+ }
+
+ if ((StarShipPtr->cur_status_flags & SPECIAL)
+ && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST))
+ {
+ COUNT facing;
+ ELEMENT *ShipElementPtr;
+
+ LockElement (ElementPtr->hTarget, &ShipElementPtr);
+
+ ProcessSound (SetAbsSoundIndex (
+ StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1),
+ ShipElementPtr);
+
+ UnlockElement (ElementPtr->hTarget);
+
+ facing = 0;
+ if (TrackShip (ElementPtr, &facing) >= 0)
+ {
+ ELEMENT *ShipElementPtr;
+
+ LockElement (ElementPtr->hTarget, &ShipElementPtr);
+ if (!GRAVITY_MASS (ShipElementPtr->mass_points + 1))
+ {
+ SIZE i, dx, dy;
+ COUNT angle, magnitude;
+ STARSHIP *EnemyStarShipPtr;
+ static const SIZE shadow_offs[] =
+ {
+ DISPLAY_TO_WORLD (8),
+ DISPLAY_TO_WORLD (8 + 9),
+ DISPLAY_TO_WORLD (8 + 9 + 11),
+ DISPLAY_TO_WORLD (8 + 9 + 11 + 14),
+ DISPLAY_TO_WORLD (8 + 9 + 11 + 14 + 18),
+ };
+ static const Color color_tab[] =
+ {
+ BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x10), 0x53),
+ BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x0E), 0x54),
+ BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x0C), 0x55),
+ BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x09), 0x56),
+ BUILD_COLOR (MAKE_RGB15_INIT (0x00, 0x00, 0x07), 0x57),
+ };
+ DWORD current_speed, max_speed;
+
+ // calculate tractor beam effect
+ angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing);
+ dx = (ElementPtr->next.location.x
+ + COSINE (angle, (LASER_RANGE / 3)
+ + DISPLAY_TO_WORLD (CHMMR_OFFSET)))
+ - ShipElementPtr->next.location.x;
+ dy = (ElementPtr->next.location.y
+ + SINE (angle, (LASER_RANGE / 3)
+ + DISPLAY_TO_WORLD (CHMMR_OFFSET)))
+ - ShipElementPtr->next.location.y;
+ angle = ARCTAN (dx, dy);
+ magnitude = WORLD_TO_VELOCITY (12) /
+ ShipElementPtr->mass_points;
+ DeltaVelocityComponents (&ShipElementPtr->velocity,
+ COSINE (angle, magnitude), SINE (angle, magnitude));
+
+ GetCurrentVelocityComponents (&ShipElementPtr->velocity,
+ &dx, &dy);
+ GetElementStarShip (ShipElementPtr, &EnemyStarShipPtr);
+
+ // set the effected ship's speed flags
+ current_speed = VelocitySquared (dx, dy);
+ max_speed = VelocitySquared (WORLD_TO_VELOCITY (
+ EnemyStarShipPtr->RaceDescPtr->characteristics.max_thrust),
+ 0);
+ EnemyStarShipPtr->cur_status_flags &= ~(SHIP_AT_MAX_SPEED
+ | SHIP_BEYOND_MAX_SPEED);
+ if (current_speed > max_speed)
+ EnemyStarShipPtr->cur_status_flags |= (SHIP_AT_MAX_SPEED
+ | SHIP_BEYOND_MAX_SPEED);
+ else if (current_speed == max_speed)
+ EnemyStarShipPtr->cur_status_flags |= SHIP_AT_MAX_SPEED;
+
+ // add tractor beam graphical effects
+ for (i = 0; i < NUM_SHADOWS; ++i)
+ {
+ HELEMENT hShadow;
+
+ hShadow = AllocElement ();
+ if (hShadow)
+ {
+ ELEMENT *ShadowElementPtr;
+
+ LockElement (hShadow, &ShadowElementPtr);
+ ShadowElementPtr->playerNr = ShipElementPtr->playerNr;
+ ShadowElementPtr->state_flags = FINITE_LIFE | NONSOLID
+ | IGNORE_SIMILAR | POST_PROCESS;
+ ShadowElementPtr->life_span = 1;
+
+ ShadowElementPtr->current = ShipElementPtr->next;
+ ShadowElementPtr->current.location.x +=
+ COSINE (angle, shadow_offs[i]);
+ ShadowElementPtr->current.location.y +=
+ SINE (angle, shadow_offs[i]);
+ ShadowElementPtr->next = ShadowElementPtr->current;
+
+ SetElementStarShip (ShadowElementPtr, EnemyStarShipPtr);
+ SetVelocityComponents (&ShadowElementPtr->velocity,
+ dx, dy);
+
+ SetPrimType (&(GLOBAL (DisplayArray))[
+ ShadowElementPtr->PrimIndex
+ ], STAMPFILL_PRIM);
+ SetPrimColor (&(GLOBAL (DisplayArray))[
+ ShadowElementPtr->PrimIndex
+ ], color_tab[i]);
+
+ UnlockElement (hShadow);
+ InsertElement (hShadow, GetHeadElement ());
+ }
+ }
+ }
+ UnlockElement (ElementPtr->hTarget);
+ }
+ }
+
+ StarShipPtr->special_counter = 0;
+}
+
+static void
+satellite_preprocess (ELEMENT *ElementPtr)
+{
+ STARSHIP *StarShipPtr;
+
+ ++ElementPtr->life_span;
+
+ ElementPtr->next.image.frame =
+ SetAbsFrameIndex (ElementPtr->current.image.frame,
+ (GetFrameIndex (ElementPtr->current.image.frame) + 1) & 7);
+ ElementPtr->state_flags |= CHANGING;
+
+ ElementPtr->turn_wait = (BYTE)NORMALIZE_ANGLE (
+ ElementPtr->turn_wait + 1
+ );
+
+ GetElementStarShip (ElementPtr, &StarShipPtr);
+ if (StarShipPtr->hShip)
+ {
+ SIZE dx, dy;
+ ELEMENT *ShipPtr;
+
+ StarShipPtr->RaceDescPtr->ship_info.ship_flags |= POINT_DEFENSE;
+
+ LockElement (StarShipPtr->hShip, &ShipPtr);
+
+ dx = (ShipPtr->next.location.x
+ + COSINE (ElementPtr->turn_wait, SATELLITE_OFFSET))
+ - ElementPtr->current.location.x;
+ dy = (ShipPtr->next.location.y
+ + SINE (ElementPtr->turn_wait, SATELLITE_OFFSET))
+ - ElementPtr->current.location.y;
+ dx = WRAP_DELTA_X (dx);
+ dy = WRAP_DELTA_Y (dy);
+ if ((long)dx * dx + (long)dy * dy
+ <= DISPLAY_TO_WORLD (20L) * DISPLAY_TO_WORLD (20L))
+ SetVelocityComponents (&ElementPtr->velocity,
+ WORLD_TO_VELOCITY (dx),
+ WORLD_TO_VELOCITY (dy));
+ else
+ {
+ COUNT angle;
+
+ angle = ARCTAN (dx, dy);
+ SetVelocityComponents (&ElementPtr->velocity,
+ COSINE (angle, WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (20))),
+ SINE (angle, WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (20))));
+ }
+
+ UnlockElement (StarShipPtr->hShip);
+ }
+}
+
+static void
+spawn_point_defense (ELEMENT *ElementPtr)
+{
+ BYTE weakest;
+ UWORD best_dist;
+ STARSHIP *StarShipPtr;
+ HELEMENT hObject, hNextObject, hBestObject;
+ ELEMENT *ShipPtr;
+ ELEMENT *SattPtr;
+ ELEMENT *ObjectPtr;
+
+ GetElementStarShip (ElementPtr, &StarShipPtr);
+ hBestObject = 0;
+ best_dist = DEFENSE_RANGE + 1;
+ weakest = 255;
+ LockElement (StarShipPtr->hShip, &ShipPtr);
+ LockElement (ElementPtr->hTarget, &SattPtr);
+ for (hObject = GetPredElement (ElementPtr);
+ hObject; hObject = hNextObject)
+ {
+ LockElement (hObject, &ObjectPtr);
+ hNextObject = GetPredElement (ObjectPtr);
+ if (!elementsOfSamePlayer (ObjectPtr, ShipPtr)
+ && ObjectPtr->playerNr != NEUTRAL_PLAYER_NUM
+ && CollisionPossible (ObjectPtr, ShipPtr)
+ && !OBJECT_CLOAKED (ObjectPtr))
+ {
+ SIZE delta_x, delta_y;
+ UWORD dist;
+
+ delta_x = ObjectPtr->next.location.x
+ - SattPtr->next.location.x;
+ delta_y = ObjectPtr->next.location.y
+ - SattPtr->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 <= DEFENSE_RANGE &&
+ (UWORD)delta_y <= DEFENSE_RANGE &&
+ (dist =
+ (UWORD)delta_x * (UWORD)delta_x
+ + (UWORD)delta_y * (UWORD)delta_y) <=
+ DEFENSE_RANGE * DEFENSE_RANGE
+ && (ObjectPtr->hit_points < weakest
+ || (ObjectPtr->hit_points == weakest
+ && dist < best_dist)))
+ {
+ hBestObject = hObject;
+ best_dist = dist;
+ weakest = ObjectPtr->hit_points;
+ }
+ }
+ UnlockElement (hObject);
+ }
+
+ if (hBestObject)
+ {
+ LASER_BLOCK LaserBlock;
+ HELEMENT hPointDefense;
+
+ LockElement (hBestObject, &ObjectPtr);
+
+ LaserBlock.cx = SattPtr->next.location.x;
+ LaserBlock.cy = SattPtr->next.location.y;
+ LaserBlock.face = 0;
+ LaserBlock.ex = ObjectPtr->next.location.x
+ - SattPtr->next.location.x;
+ LaserBlock.ey = ObjectPtr->next.location.y
+ - SattPtr->next.location.y;
+ LaserBlock.sender = SattPtr->playerNr;
+ LaserBlock.flags = IGNORE_SIMILAR;
+ LaserBlock.pixoffs = 0;
+ LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x00, 0x01, 0x1F), 0x4D);
+ hPointDefense = initialize_laser (&LaserBlock);
+ if (hPointDefense)
+ {
+ ELEMENT *PDPtr;
+
+ LockElement (hPointDefense, &PDPtr);
+ SetElementStarShip (PDPtr, StarShipPtr);
+ PDPtr->hTarget = 0;
+ UnlockElement (hPointDefense);
+
+ PutElement (hPointDefense);
+
+ SattPtr->thrust_wait = DEFENSE_WAIT;
+ }
+
+ UnlockElement (hBestObject);
+ }
+
+ UnlockElement (ElementPtr->hTarget);
+ UnlockElement (StarShipPtr->hShip);
+}
+
+static void
+satellite_postprocess (ELEMENT *ElementPtr)
+{
+ STARSHIP *StarShipPtr;
+
+ if (ElementPtr->thrust_wait || ElementPtr->life_span == 0)
+ --ElementPtr->thrust_wait;
+ else
+ {
+ HELEMENT hDefense;
+
+ hDefense = AllocElement ();
+ if (hDefense)
+ {
+ ELEMENT *DefensePtr;
+
+ PutElement (hDefense);
+
+ LockElement (hDefense, &DefensePtr);
+ DefensePtr->playerNr = ElementPtr->playerNr;
+ DefensePtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE;
+
+ {
+ ELEMENT *SuccPtr;
+
+ LockElement (GetSuccElement (ElementPtr), &SuccPtr);
+ DefensePtr->hTarget = GetPredElement (SuccPtr);
+ UnlockElement (GetSuccElement (ElementPtr));
+
+ DefensePtr->death_func = spawn_point_defense;
+ }
+
+ GetElementStarShip (ElementPtr, &StarShipPtr);
+ SetElementStarShip (DefensePtr, StarShipPtr);
+
+ UnlockElement (hDefense);
+ }
+ }
+}
+
+static void
+satellite_collision (ELEMENT *ElementPtr0, POINT *pPt0,
+ ELEMENT *ElementPtr1, POINT *pPt1)
+{
+ (void) ElementPtr0; /* Satisfying compiler (unused parameter) */
+ (void) pPt0; /* Satisfying compiler (unused parameter) */
+ (void) ElementPtr1; /* Satisfying compiler (unused parameter) */
+ (void) pPt1; /* Satisfying compiler (unused parameter) */
+}
+
+static void
+satellite_death (ELEMENT *ElementPtr)
+{
+ STARSHIP *StarShipPtr;
+
+ GetElementStarShip (ElementPtr, &StarShipPtr);
+ StarShipPtr->RaceDescPtr->ship_info.ship_flags &= ~POINT_DEFENSE;
+
+ ElementPtr->state_flags &= ~DISAPPEARING;
+ ElementPtr->state_flags |= NONSOLID | FINITE_LIFE | CHANGING;
+ ElementPtr->life_span = 4;
+ ElementPtr->turn_wait = 1;
+ ElementPtr->next_turn = 0;
+ ElementPtr->next.image.frame =
+ SetAbsFrameIndex (ElementPtr->current.image.frame, 8);
+
+ ElementPtr->preprocess_func = animate;
+ ElementPtr->death_func = NULL;
+ ElementPtr->postprocess_func = NULL;
+ ElementPtr->collision_func = NULL;
+}
+
+static void
+spawn_satellites (ELEMENT *ElementPtr)
+{
+ COUNT i;
+ STARSHIP *StarShipPtr;
+
+ GetElementStarShip (ElementPtr, &StarShipPtr);
+ if (StarShipPtr->hShip)
+ {
+ LockElement (StarShipPtr->hShip, &ElementPtr);
+ for (i = 0; i < NUM_SATELLITES; ++i)
+ {
+ HELEMENT hSatellite;
+
+ hSatellite = AllocElement ();
+ if (hSatellite)
+ {
+ COUNT angle;
+ ELEMENT *SattPtr;
+
+ LockElement (hSatellite, &SattPtr);
+ SattPtr->playerNr = ElementPtr->playerNr;
+ SattPtr->state_flags = IGNORE_SIMILAR | APPEARING
+ | FINITE_LIFE;
+ SattPtr->life_span = NORMAL_LIFE + 1;
+ SattPtr->hit_points = SATELLITE_HITPOINTS;
+ SattPtr->mass_points = SATELLITE_MASS;
+
+ angle = (i * FULL_CIRCLE + (NUM_SATELLITES >> 1))
+ / NUM_SATELLITES;
+ SattPtr->turn_wait = (BYTE)angle;
+ SattPtr->current.location.x = ElementPtr->next.location.x
+ + COSINE (angle, SATELLITE_OFFSET);
+ SattPtr->current.location.y = ElementPtr->next.location.y
+ + SINE (angle, SATELLITE_OFFSET);
+ SattPtr->current.image.farray =
+ StarShipPtr->RaceDescPtr->ship_data.special;
+ SattPtr->current.image.frame = SetAbsFrameIndex (
+ StarShipPtr->RaceDescPtr->ship_data.special[0],
+ (COUNT)TFB_Random () & 0x07
+ );
+
+ SattPtr->preprocess_func = satellite_preprocess;
+ SattPtr->postprocess_func = satellite_postprocess;
+ SattPtr->death_func = satellite_death;
+ SattPtr->collision_func = satellite_collision;
+
+ SetElementStarShip (SattPtr, StarShipPtr);
+
+ SetPrimType (&(GLOBAL (DisplayArray))[
+ SattPtr->PrimIndex
+ ], STAMP_PRIM);
+
+ UnlockElement (hSatellite);
+ PutElement (hSatellite);
+ }
+ }
+ UnlockElement (StarShipPtr->hShip);
+ }
+}
+
+static void
+chmmr_preprocess (ELEMENT *ElementPtr)
+{
+ HELEMENT hSatellite;
+ STARSHIP *StarShipPtr;
+
+ GetElementStarShip (ElementPtr, &StarShipPtr);
+ hSatellite = AllocElement ();
+ if (hSatellite)
+ {
+ ELEMENT *SattPtr;
+ STARSHIP *StarShipPtr;
+
+ LockElement (hSatellite, &SattPtr);
+ SattPtr->playerNr = ElementPtr->playerNr;
+ SattPtr->state_flags = FINITE_LIFE | NONSOLID | IGNORE_SIMILAR
+ | APPEARING;
+ SattPtr->life_span = HYPERJUMP_LIFE + 1;
+
+ SattPtr->death_func = spawn_satellites;
+
+ GetElementStarShip (ElementPtr, &StarShipPtr);
+ SetElementStarShip (SattPtr, StarShipPtr);
+
+ SetPrimType (&(GLOBAL (DisplayArray))[
+ SattPtr->PrimIndex
+ ], NO_PRIM);
+
+ UnlockElement (hSatellite);
+ PutElement (hSatellite);
+ }
+
+ StarShipPtr->RaceDescPtr->preprocess_func = 0;
+}
+
+RACE_DESC*
+init_chmmr (void)
+{
+ RACE_DESC *RaceDescPtr;
+
+ chmmr_desc.preprocess_func = chmmr_preprocess;
+ chmmr_desc.postprocess_func = chmmr_postprocess;
+ chmmr_desc.init_weapon_func = initialize_megawatt_laser;
+ chmmr_desc.cyborg_control.intelligence_func = chmmr_intelligence;
+
+ RaceDescPtr = &chmmr_desc;
+
+ return (RaceDescPtr);
+}
+