Refactoring of ship_death() code: Pkunk/Shofixti exception hacks removed (but not MAX_SHIP_MASS+1); both now have own death_func(); Pkunk ditty plays after a simultaneous destruction + reincarnation (bug #666); plus some comments
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3664 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
Changes towards version 0.8:
|
Changes towards version 0.8:
|
||||||
|
- Fixed various Pkunk reincarnation and Shofixti Glory device interactions;
|
||||||
|
Pkunk ditty plays in a simultaneous destruction (bug #666) - Alex
|
||||||
- Preparing for linking with C++ code, from Scott A. Colcord
|
- Preparing for linking with C++ code, from Scott A. Colcord
|
||||||
- Fixed player's phrase leading to Tanaka's response about a solitary
|
- Fixed player's phrase leading to Tanaka's response about a solitary
|
||||||
vigil (bug #859) - Alex
|
vigil (bug #859) - Alex
|
||||||
|
|||||||
@@ -96,7 +96,8 @@ typedef struct state
|
|||||||
|
|
||||||
typedef struct element ELEMENT;
|
typedef struct element ELEMENT;
|
||||||
|
|
||||||
typedef void (CollisionFunc) (ELEMENT *ElementPtr0, POINT *pPt0,
|
typedef void (ElementProcessFunc) (ELEMENT *ElementPtr);
|
||||||
|
typedef void (ElementCollisionFunc) (ELEMENT *ElementPtr0, POINT *pPt0,
|
||||||
ELEMENT *ElementPtr1, POINT *pPt1);
|
ELEMENT *ElementPtr1, POINT *pPt1);
|
||||||
|
|
||||||
// Any physical object in the simulation.
|
// Any physical object in the simulation.
|
||||||
@@ -105,10 +106,10 @@ struct element
|
|||||||
// LINK elements; must be first
|
// LINK elements; must be first
|
||||||
HELEMENT pred, succ;
|
HELEMENT pred, succ;
|
||||||
|
|
||||||
void (*preprocess_func) (struct element *ElementPtr);
|
ElementProcessFunc *preprocess_func;
|
||||||
void (*postprocess_func) (struct element *ElementPtr);
|
ElementProcessFunc *postprocess_func;
|
||||||
CollisionFunc *collision_func;
|
ElementCollisionFunc *collision_func;
|
||||||
void (*death_func) (struct element *ElementPtr);
|
ElementProcessFunc *death_func;
|
||||||
|
|
||||||
// Player this element belongs to
|
// Player this element belongs to
|
||||||
// -1: neutral (planets, asteroids, crew, etc.)
|
// -1: neutral (planets, asteroids, crew, etc.)
|
||||||
|
|||||||
@@ -1660,6 +1660,7 @@ CreateStarBackGround (void)
|
|||||||
RECT clipRect;
|
RECT clipRect;
|
||||||
FRAME frame;
|
FRAME frame;
|
||||||
|
|
||||||
|
// Use SpaceContext to find out the dimensions of the background
|
||||||
oldContext = SetContext (SpaceContext);
|
oldContext = SetContext (SpaceContext);
|
||||||
GetContextClipRect (&clipRect);
|
GetContextClipRect (&clipRect);
|
||||||
|
|
||||||
|
|||||||
@@ -193,6 +193,9 @@ ship_preprocess (ELEMENT *ElementPtr)
|
|||||||
if (RDPtr->preprocess_func)
|
if (RDPtr->preprocess_func)
|
||||||
(*RDPtr->preprocess_func) (ElementPtr);
|
(*RDPtr->preprocess_func) (ElementPtr);
|
||||||
|
|
||||||
|
// XXX: Hack: Pkunk sets hTarget!=0 when it reincarnates. In that
|
||||||
|
// case there is no ship_transition() but a Phoenix transition
|
||||||
|
// instead.
|
||||||
if (ElementPtr->hTarget == 0)
|
if (ElementPtr->hTarget == 0)
|
||||||
{
|
{
|
||||||
ship_transition (ElementPtr);
|
ship_transition (ElementPtr);
|
||||||
|
|||||||
@@ -426,7 +426,7 @@ androsynth_preprocess (ELEMENT *ElementPtr)
|
|||||||
StarShipPtr->RaceDescPtr->characteristics.special_wait;
|
StarShipPtr->RaceDescPtr->characteristics.special_wait;
|
||||||
StarShipPtr->RaceDescPtr->characteristics.energy_regeneration = ENERGY_REGENERATION;
|
StarShipPtr->RaceDescPtr->characteristics.energy_regeneration = ENERGY_REGENERATION;
|
||||||
ElementPtr->mass_points = SHIP_MASS;
|
ElementPtr->mass_points = SHIP_MASS;
|
||||||
ElementPtr->collision_func = (CollisionFunc *)
|
ElementPtr->collision_func = (ElementCollisionFunc *)
|
||||||
StarShipPtr->RaceDescPtr->data;
|
StarShipPtr->RaceDescPtr->data;
|
||||||
ElementPtr->next.image.farray =
|
ElementPtr->next.image.farray =
|
||||||
StarShipPtr->RaceDescPtr->ship_data.ship;
|
StarShipPtr->RaceDescPtr->ship_data.ship;
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ RACE_DESC*
|
|||||||
init_mmrnmhrm (void)
|
init_mmrnmhrm (void)
|
||||||
{
|
{
|
||||||
RACE_DESC *RaceDescPtr;
|
RACE_DESC *RaceDescPtr;
|
||||||
|
// The caller of this func will copy the struct
|
||||||
static RACE_DESC new_mmrnmhrm_desc;
|
static RACE_DESC new_mmrnmhrm_desc;
|
||||||
CHARACTERISTIC_STUFF *otherwing_desc;
|
CHARACTERISTIC_STUFF *otherwing_desc;
|
||||||
|
|
||||||
|
|||||||
+138
-94
@@ -21,6 +21,7 @@
|
|||||||
#include "resinst.h"
|
#include "resinst.h"
|
||||||
|
|
||||||
#include "uqm/globdata.h"
|
#include "uqm/globdata.h"
|
||||||
|
#include "uqm/tactrans.h"
|
||||||
#include "libs/mathlib.h"
|
#include "libs/mathlib.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -112,6 +113,16 @@ static RACE_DESC pkunk_desc =
|
|||||||
0, /* CodeRef */
|
0, /* CodeRef */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Private per-instance ship data
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
HELEMENT hPhoenix;
|
||||||
|
ElementProcessFunc *saved_preprocess_func;
|
||||||
|
ElementProcessFunc *saved_postprocess_func;
|
||||||
|
ElementProcessFunc *saved_death_func;
|
||||||
|
|
||||||
|
} PKUNK_DATA;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
animate (ELEMENT *ElementPtr)
|
animate (ELEMENT *ElementPtr)
|
||||||
{
|
{
|
||||||
@@ -186,15 +197,15 @@ pkunk_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern,
|
|||||||
COUNT ConcernCounter)
|
COUNT ConcernCounter)
|
||||||
{
|
{
|
||||||
STARSHIP *StarShipPtr;
|
STARSHIP *StarShipPtr;
|
||||||
HELEMENT hPhoenix;
|
PKUNK_DATA *PkunkData;
|
||||||
|
|
||||||
GetElementStarShip (ShipPtr, &StarShipPtr);
|
GetElementStarShip (ShipPtr, &StarShipPtr);
|
||||||
hPhoenix = (HELEMENT) StarShipPtr->RaceDescPtr->data;
|
PkunkData = (PKUNK_DATA *) StarShipPtr->RaceDescPtr->data;
|
||||||
if (hPhoenix && (StarShipPtr->control & STANDARD_RATING))
|
if (PkunkData->hPhoenix && (StarShipPtr->control & STANDARD_RATING))
|
||||||
{
|
{
|
||||||
RemoveElement (hPhoenix);
|
RemoveElement (PkunkData->hPhoenix);
|
||||||
FreeElement (hPhoenix);
|
FreeElement (PkunkData->hPhoenix);
|
||||||
StarShipPtr->RaceDescPtr->data = 0;
|
PkunkData->hPhoenix = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StarShipPtr->RaceDescPtr->ship_info.energy_level <
|
if (StarShipPtr->RaceDescPtr->ship_info.energy_level <
|
||||||
@@ -208,108 +219,116 @@ pkunk_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void pkunk_preprocess (ELEMENT *ElementPtr);
|
static void pkunk_preprocess (ELEMENT *ElementPtr);
|
||||||
static void pkunk_postprocess (ELEMENT *ElementPtr);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
new_pkunk (ELEMENT *ElementPtr)
|
new_pkunk (ELEMENT *ElementPtr)
|
||||||
{
|
{
|
||||||
STARSHIP *StarShipPtr;
|
STARSHIP *StarShipPtr;
|
||||||
|
PKUNK_DATA *PkunkData;
|
||||||
|
|
||||||
GetElementStarShip (ElementPtr, &StarShipPtr);
|
GetElementStarShip (ElementPtr, &StarShipPtr);
|
||||||
if (!(ElementPtr->state_flags & PLAYER_SHIP))
|
PkunkData = (PKUNK_DATA *) StarShipPtr->RaceDescPtr->data;
|
||||||
|
|
||||||
|
ElementPtr->state_flags = APPEARING | PLAYER_SHIP | IGNORE_SIMILAR;
|
||||||
|
ElementPtr->mass_points = SHIP_MASS;
|
||||||
|
// Restore the element processing callbacks after the explosion.
|
||||||
|
// The callbacks were changed for the explosion sequence
|
||||||
|
ElementPtr->preprocess_func = PkunkData->saved_preprocess_func;
|
||||||
|
ElementPtr->postprocess_func = PkunkData->saved_postprocess_func;
|
||||||
|
ElementPtr->death_func = PkunkData->saved_death_func;
|
||||||
|
// preprocess_func() is called during the phoenix transition and
|
||||||
|
// then cleared, so we need to restore it
|
||||||
|
StarShipPtr->RaceDescPtr->preprocess_func = pkunk_preprocess;
|
||||||
|
StarShipPtr->RaceDescPtr->ship_info.crew_level = MAX_CREW;
|
||||||
|
StarShipPtr->RaceDescPtr->ship_info.energy_level = MAX_ENERGY;
|
||||||
|
/* fix vux impairment */
|
||||||
|
StarShipPtr->RaceDescPtr->characteristics.max_thrust = MAX_THRUST;
|
||||||
|
StarShipPtr->RaceDescPtr->characteristics.thrust_increment = THRUST_INCREMENT;
|
||||||
|
StarShipPtr->RaceDescPtr->characteristics.turn_wait = TURN_WAIT;
|
||||||
|
StarShipPtr->RaceDescPtr->characteristics.thrust_wait = THRUST_WAIT;
|
||||||
|
StarShipPtr->RaceDescPtr->characteristics.special_wait = 0;
|
||||||
|
|
||||||
|
StarShipPtr->ship_input_state = 0;
|
||||||
|
// Pkunk wins in a simultaneous destruction if it reincarnates
|
||||||
|
StarShipPtr->cur_status_flags &= PLAY_VICTORY_DITTY;
|
||||||
|
StarShipPtr->old_status_flags = 0;
|
||||||
|
StarShipPtr->energy_counter = 0;
|
||||||
|
StarShipPtr->weapon_counter = 0;
|
||||||
|
StarShipPtr->special_counter = 0;
|
||||||
|
ElementPtr->crew_level = 0;
|
||||||
|
ElementPtr->turn_wait = 0;
|
||||||
|
ElementPtr->thrust_wait = 0;
|
||||||
|
ElementPtr->life_span = NORMAL_LIFE;
|
||||||
|
|
||||||
|
StarShipPtr->ShipFacing = NORMALIZE_FACING (TFB_Random ());
|
||||||
|
ElementPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.ship;
|
||||||
|
ElementPtr->current.image.frame = SetAbsFrameIndex (
|
||||||
|
StarShipPtr->RaceDescPtr->ship_data.ship[0],
|
||||||
|
StarShipPtr->ShipFacing);
|
||||||
|
SetPrimType (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], STAMP_PRIM);
|
||||||
|
|
||||||
|
do
|
||||||
{
|
{
|
||||||
ELEMENT *ShipPtr;
|
ElementPtr->current.location.x =
|
||||||
|
WRAP_X (DISPLAY_ALIGN_X (TFB_Random ()));
|
||||||
|
ElementPtr->current.location.y =
|
||||||
|
WRAP_Y (DISPLAY_ALIGN_Y (TFB_Random ()));
|
||||||
|
} while (CalculateGravity (ElementPtr)
|
||||||
|
|| TimeSpaceMatterConflict (ElementPtr));
|
||||||
|
|
||||||
LockElement (StarShipPtr->hShip, &ShipPtr);
|
// XXX: Hack: Set hTarget!=0 so that ship_preprocess() does not
|
||||||
ShipPtr->death_func = new_pkunk;
|
// call ship_transition() for us.
|
||||||
UnlockElement (StarShipPtr->hShip);
|
ElementPtr->hTarget = StarShipPtr->hShip;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ElementPtr->state_flags = APPEARING | PLAYER_SHIP | IGNORE_SIMILAR;
|
|
||||||
ElementPtr->mass_points = SHIP_MASS;
|
|
||||||
ElementPtr->preprocess_func = StarShipPtr->RaceDescPtr->preprocess_func;
|
|
||||||
ElementPtr->postprocess_func = StarShipPtr->RaceDescPtr->postprocess_func;
|
|
||||||
ElementPtr->death_func =
|
|
||||||
(void (*) (ELEMENT *ElementPtr))
|
|
||||||
StarShipPtr->RaceDescPtr->init_weapon_func;
|
|
||||||
StarShipPtr->RaceDescPtr->preprocess_func = pkunk_preprocess;
|
|
||||||
StarShipPtr->RaceDescPtr->postprocess_func = pkunk_postprocess;
|
|
||||||
StarShipPtr->RaceDescPtr->init_weapon_func = initialize_bug_missile;
|
|
||||||
StarShipPtr->RaceDescPtr->ship_info.crew_level = MAX_CREW;
|
|
||||||
StarShipPtr->RaceDescPtr->ship_info.energy_level = MAX_ENERGY;
|
|
||||||
/* fix vux impairment */
|
|
||||||
StarShipPtr->RaceDescPtr->characteristics.max_thrust = MAX_THRUST;
|
|
||||||
StarShipPtr->RaceDescPtr->characteristics.thrust_increment = THRUST_INCREMENT;
|
|
||||||
StarShipPtr->RaceDescPtr->characteristics.turn_wait = TURN_WAIT;
|
|
||||||
StarShipPtr->RaceDescPtr->characteristics.thrust_wait = THRUST_WAIT;
|
|
||||||
StarShipPtr->RaceDescPtr->characteristics.special_wait = 0;
|
|
||||||
|
|
||||||
StarShipPtr->ship_input_state = 0;
|
// This function is called when the ship dies but reincarnates.
|
||||||
StarShipPtr->cur_status_flags = 0;
|
// The generic ship_death() function is not called for the ship in this case.
|
||||||
StarShipPtr->old_status_flags = 0;
|
static void
|
||||||
StarShipPtr->energy_counter = 0;
|
pkunk_reincarnation_death (ELEMENT *ShipPtr)
|
||||||
StarShipPtr->weapon_counter = 0;
|
{
|
||||||
StarShipPtr->special_counter = 0;
|
// Simulate ship death
|
||||||
ElementPtr->crew_level = 0;
|
StopAllBattleMusic ();
|
||||||
ElementPtr->turn_wait = 0;
|
StartShipExplosion (ShipPtr, true);
|
||||||
ElementPtr->thrust_wait = 0;
|
// Once the explosion ends, we will get a brand new ship
|
||||||
ElementPtr->life_span = NORMAL_LIFE;
|
ShipPtr->death_func = new_pkunk;
|
||||||
|
|
||||||
StarShipPtr->ShipFacing = NORMALIZE_FACING (TFB_Random ());
|
|
||||||
ElementPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.ship;
|
|
||||||
ElementPtr->current.image.frame =
|
|
||||||
SetAbsFrameIndex (StarShipPtr->RaceDescPtr->ship_data.ship[0],
|
|
||||||
StarShipPtr->ShipFacing);
|
|
||||||
SetPrimType (&(GLOBAL (DisplayArray))[
|
|
||||||
ElementPtr->PrimIndex
|
|
||||||
], STAMP_PRIM);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
ElementPtr->current.location.x =
|
|
||||||
WRAP_X (DISPLAY_ALIGN_X (TFB_Random ()));
|
|
||||||
ElementPtr->current.location.y =
|
|
||||||
WRAP_Y (DISPLAY_ALIGN_Y (TFB_Random ()));
|
|
||||||
} while (CalculateGravity (ElementPtr)
|
|
||||||
|| TimeSpaceMatterConflict (ElementPtr));
|
|
||||||
|
|
||||||
ElementPtr->hTarget = StarShipPtr->hShip;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
intercept_pkunk_death (ELEMENT *ElementPtr)
|
intercept_pkunk_death (ELEMENT *ElementPtr)
|
||||||
{
|
{
|
||||||
STARSHIP *StarShipPtr;
|
STARSHIP *StarShipPtr;
|
||||||
|
PKUNK_DATA *PkunkData;
|
||||||
ElementPtr->state_flags &= ~DISAPPEARING;
|
ELEMENT *ShipPtr;
|
||||||
ElementPtr->life_span = 1;
|
|
||||||
|
|
||||||
GetElementStarShip (ElementPtr, &StarShipPtr);
|
GetElementStarShip (ElementPtr, &StarShipPtr);
|
||||||
if (StarShipPtr->RaceDescPtr->ship_info.crew_level == 0)
|
PkunkData = (PKUNK_DATA *) StarShipPtr->RaceDescPtr->data;
|
||||||
{
|
|
||||||
ELEMENT *ShipPtr;
|
|
||||||
|
|
||||||
LockElement (StarShipPtr->hShip, &ShipPtr);
|
if (StarShipPtr->RaceDescPtr->ship_info.crew_level != 0)
|
||||||
if (GRAVITY_MASS (ShipPtr->mass_points + 1))
|
{ // Ship not dead yet.
|
||||||
{
|
// Keep the Phoenix element alive.
|
||||||
ElementPtr->state_flags |= DISAPPEARING;
|
ElementPtr->state_flags &= ~DISAPPEARING;
|
||||||
ElementPtr->life_span = 0;
|
ElementPtr->life_span = 1;
|
||||||
}
|
return;
|
||||||
else
|
|
||||||
{
|
|
||||||
ShipPtr->mass_points = MAX_SHIP_MASS + 1;
|
|
||||||
StarShipPtr->RaceDescPtr->preprocess_func = ShipPtr->preprocess_func;
|
|
||||||
StarShipPtr->RaceDescPtr->postprocess_func = ShipPtr->postprocess_func;
|
|
||||||
StarShipPtr->RaceDescPtr->init_weapon_func =
|
|
||||||
(COUNT (*) (ELEMENT *ElementPtr, HELEMENT Weapon[]))
|
|
||||||
ShipPtr->death_func;
|
|
||||||
|
|
||||||
ElementPtr->death_func = new_pkunk;
|
|
||||||
}
|
|
||||||
UnlockElement (StarShipPtr->hShip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LockElement (StarShipPtr->hShip, &ShipPtr);
|
||||||
|
// GRAVITY_MASS() indicates a warp-out here. If Pkunk dies while warping
|
||||||
|
// out, there is no reincarnation.
|
||||||
|
if (!GRAVITY_MASS (ShipPtr->mass_points + 1))
|
||||||
|
{
|
||||||
|
// XXX: Hack: Set mass_points to indicate a reincarnation to
|
||||||
|
// FindAliveStarShip()
|
||||||
|
ShipPtr->mass_points = MAX_SHIP_MASS + 1;
|
||||||
|
// Save the various element processing callbacks before the
|
||||||
|
// explosion happens, because we were not the ones who set
|
||||||
|
// these callbacks and they are about to be changed.
|
||||||
|
PkunkData->saved_preprocess_func = ShipPtr->preprocess_func;
|
||||||
|
PkunkData->saved_postprocess_func = ShipPtr->postprocess_func;
|
||||||
|
PkunkData->saved_death_func = ShipPtr->death_func;
|
||||||
|
|
||||||
|
ShipPtr->death_func = pkunk_reincarnation_death;
|
||||||
|
}
|
||||||
|
UnlockElement (StarShipPtr->hShip);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define START_PHOENIX_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A)
|
#define START_PHOENIX_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A)
|
||||||
@@ -425,15 +444,22 @@ static void
|
|||||||
pkunk_preprocess (ELEMENT *ElementPtr)
|
pkunk_preprocess (ELEMENT *ElementPtr)
|
||||||
{
|
{
|
||||||
STARSHIP *StarShipPtr;
|
STARSHIP *StarShipPtr;
|
||||||
|
PKUNK_DATA *PkunkData;
|
||||||
|
|
||||||
GetElementStarShip (ElementPtr, &StarShipPtr);
|
GetElementStarShip (ElementPtr, &StarShipPtr);
|
||||||
|
PkunkData = (PKUNK_DATA *) StarShipPtr->RaceDescPtr->data;
|
||||||
if (ElementPtr->state_flags & APPEARING)
|
if (ElementPtr->state_flags & APPEARING)
|
||||||
{
|
{
|
||||||
HELEMENT hPhoenix = 0;
|
HELEMENT hPhoenix = 0;
|
||||||
|
|
||||||
if ((BYTE)TFB_Random () & 1)
|
if (TFB_Random () & 1)
|
||||||
hPhoenix = AllocElement ();
|
hPhoenix = AllocElement ();
|
||||||
|
|
||||||
|
// The hPhoenix element is created and placed at the head of the
|
||||||
|
// queue so that it is preprocessed before any of the ships' elements
|
||||||
|
// are, and so before death_func() is called for the dead Pkunk.
|
||||||
|
// hPhoenix detects when the Pkunk ship dies and tweaks the ship,
|
||||||
|
// starting the death + reincarnation sequence.
|
||||||
if (hPhoenix)
|
if (hPhoenix)
|
||||||
{
|
{
|
||||||
ELEMENT *PhoenixPtr;
|
ELEMENT *PhoenixPtr;
|
||||||
@@ -450,12 +476,17 @@ pkunk_preprocess (ELEMENT *ElementPtr)
|
|||||||
UnlockElement (hPhoenix);
|
UnlockElement (hPhoenix);
|
||||||
InsertElement (hPhoenix, GetHeadElement ());
|
InsertElement (hPhoenix, GetHeadElement ());
|
||||||
}
|
}
|
||||||
StarShipPtr->RaceDescPtr->data = (intptr_t) hPhoenix;
|
PkunkData->hPhoenix = hPhoenix;
|
||||||
|
|
||||||
|
// XXX: Hack: new_pkunk() sets hTarget!=0 which indicates a
|
||||||
|
// reincarnation to us.
|
||||||
if (ElementPtr->hTarget == 0)
|
if (ElementPtr->hTarget == 0)
|
||||||
StarShipPtr->RaceDescPtr->preprocess_func = 0;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
// A brand new ship is preprocessed only once
|
||||||
|
StarShipPtr->RaceDescPtr->preprocess_func = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // Start the reincarnation sequence
|
||||||
COUNT angle, facing;
|
COUNT angle, facing;
|
||||||
|
|
||||||
ProcessSound (SetAbsSoundIndex (
|
ProcessSound (SetAbsSoundIndex (
|
||||||
@@ -538,17 +569,31 @@ pkunk_postprocess (ELEMENT *ElementPtr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
uninit_pkunk (RACE_DESC *pRaceDesc)
|
||||||
|
{
|
||||||
|
HFree ((void *)pRaceDesc->data);
|
||||||
|
pRaceDesc->data = 0;
|
||||||
|
}
|
||||||
|
|
||||||
RACE_DESC*
|
RACE_DESC*
|
||||||
init_pkunk (void)
|
init_pkunk (void)
|
||||||
{
|
{
|
||||||
RACE_DESC *RaceDescPtr;
|
RACE_DESC *RaceDescPtr;
|
||||||
|
// The caller of this func will copy the struct
|
||||||
|
static RACE_DESC new_pkunk_desc;
|
||||||
|
|
||||||
|
pkunk_desc.uninit_func = uninit_pkunk;
|
||||||
pkunk_desc.preprocess_func = pkunk_preprocess;
|
pkunk_desc.preprocess_func = pkunk_preprocess;
|
||||||
pkunk_desc.postprocess_func = pkunk_postprocess;
|
pkunk_desc.postprocess_func = pkunk_postprocess;
|
||||||
pkunk_desc.init_weapon_func = initialize_bug_missile;
|
pkunk_desc.init_weapon_func = initialize_bug_missile;
|
||||||
pkunk_desc.cyborg_control.intelligence_func = pkunk_intelligence;
|
pkunk_desc.cyborg_control.intelligence_func = pkunk_intelligence;
|
||||||
|
|
||||||
RaceDescPtr = &pkunk_desc;
|
/* copy initial ship settings to the new descriptor */
|
||||||
|
new_pkunk_desc = pkunk_desc;
|
||||||
|
new_pkunk_desc.data = (intptr_t) HCalloc (sizeof (PKUNK_DATA));
|
||||||
|
|
||||||
|
RaceDescPtr = &new_pkunk_desc;
|
||||||
|
|
||||||
LastSound = 0;
|
LastSound = 0;
|
||||||
// We need to reinitialise it at least each battle, to ensure
|
// We need to reinitialise it at least each battle, to ensure
|
||||||
@@ -557,4 +602,3 @@ init_pkunk (void)
|
|||||||
|
|
||||||
return (RaceDescPtr);
|
return (RaceDescPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "resinst.h"
|
#include "resinst.h"
|
||||||
|
|
||||||
#include "uqm/globdata.h"
|
#include "uqm/globdata.h"
|
||||||
|
#include "uqm/tactrans.h"
|
||||||
#include "libs/mathlib.h"
|
#include "libs/mathlib.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -212,10 +213,10 @@ destruct_preprocess (ELEMENT *ElementPtr)
|
|||||||
PutElement (hDestruct);
|
PutElement (hDestruct);
|
||||||
LockElement (hDestruct, &DestructPtr);
|
LockElement (hDestruct, &DestructPtr);
|
||||||
SetElementStarShip (DestructPtr, StarShipPtr);
|
SetElementStarShip (DestructPtr, StarShipPtr);
|
||||||
DestructPtr->hit_points = DestructPtr->mass_points = 0;
|
DestructPtr->hit_points = 0;
|
||||||
|
DestructPtr->mass_points = 0;
|
||||||
DestructPtr->playerNr = NEUTRAL_PLAYER_NUM;
|
DestructPtr->playerNr = NEUTRAL_PLAYER_NUM;
|
||||||
DestructPtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID;
|
DestructPtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID;
|
||||||
DestructPtr->life_span = (NUM_EXPLOSION_FRAMES - 3) - 1;
|
|
||||||
SetPrimType (&(GLOBAL (DisplayArray))[DestructPtr->PrimIndex],
|
SetPrimType (&(GLOBAL (DisplayArray))[DestructPtr->PrimIndex],
|
||||||
STAMPFILL_PRIM);
|
STAMPFILL_PRIM);
|
||||||
SetPrimColor (&(GLOBAL (DisplayArray))[DestructPtr->PrimIndex],
|
SetPrimColor (&(GLOBAL (DisplayArray))[DestructPtr->PrimIndex],
|
||||||
@@ -224,6 +225,8 @@ destruct_preprocess (ELEMENT *ElementPtr)
|
|||||||
StarShipPtr->RaceDescPtr->ship_data.special;
|
StarShipPtr->RaceDescPtr->ship_data.special;
|
||||||
DestructPtr->current.image.frame =
|
DestructPtr->current.image.frame =
|
||||||
StarShipPtr->RaceDescPtr->ship_data.special[0];
|
StarShipPtr->RaceDescPtr->ship_data.special[0];
|
||||||
|
DestructPtr->life_span = GetFrameCount (
|
||||||
|
DestructPtr->current.image.frame);
|
||||||
DestructPtr->current.location = ElementPtr->current.location;
|
DestructPtr->current.location = ElementPtr->current.location;
|
||||||
DestructPtr->preprocess_func = destruct_preprocess;
|
DestructPtr->preprocess_func = destruct_preprocess;
|
||||||
DestructPtr->postprocess_func = NULL;
|
DestructPtr->postprocess_func = NULL;
|
||||||
@@ -240,110 +243,147 @@ destruct_preprocess (ELEMENT *ElementPtr)
|
|||||||
#define ORZ_MARINE(ptr) (ptr->preprocess_func == intruder_preprocess && \
|
#define ORZ_MARINE(ptr) (ptr->preprocess_func == intruder_preprocess && \
|
||||||
ptr->collision_func == marine_collision)
|
ptr->collision_func == marine_collision)
|
||||||
|
|
||||||
// XXX: This function should be split into two
|
static void
|
||||||
|
self_destruct_kill_objects (ELEMENT *ElementPtr)
|
||||||
|
{
|
||||||
|
// This is called during PostProcessQueue(), close to or at the end,
|
||||||
|
// for the temporary destruct element to apply the effects of glory
|
||||||
|
// explosion. The effects are not seen until the next frame.
|
||||||
|
HELEMENT hElement, hNextElement;
|
||||||
|
|
||||||
|
for (hElement = GetHeadElement (); hElement != 0; hElement = hNextElement)
|
||||||
|
{
|
||||||
|
ELEMENT *ObjPtr;
|
||||||
|
SIZE delta_x, delta_y;
|
||||||
|
DWORD dist;
|
||||||
|
|
||||||
|
LockElement (hElement, &ObjPtr);
|
||||||
|
hNextElement = GetSuccElement (ObjPtr);
|
||||||
|
|
||||||
|
if (!CollidingElement (ObjPtr) && !ORZ_MARINE (ObjPtr))
|
||||||
|
{
|
||||||
|
UnlockElement (hElement);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DESTRUCT_RANGE 180
|
||||||
|
delta_x = ObjPtr->next.location.x - ElementPtr->next.location.x;
|
||||||
|
if (delta_x < 0)
|
||||||
|
delta_x = -delta_x;
|
||||||
|
delta_y = ObjPtr->next.location.y - ElementPtr->next.location.y;
|
||||||
|
if (delta_y < 0)
|
||||||
|
delta_y = -delta_y;
|
||||||
|
delta_x = WORLD_TO_DISPLAY (delta_x);
|
||||||
|
delta_y = WORLD_TO_DISPLAY (delta_y);
|
||||||
|
dist = delta_x * delta_x + delta_y * delta_y;
|
||||||
|
if (delta_x <= DESTRUCT_RANGE && delta_y <= DESTRUCT_RANGE
|
||||||
|
&& dist <= DESTRUCT_RANGE * DESTRUCT_RANGE)
|
||||||
|
{
|
||||||
|
#define MAX_DESTRUCTION (DESTRUCT_RANGE / 10)
|
||||||
|
int destruction = 1 + MAX_DESTRUCTION *
|
||||||
|
(DESTRUCT_RANGE - square_root (dist)) / DESTRUCT_RANGE;
|
||||||
|
|
||||||
|
// XXX: Why not simply call do_damage()?
|
||||||
|
if (ObjPtr->state_flags & PLAYER_SHIP)
|
||||||
|
{
|
||||||
|
if (!DeltaCrew (ObjPtr, -destruction))
|
||||||
|
ObjPtr->life_span = 0;
|
||||||
|
}
|
||||||
|
else if (!GRAVITY_MASS (ObjPtr->mass_points))
|
||||||
|
{
|
||||||
|
if (destruction < ObjPtr->hit_points)
|
||||||
|
ObjPtr->hit_points -= destruction;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ObjPtr->hit_points = 0;
|
||||||
|
ObjPtr->life_span = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockElement (hElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is called when the ship dies via Glory Device.
|
||||||
|
// The generic ship_death() function is not called for the ship in this case.
|
||||||
|
static void
|
||||||
|
shofixti_destruct_death (ELEMENT *ShipPtr)
|
||||||
|
{
|
||||||
|
STARSHIP *StarShip;
|
||||||
|
STARSHIP *winner;
|
||||||
|
|
||||||
|
GetElementStarShip (ShipPtr, &StarShip);
|
||||||
|
|
||||||
|
StopAllBattleMusic ();
|
||||||
|
|
||||||
|
StartShipExplosion (ShipPtr, false);
|
||||||
|
// We process the explosion ourselves because it is different
|
||||||
|
ShipPtr->preprocess_func = destruct_preprocess;
|
||||||
|
|
||||||
|
PlaySound (SetAbsSoundIndex (StarShip->RaceDescPtr->ship_data.ship_sounds,
|
||||||
|
1), CalcSoundPosition (ShipPtr), ShipPtr, GAME_SOUND_PRIORITY + 1);
|
||||||
|
|
||||||
|
winner = GetWinnerStarShip ();
|
||||||
|
if (winner == NULL)
|
||||||
|
{ // No winner determined yet
|
||||||
|
winner = FindAliveStarShip (ShipPtr);
|
||||||
|
if (winner == NULL)
|
||||||
|
{ // No ships left alive after the Glory Device thus Shofixti wins
|
||||||
|
winner = StarShip;
|
||||||
|
}
|
||||||
|
SetWinnerStarShip (winner);
|
||||||
|
}
|
||||||
|
else if (winner == StarShip)
|
||||||
|
{ // This ship is the winner
|
||||||
|
// It may have self-destructed before the ditty started playing,
|
||||||
|
// and in that case, there should be no ditty
|
||||||
|
StarShip->cur_status_flags &= ~PLAY_VICTORY_DITTY;
|
||||||
|
}
|
||||||
|
RecordShipDeath (ShipPtr);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
self_destruct (ELEMENT *ElementPtr)
|
self_destruct (ELEMENT *ElementPtr)
|
||||||
{
|
{
|
||||||
STARSHIP *StarShipPtr;
|
STARSHIP *StarShipPtr;
|
||||||
|
HELEMENT hDestruct;
|
||||||
|
|
||||||
GetElementStarShip (ElementPtr, &StarShipPtr);
|
GetElementStarShip (ElementPtr, &StarShipPtr);
|
||||||
if (ElementPtr->state_flags & PLAYER_SHIP)
|
|
||||||
|
// Spawn a temporary element, which dies in this same frame, in order
|
||||||
|
// to defer the effects of the glory explosion.
|
||||||
|
// It will be the last element (or one of the last) for which the
|
||||||
|
// death_func() will be called from PostProcessQueue() in this frame.
|
||||||
|
// XXX: Why at the end? Why not just do it now?
|
||||||
|
hDestruct = AllocElement ();
|
||||||
|
if (hDestruct)
|
||||||
{
|
{
|
||||||
HELEMENT hDestruct;
|
ELEMENT *DestructPtr;
|
||||||
|
|
||||||
// Spawn a temporary element, which dies in this same frame, in order
|
LockElement (hDestruct, &DestructPtr);
|
||||||
// to defer the effects of the glory explosion.
|
DestructPtr->playerNr = ElementPtr->playerNr;
|
||||||
// It will be the last element (or one of the last) for which the
|
DestructPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE;
|
||||||
// death_func will be called from PostProcessQueue() in this frame.
|
DestructPtr->next.location = ElementPtr->next.location;
|
||||||
hDestruct = AllocElement ();
|
DestructPtr->life_span = 0;
|
||||||
if (hDestruct)
|
DestructPtr->pParent = ElementPtr->pParent;
|
||||||
{
|
DestructPtr->hTarget = 0;
|
||||||
ELEMENT *DestructPtr;
|
|
||||||
|
|
||||||
LockElement (hDestruct, &DestructPtr);
|
DestructPtr->death_func = self_destruct_kill_objects;
|
||||||
DestructPtr->playerNr = ElementPtr->playerNr;
|
|
||||||
DestructPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE;
|
|
||||||
DestructPtr->next.location = ElementPtr->next.location;
|
|
||||||
DestructPtr->life_span = 0;
|
|
||||||
DestructPtr->pParent = ElementPtr->pParent;
|
|
||||||
DestructPtr->hTarget = 0;
|
|
||||||
|
|
||||||
DestructPtr->death_func = self_destruct;
|
UnlockElement (hDestruct);
|
||||||
|
|
||||||
UnlockElement (hDestruct);
|
PutElement (hDestruct);
|
||||||
|
|
||||||
PutElement (hDestruct);
|
|
||||||
}
|
|
||||||
|
|
||||||
ElementPtr->state_flags |= NONSOLID;
|
|
||||||
// The ship is now dead. It's death_func, i.e. ship_death(), will be
|
|
||||||
// called the next frame.
|
|
||||||
ElementPtr->life_span = 0;
|
|
||||||
|
|
||||||
ElementPtr->preprocess_func = destruct_preprocess;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// This is called during PostProcessQueue(), close to or at the end,
|
|
||||||
// for the temporary destruct element to apply the effects of glory
|
|
||||||
// explosion. The effects are not seen until the next frame.
|
|
||||||
HELEMENT hElement, hNextElement;
|
|
||||||
|
|
||||||
for (hElement = GetHeadElement ();
|
// Must kill off the remaining crew ourselves
|
||||||
hElement != 0; hElement = hNextElement)
|
DeltaCrew (ElementPtr, -(int)ElementPtr->crew_level);
|
||||||
{
|
|
||||||
ELEMENT *ObjPtr;
|
|
||||||
|
|
||||||
LockElement (hElement, &ObjPtr);
|
ElementPtr->state_flags |= NONSOLID;
|
||||||
hNextElement = GetSuccElement (ObjPtr);
|
ElementPtr->life_span = 0;
|
||||||
|
// The ship is now dead. It's death_func, i.e. shofixti_destruct_death(),
|
||||||
if (CollidingElement (ObjPtr) || ORZ_MARINE (ObjPtr))
|
// will be called the next frame.
|
||||||
{
|
ElementPtr->death_func = shofixti_destruct_death;
|
||||||
#define DESTRUCT_RANGE 180
|
|
||||||
SIZE delta_x, delta_y;
|
|
||||||
DWORD dist;
|
|
||||||
|
|
||||||
if ((delta_x = ObjPtr->next.location.x
|
|
||||||
- ElementPtr->next.location.x) < 0)
|
|
||||||
delta_x = -delta_x;
|
|
||||||
if ((delta_y = ObjPtr->next.location.y
|
|
||||||
- ElementPtr->next.location.y) < 0)
|
|
||||||
delta_y = -delta_y;
|
|
||||||
delta_x = WORLD_TO_DISPLAY (delta_x);
|
|
||||||
delta_y = WORLD_TO_DISPLAY (delta_y);
|
|
||||||
if (delta_x <= DESTRUCT_RANGE && delta_y <= DESTRUCT_RANGE
|
|
||||||
&& (dist = (DWORD)(delta_x * delta_x)
|
|
||||||
+ (DWORD)(delta_y * delta_y)) <=
|
|
||||||
(DWORD)(DESTRUCT_RANGE * DESTRUCT_RANGE))
|
|
||||||
{
|
|
||||||
#define MAX_DESTRUCTION (DESTRUCT_RANGE / 10)
|
|
||||||
SIZE destruction;
|
|
||||||
|
|
||||||
destruction = ((MAX_DESTRUCTION
|
|
||||||
* (DESTRUCT_RANGE - square_root (dist)))
|
|
||||||
/ DESTRUCT_RANGE) + 1;
|
|
||||||
|
|
||||||
if (ObjPtr->state_flags & PLAYER_SHIP)
|
|
||||||
{
|
|
||||||
if (!DeltaCrew (ObjPtr, -destruction))
|
|
||||||
ObjPtr->life_span = 0;
|
|
||||||
}
|
|
||||||
else if (!GRAVITY_MASS (ObjPtr->mass_points))
|
|
||||||
{
|
|
||||||
if ((BYTE)destruction < ObjPtr->hit_points)
|
|
||||||
ObjPtr->hit_points -= (BYTE)destruction;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ObjPtr->hit_points = 0;
|
|
||||||
ObjPtr->life_span = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UnlockElement (hElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -410,7 +450,7 @@ RACE_DESC*
|
|||||||
init_shofixti (void)
|
init_shofixti (void)
|
||||||
{
|
{
|
||||||
RACE_DESC *RaceDescPtr;
|
RACE_DESC *RaceDescPtr;
|
||||||
|
// The caller of this func will copy the struct
|
||||||
static RACE_DESC new_shofixti_desc;
|
static RACE_DESC new_shofixti_desc;
|
||||||
|
|
||||||
shofixti_desc.postprocess_func = shofixti_postprocess;
|
shofixti_desc.postprocess_func = shofixti_postprocess;
|
||||||
|
|||||||
@@ -848,8 +848,8 @@ RACE_DESC*
|
|||||||
init_sis (void)
|
init_sis (void)
|
||||||
{
|
{
|
||||||
RACE_DESC *RaceDescPtr;
|
RACE_DESC *RaceDescPtr;
|
||||||
|
|
||||||
COUNT i;
|
COUNT i;
|
||||||
|
// The caller of this func will copy the struct
|
||||||
static RACE_DESC new_sis_desc;
|
static RACE_DESC new_sis_desc;
|
||||||
|
|
||||||
/* copy initial ship settings to new_sis_desc */
|
/* copy initial ship settings to new_sis_desc */
|
||||||
|
|||||||
+95
-48
@@ -47,6 +47,8 @@ static void cleanup_dead_ship (ELEMENT *ElementPtr);
|
|||||||
|
|
||||||
static BOOLEAN dittyIsPlaying;
|
static BOOLEAN dittyIsPlaying;
|
||||||
static STARSHIP *winnerStarShip;
|
static STARSHIP *winnerStarShip;
|
||||||
|
// Indicates which ship is the winner of the current battle.
|
||||||
|
// The winner will be last to pick the next ship.
|
||||||
|
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
@@ -617,38 +619,37 @@ explosion_preprocess (ELEMENT *ShipPtr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ship_death (ELEMENT *ShipPtr)
|
StopAllBattleMusic (void)
|
||||||
{
|
{
|
||||||
STARSHIP *StarShipPtr;
|
|
||||||
STARSHIP *VictoriousStarShipPtr;
|
|
||||||
HELEMENT hElement, hNextElement;
|
|
||||||
ELEMENT *ElementPtr;
|
|
||||||
|
|
||||||
StopDitty ();
|
StopDitty ();
|
||||||
StopMusic ();
|
StopMusic ();
|
||||||
|
}
|
||||||
|
|
||||||
GetElementStarShip (ShipPtr, &StarShipPtr);
|
STARSHIP *
|
||||||
|
FindAliveStarShip (ELEMENT *deadShip)
|
||||||
|
{
|
||||||
|
STARSHIP *aliveShip = NULL;
|
||||||
|
HELEMENT hElement, hNextElement;
|
||||||
|
|
||||||
if (ShipPtr->mass_points <= MAX_SHIP_MASS)
|
// Find the remaining ship, if any, and see if it is still alive.
|
||||||
{ // Not running away and not reincarnating (Pkunk)
|
|
||||||
// When a ship tries to run away, it is (dis)counted in DoRunAway(),
|
|
||||||
// so when it dies while running away, we will not count it again
|
|
||||||
assert (StarShipPtr->playerNr >= 0);
|
|
||||||
battle_counter[StarShipPtr->playerNr]--;
|
|
||||||
}
|
|
||||||
|
|
||||||
VictoriousStarShipPtr = NULL;
|
|
||||||
for (hElement = GetHeadElement (); hElement; hElement = hNextElement)
|
for (hElement = GetHeadElement (); hElement; hElement = hNextElement)
|
||||||
{
|
{
|
||||||
|
ELEMENT *ElementPtr;
|
||||||
|
|
||||||
LockElement (hElement, &ElementPtr);
|
LockElement (hElement, &ElementPtr);
|
||||||
if ((ElementPtr->state_flags & PLAYER_SHIP)
|
if ((ElementPtr->state_flags & PLAYER_SHIP)
|
||||||
&& ElementPtr != ShipPtr
|
&& ElementPtr != deadShip
|
||||||
/* and not running away */
|
/* and not running away */
|
||||||
&& ElementPtr->mass_points <= MAX_SHIP_MASS)
|
&& ElementPtr->mass_points <= MAX_SHIP_MASS + 1)
|
||||||
{
|
{
|
||||||
GetElementStarShip (ElementPtr, &VictoriousStarShipPtr);
|
GetElementStarShip (ElementPtr, &aliveShip);
|
||||||
if (VictoriousStarShipPtr->RaceDescPtr->ship_info.crew_level == 0)
|
assert (aliveShip != NULL);
|
||||||
VictoriousStarShipPtr = NULL;
|
if (aliveShip->RaceDescPtr->ship_info.crew_level == 0
|
||||||
|
/* reincarnating Pkunk is not actually dead */
|
||||||
|
&& ElementPtr->mass_points != MAX_SHIP_MASS + 1)
|
||||||
|
{
|
||||||
|
aliveShip = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
UnlockElement (hElement);
|
UnlockElement (hElement);
|
||||||
break;
|
break;
|
||||||
@@ -657,7 +658,58 @@ ship_death (ELEMENT *ShipPtr)
|
|||||||
UnlockElement (hElement);
|
UnlockElement (hElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
StarShipPtr->cur_status_flags &= ~PLAY_VICTORY_DITTY;
|
return aliveShip;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARSHIP *
|
||||||
|
GetWinnerStarShip (void)
|
||||||
|
{
|
||||||
|
return winnerStarShip;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetWinnerStarShip (STARSHIP *winner)
|
||||||
|
{
|
||||||
|
if (winner == NULL)
|
||||||
|
return; // nothing to do
|
||||||
|
|
||||||
|
winner->cur_status_flags |= PLAY_VICTORY_DITTY;
|
||||||
|
|
||||||
|
// The winner is set once per battle. If both ships die, this function is
|
||||||
|
// called twice, once for each ship. We need to preserve the winner
|
||||||
|
// determined on the first call.
|
||||||
|
if (winnerStarShip == NULL)
|
||||||
|
winnerStarShip = winner;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RecordShipDeath (ELEMENT *deadShip)
|
||||||
|
{
|
||||||
|
STARSHIP *deadStarShip;
|
||||||
|
|
||||||
|
GetElementStarShip (deadShip, &deadStarShip);
|
||||||
|
assert (deadStarShip != NULL);
|
||||||
|
|
||||||
|
if (deadShip->mass_points <= MAX_SHIP_MASS)
|
||||||
|
{ // Not running away.
|
||||||
|
// When a ship tries to run away, it is (dis)counted in DoRunAway(),
|
||||||
|
// so when it dies while running away, we will not count it again
|
||||||
|
assert (deadStarShip->playerNr >= 0);
|
||||||
|
battle_counter[deadStarShip->playerNr]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE)
|
||||||
|
MeleeShipDeath (deadStarShip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StartShipExplosion (ELEMENT *ShipPtr, bool playSound)
|
||||||
|
{
|
||||||
|
STARSHIP *StarShipPtr;
|
||||||
|
|
||||||
|
GetElementStarShip (ShipPtr, &StarShipPtr);
|
||||||
|
|
||||||
|
ZeroVelocityComponents (&ShipPtr->velocity);
|
||||||
|
|
||||||
DeltaEnergy (ShipPtr,
|
DeltaEnergy (ShipPtr,
|
||||||
-(SIZE)StarShipPtr->RaceDescPtr->ship_info.energy_level);
|
-(SIZE)StarShipPtr->RaceDescPtr->ship_info.energy_level);
|
||||||
@@ -665,43 +717,38 @@ ship_death (ELEMENT *ShipPtr)
|
|||||||
ShipPtr->life_span = NUM_EXPLOSION_FRAMES * 3;
|
ShipPtr->life_span = NUM_EXPLOSION_FRAMES * 3;
|
||||||
ShipPtr->state_flags &= ~DISAPPEARING;
|
ShipPtr->state_flags &= ~DISAPPEARING;
|
||||||
ShipPtr->state_flags |= FINITE_LIFE | NONSOLID;
|
ShipPtr->state_flags |= FINITE_LIFE | NONSOLID;
|
||||||
|
ShipPtr->preprocess_func = explosion_preprocess;
|
||||||
ShipPtr->postprocess_func = PostProcessStatus;
|
ShipPtr->postprocess_func = PostProcessStatus;
|
||||||
ShipPtr->death_func = cleanup_dead_ship;
|
ShipPtr->death_func = cleanup_dead_ship;
|
||||||
ShipPtr->hTarget = 0;
|
ShipPtr->hTarget = 0;
|
||||||
ZeroVelocityComponents (&ShipPtr->velocity);
|
|
||||||
if (ShipPtr->crew_level) /* only happens for shofixti self-destruct */
|
|
||||||
{
|
|
||||||
PlaySound (SetAbsSoundIndex (
|
|
||||||
StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1),
|
|
||||||
CalcSoundPosition (ShipPtr), ShipPtr,
|
|
||||||
GAME_SOUND_PRIORITY + 1);
|
|
||||||
|
|
||||||
DeltaCrew (ShipPtr, -(SIZE)ShipPtr->crew_level);
|
if (playSound)
|
||||||
if (VictoriousStarShipPtr == NULL)
|
|
||||||
{ // No ships left alive after a Shofixti Glory device,
|
|
||||||
// thus Shofixti wins
|
|
||||||
VictoriousStarShipPtr = StarShipPtr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ShipPtr->preprocess_func = explosion_preprocess;
|
|
||||||
|
|
||||||
PlaySound (SetAbsSoundIndex (GameSounds, SHIP_EXPLODES),
|
PlaySound (SetAbsSoundIndex (GameSounds, SHIP_EXPLODES),
|
||||||
CalcSoundPosition (ShipPtr), ShipPtr, GAME_SOUND_PRIORITY + 1);
|
CalcSoundPosition (ShipPtr), ShipPtr, GAME_SOUND_PRIORITY + 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (VictoriousStarShipPtr != NULL)
|
void
|
||||||
VictoriousStarShipPtr->cur_status_flags |= PLAY_VICTORY_DITTY;
|
ship_death (ELEMENT *ShipPtr)
|
||||||
|
{
|
||||||
|
STARSHIP *StarShipPtr;
|
||||||
|
STARSHIP *winner;
|
||||||
|
|
||||||
// The winner is set once per battle. If both ships die, this function is
|
GetElementStarShip (ShipPtr, &StarShipPtr);
|
||||||
// called twice, once for each ship. We need to preserve the winner
|
|
||||||
// determined on the first call.
|
|
||||||
if (winnerStarShip == NULL)
|
|
||||||
winnerStarShip = VictoriousStarShipPtr;
|
|
||||||
|
|
||||||
if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE)
|
StopAllBattleMusic ();
|
||||||
MeleeShipDeath (StarShipPtr);
|
|
||||||
|
// If the winning ship dies before the ditty starts, do not play it.
|
||||||
|
// e.g. a ship can die after the opponent begins exploding but
|
||||||
|
// before the explosion is over.
|
||||||
|
StarShipPtr->cur_status_flags &= ~PLAY_VICTORY_DITTY;
|
||||||
|
|
||||||
|
StartShipExplosion (ShipPtr, true);
|
||||||
|
|
||||||
|
winner = FindAliveStarShip (ShipPtr);
|
||||||
|
SetWinnerStarShip (winner);
|
||||||
|
RecordShipDeath (ShipPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define START_ION_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A)
|
#define START_ION_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A)
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ extern void flee_preprocess (ELEMENT *ElementPtr);
|
|||||||
|
|
||||||
extern void StopDitty (void);
|
extern void StopDitty (void);
|
||||||
extern void ResetWinnerStarShip (void);
|
extern void ResetWinnerStarShip (void);
|
||||||
|
extern void StopAllBattleMusic (void);
|
||||||
|
extern STARSHIP* FindAliveStarShip (ELEMENT *deadShip);
|
||||||
|
extern STARSHIP* GetWinnerStarShip (void);
|
||||||
|
extern void SetWinnerStarShip (STARSHIP *winner);
|
||||||
|
extern void RecordShipDeath (ELEMENT *deadShip);
|
||||||
|
extern void StartShipExplosion (ELEMENT *ShipPtr, bool playSound);
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ initialize_laser (LASER_BLOCK *pLaserBlock)
|
|||||||
LaserElementPtr->state_flags = APPEARING | FINITE_LIFE
|
LaserElementPtr->state_flags = APPEARING | FINITE_LIFE
|
||||||
| pLaserBlock->flags;
|
| pLaserBlock->flags;
|
||||||
LaserElementPtr->life_span = LASER_LIFE;
|
LaserElementPtr->life_span = LASER_LIFE;
|
||||||
LaserElementPtr->collision_func = (CollisionFunc*)weapon_collision;
|
LaserElementPtr->collision_func = weapon_collision;
|
||||||
LaserElementPtr->blast_offset = 1;
|
LaserElementPtr->blast_offset = 1;
|
||||||
|
|
||||||
LaserElementPtr->current.location.x = pLaserBlock->cx
|
LaserElementPtr->current.location.x = pLaserBlock->cx
|
||||||
@@ -100,7 +100,7 @@ initialize_missile (MISSILE_BLOCK *pMissileBlock)
|
|||||||
SetAbsFrameIndex (pMissileBlock->farray[0],
|
SetAbsFrameIndex (pMissileBlock->farray[0],
|
||||||
pMissileBlock->index);
|
pMissileBlock->index);
|
||||||
MissileElementPtr->preprocess_func = pMissileBlock->preprocess_func;
|
MissileElementPtr->preprocess_func = pMissileBlock->preprocess_func;
|
||||||
MissileElementPtr->collision_func = (CollisionFunc*)weapon_collision;
|
MissileElementPtr->collision_func = weapon_collision;
|
||||||
MissileElementPtr->blast_offset = (BYTE)pMissileBlock->blast_offs;
|
MissileElementPtr->blast_offset = (BYTE)pMissileBlock->blast_offs;
|
||||||
|
|
||||||
angle = FACING_TO_ANGLE (pMissileBlock->face);
|
angle = FACING_TO_ANGLE (pMissileBlock->face);
|
||||||
|
|||||||
Reference in New Issue
Block a user