Account for ship death in Supermelee early to keep the scores correct after a simultaneous destruction of last ships in each fleet; some ship selection refactoring; bug #437

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3543 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2010-06-01 18:44:44 +00:00
parent 9de766e368
commit 1402590807
8 changed files with 172 additions and 152 deletions
+2
View File
@@ -1,4 +1,6 @@
Changes towards version 0.7: Changes towards version 0.7:
- Properly account for simultaneous destruction of last ships
in each fleet in Supermelee (bug #437) - Alex
- Do not match singular stars when given a prefix in star search - Do not match singular stars when given a prefix in star search
(bug #1071) - Alex (bug #1071) - Alex
- Preserve character case when editing with joystick (bug #1080) - Alex - Preserve character case when editing with joystick (bug #1080) - Alex
+77 -5
View File
@@ -89,6 +89,15 @@ DoSelectAction (MENU_STATE *pMS)
return (TRUE); return (TRUE);
} }
static QUEUE *
GetShipFragQueueForPlayer (COUNT playerNr)
{
if (playerNr == RPG_PLAYER_NUM)
return &GLOBAL (built_ship_q);
else
return &GLOBAL (npc_built_ship_q);
}
// Called by comm code to intialize battle fleets during encounter // Called by comm code to intialize battle fleets during encounter
void void
BuildBattle (COUNT which_player) BuildBattle (COUNT which_player)
@@ -106,10 +115,9 @@ BuildBattle (COUNT which_player)
return; return;
} }
if (which_player == RPG_PLAYER_NUM) if (which_player != RPG_PLAYER_NUM)
pQueue = &GLOBAL (built_ship_q); { // This function is called first for the NPC character
else // and this is when a centerpiece is loaded
{
switch (LOBYTE (GLOBAL (CurrentActivity))) switch (LOBYTE (GLOBAL (CurrentActivity)))
{ {
case IN_LAST_BATTLE: case IN_LAST_BATTLE:
@@ -124,8 +132,8 @@ BuildBattle (COUNT which_player)
load_gravity_well (GET_GAME_STATE (BATTLE_PLANET)); load_gravity_well (GET_GAME_STATE (BATTLE_PLANET));
break; break;
} }
pQueue = &GLOBAL (npc_built_ship_q);
} }
pQueue = GetShipFragQueueForPlayer (which_player);
ReinitQueue (&race_q[which_player]); ReinitQueue (&race_q[which_player]);
for (hStarShip = GetHeadLink (pQueue); for (hStarShip = GetHeadLink (pQueue);
@@ -181,6 +189,70 @@ BuildBattle (COUNT which_player)
} }
} }
BOOLEAN
FleetIsInfinite (COUNT playerNr)
{
QUEUE *pQueue;
HSHIPFRAG hShipFrag;
SHIP_FRAGMENT *FragPtr;
BOOLEAN ret;
pQueue = GetShipFragQueueForPlayer (playerNr);
hShipFrag = GetHeadLink (pQueue);
if (!hShipFrag)
{ // Ship queue is empty in SuperMelee or for RPG player w/o escorts
return FALSE;
}
FragPtr = LockShipFrag (pQueue, hShipFrag);
ret = (FragPtr->crew_level == INFINITE_FLEET);
UnlockShipFrag (pQueue, hShipFrag);
return ret;
}
void
UpdateShipFragCrew (STARSHIP *StarShipPtr)
{
QUEUE *frag_q;
HSHIPFRAG hShipFrag, hNextFrag;
SHIP_FRAGMENT *frag;
QUEUE *ship_q;
HSTARSHIP hStarShip, hNextShip;
STARSHIP *ship;
frag_q = GetShipFragQueueForPlayer (StarShipPtr->playerNr);
ship_q = &race_q[StarShipPtr->playerNr];
// Find a SHIP_FRAGMENT that corresponds to the given STARSHIP
// The ships and fragments are in the same order in two queues
// XXX: It would probably be simpler to keep HSHIPFRAG in STARSHIP struct
for (hShipFrag = GetHeadLink (frag_q), hStarShip = GetHeadLink (ship_q);
hShipFrag != 0 && hStarShip != 0;
hShipFrag = hNextFrag, hStarShip = hNextShip)
{
ship = LockStarShip (ship_q, hStarShip);
hNextShip = _GetSuccLink (ship);
frag = LockShipFrag (frag_q, hShipFrag);
hNextFrag = _GetSuccLink (frag);
if (ship == StarShipPtr)
{
assert (frag->crew_level != INFINITE_FLEET);
// Record crew left after the battle */
frag->crew_level = ship->crew_level;
UnlockShipFrag (frag_q, hShipFrag);
UnlockStarShip (ship_q, hStarShip);
break;
}
UnlockShipFrag (frag_q, hShipFrag);
UnlockStarShip (ship_q, hStarShip);
}
}
/* /*
* Encountering an alien. * Encountering an alien.
* Draws the encounter screen, plays the red alert music, and * Draws the encounter screen, plays the red alert music, and
+3
View File
@@ -28,6 +28,7 @@ typedef struct encounter ENCOUNTER;
#include "libs/gfxlib.h" #include "libs/gfxlib.h"
#include "planets/planets.h" #include "planets/planets.h"
#include "element.h" #include "element.h"
#include "races.h"
typedef HLINK HENCOUNTER; typedef HLINK HENCOUNTER;
@@ -151,6 +152,8 @@ extern void EncounterBattle (void);
extern void BuildBattle (COUNT which_player); extern void BuildBattle (COUNT which_player);
extern COUNT InitEncounter (void); extern COUNT InitEncounter (void);
extern COUNT UninitEncounter (void); extern COUNT UninitEncounter (void);
extern BOOLEAN FleetIsInfinite (COUNT playerNr);
extern void UpdateShipFragCrew (STARSHIP *);
// XXX: in comm.h, temporary, until solsys generation code is redone // XXX: in comm.h, temporary, until solsys generation code is redone
extern COUNT InitCommunication (CONVERSATION which_comm); extern COUNT InitCommunication (CONVERSATION which_comm);
+9 -11
View File
@@ -25,6 +25,7 @@
#include "pickship.h" #include "pickship.h"
#include "process.h" #include "process.h"
#include "globdata.h" #include "globdata.h"
#include "encount.h"
#include "hyper.h" #include "hyper.h"
#include "init.h" #include "init.h"
#include "port.h" #include "port.h"
@@ -268,7 +269,7 @@ void
UninitShips (void) UninitShips (void)
{ {
COUNT crew_retrieved; COUNT crew_retrieved;
SIZE i; int i;
HELEMENT hElement, hNextElement; HELEMENT hElement, hNextElement;
STARSHIP *SPtr[NUM_PLAYERS]; STARSHIP *SPtr[NUM_PLAYERS];
@@ -325,20 +326,17 @@ UninitShips (void)
GLOBAL (CurrentActivity) &= ~IN_BATTLE; GLOBAL (CurrentActivity) &= ~IN_BATTLE;
if (LOBYTE (GLOBAL (CurrentActivity)) == IN_LAST_BATTLE) if (LOBYTE (GLOBAL (CurrentActivity)) == IN_ENCOUNTER
{
}
else if (LOBYTE (GLOBAL (CurrentActivity)) <= IN_ENCOUNTER
&& !(GLOBAL (CurrentActivity) & CHECK_ABORT)) && !(GLOBAL (CurrentActivity) & CHECK_ABORT))
{ {
// XXX: This has no purpose for SuperMelee // Encounter battle in full game.
// In full-game, the sole purpose of this is to record the crew // Record the crew left in the last ship standing. The crew left
// left in the last ship standing. The crew left is first recorded // is first recorded into STARSHIP.crew_level just a few lines
// into STARSHIP.crew_level just a few lines above here. // above here.
for (i = NUM_PLAYERS - 1; i >= 0; --i) for (i = NUM_PLAYERS - 1; i >= 0; --i)
{ {
if (SPtr[i]) if (SPtr[i] && !FleetIsInfinite (i))
GetEncounterStarShip (SPtr[i], i); UpdateShipFragCrew (SPtr[i]);
} }
} }
+60 -122
View File
@@ -23,6 +23,7 @@
#include "controls.h" #include "controls.h"
#include "menustat.h" #include "menustat.h"
#include "supermelee/pickmele.h" #include "supermelee/pickmele.h"
#include "encount.h"
#include "battle.h" #include "battle.h"
#include "races.h" #include "races.h"
#include "resinst.h" #include "resinst.h"
@@ -290,7 +291,9 @@ OldContext = SetContext (SpaceContext);
if (hBattleShip) if (hBattleShip)
{ {
if (hBattleShip == GetTailLink (&race_q[0])) if (hBattleShip == GetTailLink (&race_q[0]))
battle_counter[0] = 1; { // Player chose SIS. There will be no more choices.
battle_counter[RPG_PLAYER_NUM] = 1;
}
WaitForSoundEnd (0); WaitForSoundEnd (0);
} }
@@ -302,154 +305,89 @@ SetContext (OldContext);
return (hBattleShip); return (hBattleShip);
} }
static QUEUE *
GetShipQueueForSide (COUNT sideNr)
{
if (sideNr == 0)
return &GLOBAL (built_ship_q);
else
return &GLOBAL (npc_built_ship_q);
}
// Get the next ship to use. // Get the next ship to use.
HSTARSHIP HSTARSHIP
GetEncounterStarShip (STARSHIP *LastStarShipPtr, COUNT which_player) GetEncounterStarShip (STARSHIP *LastStarShipPtr, COUNT which_player)
{ {
HSTARSHIP hBattleShip;
if (LOBYTE (GLOBAL (CurrentActivity)) == IN_HYPERSPACE) if (LOBYTE (GLOBAL (CurrentActivity)) == IN_HYPERSPACE)
{ {
// Get the next ship from the battle group. assert (which_player == RPG_PLAYER_NUM);
hBattleShip = GetHeadLink (&race_q[which_player]); // SIS for the Hyperspace flight
return GetHeadLink (&race_q[which_player]);
} }
else if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE) else if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE)
{ {
// Let the player chose their own ship. (May be a computer player). // Let the player chose their own ship. (May be a computer player).
HSTARSHIP hBattleShip;
if (!(GLOBAL (CurrentActivity) & IN_BATTLE)) if (battle_counter[0] == 0 || battle_counter[1] == 0)
{ { // One side is out of ships. Game over.
// XXX: This check is needed, because UninitShips() calls return 0;
// this function after the battle is over to record
// the crew left in the last ship standing.
hBattleShip = 0;
}
else if (!MeleeShipDeath (LastStarShipPtr, which_player))
hBattleShip = 0;
// Game over.
else
{
if (!GetNextMeleeStarShip (which_player, &hBattleShip))
hBattleShip = 0;
} }
if (!GetNextMeleeStarShip (which_player, &hBattleShip))
return 0;
return hBattleShip;
} }
else else
{ {
// Full game. // Full game.
HSHIPFRAG hStarShip; if (which_player == RPG_PLAYER_NUM)
SHIP_FRAGMENT *FragPtr; { // Human player in a full game.
if (LastStarShipPtr == 0 && battle_counter[which_player] == 1)
if (LastStarShipPtr == 0) { // First time picking a ship and player has no escorts
{ // SIS is the last ship in queue (though there is only one)
// First time picking a ship. return GetTailLink (&race_q[which_player]);
if (which_player == 0 && battle_counter[0] > 1)
{
// The player in a full game, still having a ship left.
hBattleShip = GetArmadaStarShip ();
} }
else else if (battle_counter[which_player])
{ { // Player still has ships left
hBattleShip = GetHeadLink (&race_q[which_player]); return GetArmadaStarShip ();
if (which_player == 1) }
{ else if (LastStarShipPtr != 0)
// Select the next ship for the computer. { // last ship was the flagship
hStarShip = GetHeadLink (&GLOBAL (npc_built_ship_q)); #define RUN_AWAY_FUEL_COST (5 * FUEL_TANK_SCALE)
FragPtr = LockShipFrag (&GLOBAL (npc_built_ship_q), if (LastStarShipPtr->crew_level == 0)
hStarShip); { // Died in the line of duty
if (FragPtr->crew_level == INFINITE_FLEET) GLOBAL_SIS (CrewEnlisted) = (COUNT)~0;
{ }
// Infinite number of ships. else
battle_counter[1]++; { // Player ran away
} if (GLOBAL_SIS (FuelOnBoard) > RUN_AWAY_FUEL_COST)
UnlockShipFrag (&GLOBAL (npc_built_ship_q), hStarShip); GLOBAL_SIS (FuelOnBoard) -= RUN_AWAY_FUEL_COST;
else
GLOBAL_SIS (FuelOnBoard) = 0;
} }
} }
return 0;
} }
else else
{ { // NPC player in a full game
QUEUE *pQueue; if (FleetIsInfinite (which_player))
HSHIPFRAG hNextShip;
pQueue = GetShipQueueForSide (which_player);
hBattleShip = GetHeadLink (&race_q[which_player]);
for (hStarShip = GetHeadLink (pQueue);
hStarShip != 0; hStarShip = hNextShip)
{ {
STARSHIP *SPtr; if (LastStarShipPtr != 0)
{ // The current STARSHIP is reused for the next one;
SPtr = LockStarShip (&race_q[which_player], hBattleShip); // update with new info
hNextShip = _GetSuccLink (SPtr); // XXX: Note that if Syreen had a homeworld you could
UnlockStarShip (&race_q[which_player], hBattleShip); // fight, all Syreen ships there would be crewed to
hBattleShip = hNextShip; // the maximum, instead of the normal level
LastStarShipPtr->crew_level = LastStarShipPtr->max_crew;
FragPtr = LockShipFrag (pQueue, hStarShip); LastStarShipPtr->playerNr = which_player;
if (SPtr == LastStarShipPtr) LastStarShipPtr->captains_name_index = PickCaptainName ();
{
if (FragPtr->crew_level != INFINITE_FLEET)
{
/* Record crew left after the battle */
FragPtr->crew_level = SPtr->crew_level;
if (GLOBAL (CurrentActivity) & IN_BATTLE)
SPtr->SpeciesID = NO_ID;
// deactivates the ship
}
else /* if infinite ships */
{
hBattleShip = GetTailLink (&race_q[which_player]);
/* XXX: Note that if Syreen had a homeworld you could
* fight, all Syreen ships there would be crewed to
* the maximum, instead of the normal level */
SPtr->crew_level = FragPtr->max_crew;
SPtr->playerNr = which_player;
SPtr->captains_name_index = PickCaptainName ();
battle_counter[1]++;
}
UnlockShipFrag (pQueue, hStarShip);
break;
} }
hNextShip = _GetSuccLink (FragPtr); battle_counter[which_player]++;
UnlockShipFrag (pQueue, hStarShip);
return GetHeadLink (&race_q[which_player]);
} }
if (which_player == 0) // Get the next ship for the computer
{ if (LastStarShipPtr != 0)
// Player in a full game. return _GetSuccLink (LastStarShipPtr);
if (battle_counter[0])
hBattleShip = GetArmadaStarShip (); // Get the very first ship for the computer
else /* last ship was flagship */ return GetHeadLink (&race_q[which_player]);
{
#define RUN_AWAY_FUEL_COST (5 * FUEL_TANK_SCALE)
hBattleShip = 0;
if (LastStarShipPtr->crew_level == 0)
{
/* Died in the line of duty */
GLOBAL_SIS (CrewEnlisted) = (COUNT)~0;
}
else
{
// Player ran away.
if (GLOBAL_SIS (FuelOnBoard) > RUN_AWAY_FUEL_COST)
GLOBAL_SIS (FuelOnBoard) -= RUN_AWAY_FUEL_COST;
else
GLOBAL_SIS (FuelOnBoard) = 0;
}
}
}
} }
} }
return (hBattleShip);
} }
void void
+5 -12
View File
@@ -682,24 +682,17 @@ MeleeGameOver (void)
LockMutex (GraphicsLock); LockMutex (GraphicsLock);
} }
BOOLEAN void
MeleeShipDeath (STARSHIP *ship, COUNT which_player) { MeleeShipDeath (STARSHIP *ship)
{
FRAME frame; FRAME frame;
// Deactivate fleet position. // Deactivate fleet position.
ship->SpeciesID = NO_ID; ship->SpeciesID = NO_ID;
frame = SetAbsFrameIndex (PickMeleeFrame, which_player); frame = SetAbsFrameIndex (PickMeleeFrame, ship->playerNr);
CrossOutShip (frame, ship->index); CrossOutShip (frame, ship->index);
UpdatePickMeleeFleetValue (frame, which_player); UpdatePickMeleeFleetValue (frame, ship->playerNr);
if (battle_counter[0] == 0 || battle_counter[1] == 0)
{
// One side is out of ships. Game over.
return FALSE;
}
return TRUE;
} }
// Post: the NetState for all players is NetState_interBattle // Post: the NetState for all players is NetState_interBattle
+1 -1
View File
@@ -24,7 +24,7 @@ typedef struct getmelee_struct GETMELEE_STATE;
#include "meleesetup.h" #include "meleesetup.h"
#include "libs/compiler.h" #include "libs/compiler.h"
BOOLEAN MeleeShipDeath (STARSHIP *ship, COUNT which_player); void MeleeShipDeath (STARSHIP *);
void BuildPickMeleeFrame (void); void BuildPickMeleeFrame (void);
void DestroyPickMeleeFrame (void); void DestroyPickMeleeFrame (void);
void FillPickMeleeFrame (MeleeSetup *setup); void FillPickMeleeFrame (MeleeSetup *setup);
+15 -1
View File
@@ -27,6 +27,7 @@
#include "status.h" #include "status.h"
#include "battle.h" #include "battle.h"
#include "init.h" #include "init.h"
#include "supermelee/pickmele.h"
#ifdef NETPLAY #ifdef NETPLAY
# include "supermelee/netplay/netmelee.h" # include "supermelee/netplay/netmelee.h"
# include "supermelee/netplay/netmisc.h" # include "supermelee/netplay/netmisc.h"
@@ -36,6 +37,7 @@
# include "supermelee/netplay/packetq.h" # include "supermelee/netplay/packetq.h"
#endif #endif
#include "races.h" #include "races.h"
#include "encount.h"
#include "settings.h" #include "settings.h"
#include "sounds.h" #include "sounds.h"
#include "libs/mathlib.h" #include "libs/mathlib.h"
@@ -279,7 +281,7 @@ new_ship (ELEMENT *DeadShipPtr)
if (DeadStarShipPtr->crew_level) if (DeadStarShipPtr->crew_level)
{ {
// We've just warped out. new_ship() will still be called // We've just warped out. new_ship() will still be called
// a few times, to process the trace left behind (I assume). // a few times, as for any "dead" ship.
StopMusic (); StopMusic ();
// Even after much investigation, I could find no purpose for // Even after much investigation, I could find no purpose for
@@ -339,6 +341,8 @@ new_ship (ELEMENT *DeadShipPtr)
UnlockElement (hElement); UnlockElement (hElement);
} }
// 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.
DeadShipPtr->life_span = DeadShipPtr->life_span =
MusicStarted ? (ONE_SECOND * 3) / BATTLE_FRAME_RATE : 1; MusicStarted ? (ONE_SECOND * 3) / BATTLE_FRAME_RATE : 1;
DeadShipPtr->death_func = new_ship; DeadShipPtr->death_func = new_ship;
@@ -391,6 +395,13 @@ new_ship (ELEMENT *DeadShipPtr)
} }
#endif /* NETPLAY */ #endif /* NETPLAY */
if (!FleetIsInfinite (DeadStarShipPtr->playerNr))
{ // This may be a dead ship (crew_level == 0) or a warped out ship
UpdateShipFragCrew (DeadStarShipPtr);
// Deactivate the ship (cannot be selected)
DeadStarShipPtr->SpeciesID = NO_ID;
}
if (GetNextStarShip (DeadStarShipPtr, DeadStarShipPtr->playerNr)) if (GetNextStarShip (DeadStarShipPtr, DeadStarShipPtr->playerNr))
{ {
#ifdef NETPLAY #ifdef NETPLAY
@@ -574,6 +585,9 @@ ship_death (ELEMENT *ShipPtr)
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 (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE)
MeleeShipDeath (StarShipPtr);
} }
#define START_ION_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A) #define START_ION_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A)