Fixed ship picking order after a simultaneous destruction: a dead winner (e.g. Shofixti) is kept alive longer than its dead opponent; in a tie, readyForBattleEnd() is called once per frame for the first ship found dead (currentDeadSide guard removed); fixes bugs #1087, #1088
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3551 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
Changes towards version 0.7:
|
Changes towards version 0.7:
|
||||||
|
- Fixed ship picking order after a simultaneous destruction, e.g.
|
||||||
|
Shofixti picks last after Glory device (bugs #1087, #1088) - Alex
|
||||||
- Game no longer locks up after quickly escaping melee (bug #1003) - Alex
|
- Game no longer locks up after quickly escaping melee (bug #1003) - Alex
|
||||||
- Reset input delay upon leaving Supermelee (bug #1022) - Alex
|
- Reset input delay upon leaving Supermelee (bug #1022) - Alex
|
||||||
- Properly account for simultaneous destruction of last ships
|
- Properly account for simultaneous destruction of last ships
|
||||||
|
|||||||
@@ -57,12 +57,6 @@ size_t battleInputOrder[NUM_SIDES];
|
|||||||
#ifdef NETPLAY
|
#ifdef NETPLAY
|
||||||
BattleFrameCounter battleFrameCount;
|
BattleFrameCounter battleFrameCount;
|
||||||
// Used for synchronisation purposes during netplay.
|
// Used for synchronisation purposes during netplay.
|
||||||
COUNT currentDeadSide;
|
|
||||||
// When a ship has been destroyed, each side of a network
|
|
||||||
// connection waits until the other side is ready.
|
|
||||||
// When two ships die at the same time, this is handled for one
|
|
||||||
// ship after the other. This variable indicate for which player
|
|
||||||
// we're currently doing this.
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static BOOLEAN
|
static BOOLEAN
|
||||||
@@ -447,7 +441,7 @@ Battle (BattleFrameCallback *callback)
|
|||||||
initChecksumBuffers ();
|
initChecksumBuffers ();
|
||||||
#endif /* NETPLAY_CHECKSUM */
|
#endif /* NETPLAY_CHECKSUM */
|
||||||
battleFrameCount = 0;
|
battleFrameCount = 0;
|
||||||
currentDeadSide = (COUNT)~0;
|
ResetWinnerStarShip ();
|
||||||
setBattleStateConnections (&bs);
|
setBattleStateConnections (&bs);
|
||||||
#endif /* NETPLAY */
|
#endif /* NETPLAY */
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ extern BOOLEAN instantVictory;
|
|||||||
extern BattleFrameCounter battleFrameCount;
|
extern BattleFrameCounter battleFrameCount;
|
||||||
#endif
|
#endif
|
||||||
#ifdef NETPLAY
|
#ifdef NETPLAY
|
||||||
extern COUNT currentDeadSide;
|
|
||||||
COUNT GetPlayerOrder (COUNT i);
|
COUNT GetPlayerOrder (COUNT i);
|
||||||
#else
|
#else
|
||||||
# define GetPlayerOrder(i) (i)
|
# define GetPlayerOrder(i) (i)
|
||||||
|
|||||||
+113
-30
@@ -46,6 +46,7 @@
|
|||||||
static void cleanup_dead_ship (ELEMENT *ElementPtr);
|
static void cleanup_dead_ship (ELEMENT *ElementPtr);
|
||||||
|
|
||||||
static BOOLEAN dittyIsPlaying;
|
static BOOLEAN dittyIsPlaying;
|
||||||
|
static STARSHIP *winnerStarShip;
|
||||||
|
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
@@ -96,6 +97,12 @@ DittyPlaying (void)
|
|||||||
return dittyIsPlaying;
|
return dittyIsPlaying;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ResetWinnerStarShip (void)
|
||||||
|
{
|
||||||
|
winnerStarShip = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NETPLAY
|
#ifdef NETPLAY
|
||||||
static void
|
static void
|
||||||
readyToEnd2Callback (NetConnection *conn, void *arg)
|
readyToEnd2Callback (NetConnection *conn, void *arg)
|
||||||
@@ -243,16 +250,14 @@ battleEndReadyNetwork (NetworkInputContext *context)
|
|||||||
|
|
||||||
// Returns true iff this side is ready to end the battle.
|
// Returns true iff this side is ready to end the battle.
|
||||||
static inline bool
|
static inline bool
|
||||||
readyForBattleEnd (COUNT side)
|
readyForBattleEnd (void)
|
||||||
{
|
{
|
||||||
#ifndef NETPLAY
|
#ifndef NETPLAY
|
||||||
#if DEMO_MODE
|
#if DEMO_MODE
|
||||||
// In Demo mode, the saved journal should be replayed with frame
|
// In Demo mode, the saved journal should be replayed with frame
|
||||||
// accuracy. PLRPlaying () isn't consistent enough.
|
// accuracy. PLRPlaying () isn't consistent enough.
|
||||||
(void) side;
|
|
||||||
return true;
|
return true;
|
||||||
#else /* !DEMO_MODE */
|
#else /* !DEMO_MODE */
|
||||||
(void) side;
|
|
||||||
return !DittyPlaying ();
|
return !DittyPlaying ();
|
||||||
#endif /* !DEMO_MODE */
|
#endif /* !DEMO_MODE */
|
||||||
#else /* defined (NETPLAY) */
|
#else /* defined (NETPLAY) */
|
||||||
@@ -261,28 +266,11 @@ readyForBattleEnd (COUNT side)
|
|||||||
if (DittyPlaying ())
|
if (DittyPlaying ())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// We can only handle one dead ship at a time. So 'deadSide' is set
|
|
||||||
// to the side we're handling now. (COUNT)~0 means we're not handling
|
|
||||||
// any side yet.
|
|
||||||
if (currentDeadSide == (COUNT)~0)
|
|
||||||
{
|
|
||||||
// Not handling any side yet.
|
|
||||||
currentDeadSide = side;
|
|
||||||
}
|
|
||||||
else if (side != currentDeadSide)
|
|
||||||
{
|
|
||||||
// We're handing another side at the moment.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (playerI = 0; playerI < NUM_PLAYERS; playerI++)
|
for (playerI = 0; playerI < NUM_PLAYERS; playerI++)
|
||||||
if (!PlayerInput[playerI]->handlers->battleEndReady (
|
if (!PlayerInput[playerI]->handlers->battleEndReady (
|
||||||
PlayerInput[playerI]))
|
PlayerInput[playerI]))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
currentDeadSide = (COUNT)~0;
|
|
||||||
// Another side may be handled.
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#endif /* defined (NETPLAY) */
|
#endif /* defined (NETPLAY) */
|
||||||
}
|
}
|
||||||
@@ -358,10 +346,20 @@ cleanup_dead_ship (ELEMENT *DeadShipPtr)
|
|||||||
UnlockElement (hElement);
|
UnlockElement (hElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MIN_DITTY_FRAME_COUNT ((ONE_SECOND * 3) / BATTLE_FRAME_RATE)
|
||||||
// The ship will be "alive" for at least 2 more frames to make sure
|
// The ship will be "alive" for at least 2 more frames to make sure
|
||||||
// the elements it owns (set up for deletion above) expire first.
|
// the elements it owns (set up for deletion above) expire first.
|
||||||
DeadShipPtr->life_span =
|
// Ditty does NOT play in the following circumstances:
|
||||||
MusicStarted ? (ONE_SECOND * 3) / BATTLE_FRAME_RATE : 1;
|
// * The winning ship dies before the loser finishes exploding
|
||||||
|
// * At the moment the losing ship dies, the winner has started
|
||||||
|
// the warp out sequence
|
||||||
|
DeadShipPtr->life_span = MusicStarted ? MIN_DITTY_FRAME_COUNT : 1;
|
||||||
|
if (DeadStarShipPtr == winnerStarShip)
|
||||||
|
{ // This ship died but won the battle. We need to keep it alive
|
||||||
|
// longer than the dead opponent ship so that the winning player
|
||||||
|
// picks last.
|
||||||
|
DeadShipPtr->life_span = MIN_DITTY_FRAME_COUNT + 1;
|
||||||
|
}
|
||||||
DeadShipPtr->death_func = new_ship;
|
DeadShipPtr->death_func = new_ship;
|
||||||
DeadShipPtr->preprocess_func = preprocess_dead_ship;
|
DeadShipPtr->preprocess_func = preprocess_dead_ship;
|
||||||
DeadShipPtr->state_flags &= ~DISAPPEARING;
|
DeadShipPtr->state_flags &= ~DISAPPEARING;
|
||||||
@@ -373,6 +371,70 @@ cleanup_dead_ship (ELEMENT *DeadShipPtr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setMinShipLifeSpan (ELEMENT *ship, COUNT life_span)
|
||||||
|
{
|
||||||
|
if (ship->death_func == new_ship)
|
||||||
|
{ // The ship has finished exploding or warping out, and now
|
||||||
|
// we can work with the remaining element
|
||||||
|
assert (ship->state_flags & FINITE_LIFE);
|
||||||
|
assert (!(ship->state_flags & DISAPPEARING));
|
||||||
|
if (ship->life_span < life_span)
|
||||||
|
ship->life_span = life_span;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setMinStarShipLifeSpan (STARSHIP *starShip, COUNT life_span)
|
||||||
|
{
|
||||||
|
ELEMENT *ship;
|
||||||
|
|
||||||
|
LockElement (starShip->hShip, &ship);
|
||||||
|
setMinShipLifeSpan (ship, life_span);
|
||||||
|
UnlockElement (starShip->hShip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
checkOtherShipLifeSpan (ELEMENT *deadShip)
|
||||||
|
{
|
||||||
|
STARSHIP *deadStarShip;
|
||||||
|
|
||||||
|
GetElementStarShip (deadShip, &deadStarShip);
|
||||||
|
|
||||||
|
if (winnerStarShip != NULL && deadStarShip != winnerStarShip
|
||||||
|
&& winnerStarShip->RaceDescPtr->ship_info.crew_level == 0)
|
||||||
|
{ // The opponent ship also died but won anyway (e.g. Glory device)
|
||||||
|
// We need to keep the opponent ship alive longer so that the
|
||||||
|
// winning player picks last.
|
||||||
|
setMinStarShipLifeSpan (winnerStarShip, deadShip->life_span + 1);
|
||||||
|
}
|
||||||
|
else if (winnerStarShip == NULL)
|
||||||
|
{ // Both died at the same time, or the loser has already expired
|
||||||
|
HELEMENT hElement, hNextElement;
|
||||||
|
|
||||||
|
// Find the other dead ship(s) and keep them alive for at least as
|
||||||
|
// long as this ship.
|
||||||
|
for (hElement = GetHeadElement (); hElement; hElement = hNextElement)
|
||||||
|
{
|
||||||
|
ELEMENT *element;
|
||||||
|
STARSHIP *starShip;
|
||||||
|
|
||||||
|
LockElement (hElement, &element);
|
||||||
|
hNextElement = GetSuccElement (element);
|
||||||
|
GetElementStarShip (element, &starShip);
|
||||||
|
|
||||||
|
if (starShip != NULL && element != deadShip
|
||||||
|
&& starShip->RaceDescPtr->ship_info.crew_level == 0)
|
||||||
|
{ // This is another dead ship
|
||||||
|
setMinShipLifeSpan (element, deadShip->life_span);
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockElement (hElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is called when dead ship element's life_span reaches 0
|
||||||
void
|
void
|
||||||
new_ship (ELEMENT *DeadShipPtr)
|
new_ship (ELEMENT *DeadShipPtr)
|
||||||
{
|
{
|
||||||
@@ -380,13 +442,25 @@ new_ship (ELEMENT *DeadShipPtr)
|
|||||||
|
|
||||||
GetElementStarShip (DeadShipPtr, &DeadStarShipPtr);
|
GetElementStarShip (DeadShipPtr, &DeadStarShipPtr);
|
||||||
|
|
||||||
if (!readyForBattleEnd (DeadStarShipPtr->playerNr))
|
if (!readyForBattleEnd ())
|
||||||
{
|
{
|
||||||
DeadShipPtr->state_flags &= ~DISAPPEARING;
|
DeadShipPtr->state_flags &= ~DISAPPEARING;
|
||||||
++DeadShipPtr->life_span;
|
++DeadShipPtr->life_span;
|
||||||
|
|
||||||
|
// Keep the winner alive longer, or in a simultaneous destruction
|
||||||
|
// tie, keep the other dead ship alive so that readyForBattleEnd()
|
||||||
|
// is called for only one ship at a time.
|
||||||
|
// When a ship has been destroyed, each side of a network
|
||||||
|
// connection waits until the other side is ready.
|
||||||
|
// When two ships die at the same time, this is handled for one
|
||||||
|
// ship after the other.
|
||||||
|
checkOtherShipLifeSpan (DeadShipPtr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Once a ship is being picked, we do not care about the winner anymore
|
||||||
|
winnerStarShip = NULL;
|
||||||
|
|
||||||
{
|
{
|
||||||
BOOLEAN RestartMusic;
|
BOOLEAN RestartMusic;
|
||||||
|
|
||||||
@@ -563,7 +637,7 @@ ship_death (ELEMENT *ShipPtr)
|
|||||||
battle_counter[StarShipPtr->playerNr]--;
|
battle_counter[StarShipPtr->playerNr]--;
|
||||||
}
|
}
|
||||||
|
|
||||||
VictoriousStarShipPtr = 0;
|
VictoriousStarShipPtr = NULL;
|
||||||
for (hElement = GetHeadElement (); hElement; hElement = hNextElement)
|
for (hElement = GetHeadElement (); hElement; hElement = hNextElement)
|
||||||
{
|
{
|
||||||
LockElement (hElement, &ElementPtr);
|
LockElement (hElement, &ElementPtr);
|
||||||
@@ -574,9 +648,7 @@ ship_death (ELEMENT *ShipPtr)
|
|||||||
{
|
{
|
||||||
GetElementStarShip (ElementPtr, &VictoriousStarShipPtr);
|
GetElementStarShip (ElementPtr, &VictoriousStarShipPtr);
|
||||||
if (VictoriousStarShipPtr->RaceDescPtr->ship_info.crew_level == 0)
|
if (VictoriousStarShipPtr->RaceDescPtr->ship_info.crew_level == 0)
|
||||||
VictoriousStarShipPtr = 0;
|
VictoriousStarShipPtr = NULL;
|
||||||
else
|
|
||||||
VictoriousStarShipPtr->cur_status_flags |= PLAY_VICTORY_DITTY;
|
|
||||||
|
|
||||||
UnlockElement (hElement);
|
UnlockElement (hElement);
|
||||||
break;
|
break;
|
||||||
@@ -599,15 +671,17 @@ ship_death (ELEMENT *ShipPtr)
|
|||||||
ZeroVelocityComponents (&ShipPtr->velocity);
|
ZeroVelocityComponents (&ShipPtr->velocity);
|
||||||
if (ShipPtr->crew_level) /* only happens for shofixti self-destruct */
|
if (ShipPtr->crew_level) /* only happens for shofixti self-destruct */
|
||||||
{
|
{
|
||||||
|
|
||||||
PlaySound (SetAbsSoundIndex (
|
PlaySound (SetAbsSoundIndex (
|
||||||
StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1),
|
StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1),
|
||||||
CalcSoundPosition (ShipPtr), ShipPtr,
|
CalcSoundPosition (ShipPtr), ShipPtr,
|
||||||
GAME_SOUND_PRIORITY + 1);
|
GAME_SOUND_PRIORITY + 1);
|
||||||
|
|
||||||
DeltaCrew (ShipPtr, -(SIZE)ShipPtr->crew_level);
|
DeltaCrew (ShipPtr, -(SIZE)ShipPtr->crew_level);
|
||||||
if (VictoriousStarShipPtr == 0)
|
if (VictoriousStarShipPtr == NULL)
|
||||||
StarShipPtr->cur_status_flags |= PLAY_VICTORY_DITTY;
|
{ // No ships left alive after a Shofixti Glory device,
|
||||||
|
// thus Shofixti wins
|
||||||
|
VictoriousStarShipPtr = StarShipPtr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -617,6 +691,15 @@ ship_death (ELEMENT *ShipPtr)
|
|||||||
CalcSoundPosition (ShipPtr), ShipPtr, GAME_SOUND_PRIORITY + 1);
|
CalcSoundPosition (ShipPtr), ShipPtr, GAME_SOUND_PRIORITY + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (VictoriousStarShipPtr != NULL)
|
||||||
|
VictoriousStarShipPtr->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 = VictoriousStarShipPtr;
|
||||||
|
|
||||||
if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE)
|
if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE)
|
||||||
MeleeShipDeath (StarShipPtr);
|
MeleeShipDeath (StarShipPtr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ extern void spawn_ion_trail (ELEMENT *ElementPtr);
|
|||||||
extern void flee_preprocess (ELEMENT *ElementPtr);
|
extern void flee_preprocess (ELEMENT *ElementPtr);
|
||||||
|
|
||||||
extern void StopDitty (void);
|
extern void StopDitty (void);
|
||||||
|
extern void ResetWinnerStarShip (void);
|
||||||
|
|
||||||
#endif /* _TACTRANS_H */
|
#endif /* _TACTRANS_H */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user