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
+77 -5
View File
@@ -89,6 +89,15 @@ DoSelectAction (MENU_STATE *pMS)
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
void
BuildBattle (COUNT which_player)
@@ -106,10 +115,9 @@ BuildBattle (COUNT which_player)
return;
}
if (which_player == RPG_PLAYER_NUM)
pQueue = &GLOBAL (built_ship_q);
else
{
if (which_player != RPG_PLAYER_NUM)
{ // This function is called first for the NPC character
// and this is when a centerpiece is loaded
switch (LOBYTE (GLOBAL (CurrentActivity)))
{
case IN_LAST_BATTLE:
@@ -124,8 +132,8 @@ BuildBattle (COUNT which_player)
load_gravity_well (GET_GAME_STATE (BATTLE_PLANET));
break;
}
pQueue = &GLOBAL (npc_built_ship_q);
}
pQueue = GetShipFragQueueForPlayer (which_player);
ReinitQueue (&race_q[which_player]);
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.
* 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 "planets/planets.h"
#include "element.h"
#include "races.h"
typedef HLINK HENCOUNTER;
@@ -151,6 +152,8 @@ extern void EncounterBattle (void);
extern void BuildBattle (COUNT which_player);
extern COUNT InitEncounter (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
extern COUNT InitCommunication (CONVERSATION which_comm);
+9 -11
View File
@@ -25,6 +25,7 @@
#include "pickship.h"
#include "process.h"
#include "globdata.h"
#include "encount.h"
#include "hyper.h"
#include "init.h"
#include "port.h"
@@ -268,7 +269,7 @@ void
UninitShips (void)
{
COUNT crew_retrieved;
SIZE i;
int i;
HELEMENT hElement, hNextElement;
STARSHIP *SPtr[NUM_PLAYERS];
@@ -325,20 +326,17 @@ UninitShips (void)
GLOBAL (CurrentActivity) &= ~IN_BATTLE;
if (LOBYTE (GLOBAL (CurrentActivity)) == IN_LAST_BATTLE)
{
}
else if (LOBYTE (GLOBAL (CurrentActivity)) <= IN_ENCOUNTER
if (LOBYTE (GLOBAL (CurrentActivity)) == IN_ENCOUNTER
&& !(GLOBAL (CurrentActivity) & CHECK_ABORT))
{
// XXX: This has no purpose for SuperMelee
// In full-game, the sole purpose of this is to record the crew
// left in the last ship standing. The crew left is first recorded
// into STARSHIP.crew_level just a few lines above here.
// Encounter battle in full game.
// Record the crew left in the last ship standing. The crew left
// is first recorded into STARSHIP.crew_level just a few lines
// above here.
for (i = NUM_PLAYERS - 1; i >= 0; --i)
{
if (SPtr[i])
GetEncounterStarShip (SPtr[i], i);
if (SPtr[i] && !FleetIsInfinite (i))
UpdateShipFragCrew (SPtr[i]);
}
}
+60 -122
View File
@@ -23,6 +23,7 @@
#include "controls.h"
#include "menustat.h"
#include "supermelee/pickmele.h"
#include "encount.h"
#include "battle.h"
#include "races.h"
#include "resinst.h"
@@ -290,7 +291,9 @@ OldContext = SetContext (SpaceContext);
if (hBattleShip)
{
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);
}
@@ -302,154 +305,89 @@ SetContext (OldContext);
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.
HSTARSHIP
GetEncounterStarShip (STARSHIP *LastStarShipPtr, COUNT which_player)
{
HSTARSHIP hBattleShip;
if (LOBYTE (GLOBAL (CurrentActivity)) == IN_HYPERSPACE)
{
// Get the next ship from the battle group.
hBattleShip = GetHeadLink (&race_q[which_player]);
assert (which_player == RPG_PLAYER_NUM);
// SIS for the Hyperspace flight
return GetHeadLink (&race_q[which_player]);
}
else if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE)
{
// Let the player chose their own ship. (May be a computer player).
HSTARSHIP hBattleShip;
if (!(GLOBAL (CurrentActivity) & IN_BATTLE))
{
// XXX: This check is needed, because UninitShips() calls
// 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 (battle_counter[0] == 0 || battle_counter[1] == 0)
{ // One side is out of ships. Game over.
return 0;
}
if (!GetNextMeleeStarShip (which_player, &hBattleShip))
return 0;
return hBattleShip;
}
else
{
// Full game.
HSHIPFRAG hStarShip;
SHIP_FRAGMENT *FragPtr;
if (LastStarShipPtr == 0)
{
// First time picking a ship.
if (which_player == 0 && battle_counter[0] > 1)
{
// The player in a full game, still having a ship left.
hBattleShip = GetArmadaStarShip ();
if (which_player == RPG_PLAYER_NUM)
{ // Human player in a full game.
if (LastStarShipPtr == 0 && battle_counter[which_player] == 1)
{ // First time picking a ship and player has no escorts
// SIS is the last ship in queue (though there is only one)
return GetTailLink (&race_q[which_player]);
}
else
{
hBattleShip = GetHeadLink (&race_q[which_player]);
if (which_player == 1)
{
// Select the next ship for the computer.
hStarShip = GetHeadLink (&GLOBAL (npc_built_ship_q));
FragPtr = LockShipFrag (&GLOBAL (npc_built_ship_q),
hStarShip);
if (FragPtr->crew_level == INFINITE_FLEET)
{
// Infinite number of ships.
battle_counter[1]++;
}
UnlockShipFrag (&GLOBAL (npc_built_ship_q), hStarShip);
else if (battle_counter[which_player])
{ // Player still has ships left
return GetArmadaStarShip ();
}
else if (LastStarShipPtr != 0)
{ // last ship was the flagship
#define RUN_AWAY_FUEL_COST (5 * FUEL_TANK_SCALE)
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 0;
}
else
{
QUEUE *pQueue;
HSHIPFRAG hNextShip;
pQueue = GetShipQueueForSide (which_player);
hBattleShip = GetHeadLink (&race_q[which_player]);
for (hStarShip = GetHeadLink (pQueue);
hStarShip != 0; hStarShip = hNextShip)
{ // NPC player in a full game
if (FleetIsInfinite (which_player))
{
STARSHIP *SPtr;
SPtr = LockStarShip (&race_q[which_player], hBattleShip);
hNextShip = _GetSuccLink (SPtr);
UnlockStarShip (&race_q[which_player], hBattleShip);
hBattleShip = hNextShip;
FragPtr = LockShipFrag (pQueue, hStarShip);
if (SPtr == LastStarShipPtr)
{
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;
if (LastStarShipPtr != 0)
{ // The current STARSHIP is reused for the next one;
// update with new info
// 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
LastStarShipPtr->crew_level = LastStarShipPtr->max_crew;
LastStarShipPtr->playerNr = which_player;
LastStarShipPtr->captains_name_index = PickCaptainName ();
}
hNextShip = _GetSuccLink (FragPtr);
UnlockShipFrag (pQueue, hStarShip);
battle_counter[which_player]++;
return GetHeadLink (&race_q[which_player]);
}
if (which_player == 0)
{
// Player in a full game.
if (battle_counter[0])
hBattleShip = GetArmadaStarShip ();
else /* last ship was flagship */
{
#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;
}
}
}
// Get the next ship for the computer
if (LastStarShipPtr != 0)
return _GetSuccLink (LastStarShipPtr);
// Get the very first ship for the computer
return GetHeadLink (&race_q[which_player]);
}
}
return (hBattleShip);
}
void
+5 -12
View File
@@ -682,24 +682,17 @@ MeleeGameOver (void)
LockMutex (GraphicsLock);
}
BOOLEAN
MeleeShipDeath (STARSHIP *ship, COUNT which_player) {
void
MeleeShipDeath (STARSHIP *ship)
{
FRAME frame;
// Deactivate fleet position.
ship->SpeciesID = NO_ID;
frame = SetAbsFrameIndex (PickMeleeFrame, which_player);
frame = SetAbsFrameIndex (PickMeleeFrame, ship->playerNr);
CrossOutShip (frame, ship->index);
UpdatePickMeleeFleetValue (frame, which_player);
if (battle_counter[0] == 0 || battle_counter[1] == 0)
{
// One side is out of ships. Game over.
return FALSE;
}
return TRUE;
UpdatePickMeleeFleetValue (frame, ship->playerNr);
}
// 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 "libs/compiler.h"
BOOLEAN MeleeShipDeath (STARSHIP *ship, COUNT which_player);
void MeleeShipDeath (STARSHIP *);
void BuildPickMeleeFrame (void);
void DestroyPickMeleeFrame (void);
void FillPickMeleeFrame (MeleeSetup *setup);
+15 -1
View File
@@ -27,6 +27,7 @@
#include "status.h"
#include "battle.h"
#include "init.h"
#include "supermelee/pickmele.h"
#ifdef NETPLAY
# include "supermelee/netplay/netmelee.h"
# include "supermelee/netplay/netmisc.h"
@@ -36,6 +37,7 @@
# include "supermelee/netplay/packetq.h"
#endif
#include "races.h"
#include "encount.h"
#include "settings.h"
#include "sounds.h"
#include "libs/mathlib.h"
@@ -279,7 +281,7 @@ new_ship (ELEMENT *DeadShipPtr)
if (DeadStarShipPtr->crew_level)
{
// 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 ();
// Even after much investigation, I could find no purpose for
@@ -339,6 +341,8 @@ new_ship (ELEMENT *DeadShipPtr)
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 =
MusicStarted ? (ONE_SECOND * 3) / BATTLE_FRAME_RATE : 1;
DeadShipPtr->death_func = new_ship;
@@ -391,6 +395,13 @@ new_ship (ELEMENT *DeadShipPtr)
}
#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))
{
#ifdef NETPLAY
@@ -574,6 +585,9 @@ ship_death (ELEMENT *ShipPtr)
PlaySound (SetAbsSoundIndex (GameSounds, SHIP_EXPLODES),
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)