https://github.com/libsdl-org/Maelstrom/commit/458181e3fb1aff75c43d8af3d164e5a5667b0c9d
From 458181e3fb1aff75c43d8af3d164e5a5667b0c9d Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 17 Nov 2011 01:50:02 -0500
Subject: [PATCH] The GameInfo structure is the canonical place for the game
parameters. This will allow us to serialize this information for replays and
maybe let us show more interesting information in the lobby.
---
game/Maelstrom.h | 4 +++
game/Maelstrom_Globals.h | 7 ++---
game/about.cpp | 2 --
game/game.cpp | 30 ++++++++++---------
game/gameinfo.cpp | 38 +++++++++++++++++++++++-
game/gameinfo.h | 10 +++++--
game/lobby.cpp | 19 ++++++++----
game/lobby.h | 2 +-
game/main.cpp | 29 ++++++++++--------
game/netplay.cpp | 64 +++++++++++++++-------------------------
game/netplay.h | 5 ++--
game/player.cpp | 12 ++++----
game/player.h | 2 +-
game/protocol.h | 2 +-
14 files changed, 131 insertions(+), 95 deletions(-)
diff --git a/game/Maelstrom.h b/game/Maelstrom.h
index 36f6af0d..aea32e54 100644
--- a/game/Maelstrom.h
+++ b/game/Maelstrom.h
@@ -37,6 +37,10 @@
#define FRAME_DELAY 2
#define FRAME_DELAY_MS ((FRAME_DELAY*1000)/60)
+#define DEFAULT_START_WAVE 1
+#define DEFAULT_START_LIVES 3
+#define DEFAULT_START_TURBO 0
+
#define MAX_SPRITES 100
#define MAX_SPRITE_FRAMES 60
#define MAX_STARS 30
diff --git a/game/Maelstrom_Globals.h b/game/Maelstrom_Globals.h
index fa8fd07f..6a4e46e1 100644
--- a/game/Maelstrom_Globals.h
+++ b/game/Maelstrom_Globals.h
@@ -40,6 +40,7 @@
#include "fastrand.h"
#include "scores.h"
#include "controls.h"
+#include "gameinfo.h"
// Preferences keys
#define PREFERENCES_HANDLE "Handle"
@@ -93,7 +94,6 @@ extern void SetStar(int which);
// in main.cpp :
extern Bool gUpdateBuffer;
extern Bool gRunning;
-extern int gNoDelay;
// in init.cpp :
extern Sint32 gLastHigh;
@@ -143,9 +143,8 @@ extern PrefsVariable<int> gGammaCorrect;
extern Scores hScores[];
// -- Variables specific to each game
-// in main.cpp :
-extern int gStartLives;
-extern int gStartLevel;
+// in game.cpp :
+extern GameInfo gGameInfo;
// in init.cpp :
extern Uint32 gLastDrawn;
extern int gNumSprites;
diff --git a/game/about.cpp b/game/about.cpp
index e207dc56..23232b5e 100644
--- a/game/about.cpp
+++ b/game/about.cpp
@@ -30,8 +30,6 @@ AboutPanelDelegate::OnShow()
{
int x, y, off;
- gNoDelay = 0;
-
x = (80) * SCALE_FACTOR;
y = (136) * SCALE_FACTOR;
off = 39 * SCALE_FACTOR;
diff --git a/game/game.cpp b/game/game.cpp
index 9e92a896..339ac43f 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -30,6 +30,7 @@
#include "../screenlib/UIElement.h"
// Global variables set in this file...
+GameInfo gGameInfo;
int gScore;
int gGameOn;
int gPaused;
@@ -66,15 +67,16 @@ void NewGame(void)
if ( CheckPlayers() < 0 )
return;
+ /* Start up the random number generator */
+ SeedRandom(gGameInfo.seed);
+
/* Send a "NEW_GAME" packet onto the network */
if ( gNumPlayers > 1 ) {
if ( gOurPlayer == 0 ) {
- if ( Send_NewGame(&gStartLevel,&gStartLives,&gNoDelay)
- < 0)
+ if ( Send_NewGame() < 0)
return;
} else {
- if ( Await_NewGame(&gStartLevel,&gStartLives,&gNoDelay)
- < 0 )
+ if ( Await_NewGame() < 0 )
return;
}
}
@@ -92,7 +94,7 @@ void NewGame(void)
screen->FadeIn();
/* Timing handling -- Delay the FRAME_DELAY */
- if ( ! gNoDelay ) {
+ if ( ! gGameInfo.turbo ) {
DelayFrame();
}
}
@@ -151,9 +153,9 @@ GamePanelDelegate::OnShow()
/* Initialize some game variables */
gGameOn = 1;
gPaused = 0;
- gWave = gStartLevel - 1;
+ gWave = gGameInfo.wave - 1;
for ( i=gNumPlayers; i--; )
- gPlayers[i]->NewGame(gStartLives);
+ gPlayers[i]->NewGame(gGameInfo.lives, gGameInfo.deathMatch);
gLastStar = STAR_DELAY;
gLastDrawn = 0L;
gNumSprites = 0;
@@ -173,7 +175,7 @@ GamePanelDelegate::OnShow()
m_multiplayerColor->Hide();
}
}
- if ( gDeathMatch ) {
+ if ( gGameInfo.deathMatch ) {
if (m_fragsLabel) {
m_fragsLabel->Show();
}
@@ -261,7 +263,7 @@ GamePanelDelegate::OnTick()
gSprites[i] = gSprites[gNumSprites];
}
}
- if ( gDeathMatch ) {
+ if ( gGameInfo.deathMatch ) {
OBJ_LOOP(i, gNumPlayers) {
if ( i == j ) // Don't shoot ourselves. :)
continue;
@@ -736,7 +738,7 @@ GamePanelDelegate::NextWave()
gShakeTime = 0;
gFreezeTime = 0;
- if (gWave != (gStartLevel - 1))
+ if (gWave != (gGameInfo.wave - 1))
DoBonus();
gWave++;
@@ -866,7 +868,7 @@ static void DoGameOver(void)
final[i].Score = gPlayers[i]->GetScore();
final[i].Frags = gPlayers[i]->GetFrags();
}
- if ( gDeathMatch )
+ if ( gGameInfo.deathMatch )
qsort(final,gNumPlayers,sizeof(struct FinalScore),cmp_byfrags);
else
qsort(final,gNumPlayers,sizeof(struct FinalScore),cmp_byscore);
@@ -893,7 +895,7 @@ static void DoGameOver(void)
if (!label) {
continue;
}
- if (gDeathMatch) {
+ if (gGameInfo.deathMatch) {
sprintf(num1, "%7d", final[i].Score);
sprintf(num2, "%3d", final[i].Frags);
sprintf(buffer, "Player %d: %s Points, %s Frags", final[i].Player, num1, num2);
@@ -925,8 +927,8 @@ static void DoGameOver(void)
/* -- They got a high score! */
gLastHigh = which;
- if ((which != -1) && (gStartLevel == 1) && (gStartLives == 3) &&
- (gNumPlayers == 1) && !gDeathMatch ) {
+ if ((which != -1) && (gNumPlayers == 1) &&
+ (gGameInfo.wave == 1) && (gGameInfo.lives == 3)) {
sound->PlaySound(gBonusShot, 5);
/* -- Let them enter their name */
diff --git a/game/gameinfo.cpp b/game/gameinfo.cpp
index 5f4ebfb6..aff77464 100644
--- a/game/gameinfo.cpp
+++ b/game/gameinfo.cpp
@@ -35,9 +35,25 @@ GameInfo::Reset()
}
void
-GameInfo::SetHostInfo(Uint32 gameID, const char *name)
+GameInfo::SetSinglePlayer(Uint8 wave, Uint8 lives, Uint8 turbo)
+{
+ this->gameID = 1;
+ this->seed = GetRandSeed();
+ this->wave = wave;
+ this->lives = lives;
+ this->turbo = turbo;
+ this->deathMatch = 0;
+}
+
+void
+GameInfo::SetMultiplayerHost(Uint32 gameID, const char *name)
{
this->gameID = gameID;
+ this->seed = GetRandSeed();
+ this->wave = DEFAULT_START_WAVE;
+ this->lives = DEFAULT_START_LIVES;
+ this->turbo = DEFAULT_START_TURBO;
+ this->deathMatch = 0;
players[HOST_PLAYER].playerID = gameID;
SDL_strlcpy(players[HOST_PLAYER].name, name ? name : "",
sizeof(players[HOST_PLAYER].name));
@@ -47,6 +63,10 @@ void
GameInfo::CopyFrom(const GameInfo &rhs)
{
gameID = rhs.gameID;
+ seed = rhs.seed;
+ wave = rhs.wave;
+ lives = rhs.lives;
+ turbo = rhs.turbo;
deathMatch = rhs.deathMatch;
for (int i = 0; i < MAX_PLAYERS; ++i) {
@@ -69,6 +89,18 @@ GameInfo::ReadFromPacket(DynamicPacket &packet)
if (!packet.Read(gameID)) {
return false;
}
+ if (!packet.Read(seed)) {
+ return false;
+ }
+ if (!packet.Read(wave)) {
+ return false;
+ }
+ if (!packet.Read(lives)) {
+ return false;
+ }
+ if (!packet.Read(turbo)) {
+ return false;
+ }
if (!packet.Read(deathMatch)) {
return false;
}
@@ -101,6 +133,10 @@ void
GameInfo::WriteToPacket(DynamicPacket &packet)
{
packet.Write(gameID);
+ packet.Write(seed);
+ packet.Write(wave);
+ packet.Write(lives);
+ packet.Write(turbo);
packet.Write(deathMatch);
for (int i = 0; i < MAX_PLAYERS; ++i) {
diff --git a/game/gameinfo.h b/game/gameinfo.h
index 639a4422..864cc1f7 100644
--- a/game/gameinfo.h
+++ b/game/gameinfo.h
@@ -82,12 +82,14 @@ class GameInfo
void Reset();
+ void SetSinglePlayer(Uint8 wave, Uint8 lives, Uint8 turbo);
+
+ void SetMultiplayerHost(Uint32 gameID, const char *name);
+
void SetLocalID(Uint32 playerID) {
localID = playerID;
}
- void SetHostInfo(Uint32 gameID, const char *name);
-
void CopyFrom(const GameInfo &rhs);
bool ReadFromPacket(DynamicPacket &packet);
@@ -164,6 +166,10 @@ class GameInfo
public:
Uint32 gameID;
+ Uint32 seed;
+ Uint8 wave;
+ Uint8 lives;
+ Uint8 turbo;
Uint8 deathMatch;
GameInfoPlayer players[MAX_PLAYERS];
diff --git a/game/lobby.cpp b/game/lobby.cpp
index 33a742f7..3b244ed4 100644
--- a/game/lobby.cpp
+++ b/game/lobby.cpp
@@ -42,7 +42,8 @@
LobbyDialogDelegate::LobbyDialogDelegate(UIPanel *panel) :
- UIDialogDelegate(panel)
+ UIDialogDelegate(panel),
+ m_game(gGameInfo)
{
m_state = STATE_NONE;
m_uniqueID = 0;
@@ -155,10 +156,6 @@ LobbyDialogDelegate::OnHide()
// Start the game!
if (m_dialog->GetDialogStatus() > 0) {
SetState(STATE_PLAYING);
- gStartLevel = 1;
- gStartLives = 3;
- gNoDelay = 0;
- gDeathMatch = m_game.deathMatch;
for (int i = 0; i < MAX_PLAYERS; ++i) {
GameInfoPlayer *player = m_game.GetPlayer(i);
@@ -327,7 +324,7 @@ LobbyDialogDelegate::SetState(LOBBY_STATE state)
SendLeaveRequest();
}
} else if (state == STATE_HOSTING) {
- m_game.SetHostInfo(m_uniqueID, prefs->GetString(PREFERENCES_HANDLE));
+ m_game.SetMultiplayerHost(m_uniqueID, prefs->GetString(PREFERENCES_HANDLE));
} else if (state == STATE_LISTING) {
ClearGameList();
}
@@ -659,6 +656,16 @@ LobbyDialogDelegate::ProcessPong(DynamicPacket &packet)
void
LobbyDialogDelegate::ProcessNewGame(DynamicPacket &packet)
{
+ Uint8 playerIndex;
+ Uint32 gameID;
+
+ if (!packet.Read(playerIndex)) {
+ return;
+ }
+ if (!packet.Read(gameID) || gameID != m_game.gameID) {
+ return;
+ }
+
// Ooh, ooh, they're starting!
if (m_game.HasPlayer(packet.address)) {
m_playButton->OnClick();
diff --git a/game/lobby.h b/game/lobby.h
index 760c064e..562dac25 100644
--- a/game/lobby.h
+++ b/game/lobby.h
@@ -102,7 +102,7 @@ class LobbyDialogDelegate : public UIDialogDelegate
Uint32 m_lastRefresh;
Uint32 m_requestSequence;
- GameInfo m_game;
+ GameInfo &m_game;
array<GameInfo> m_gameList;
DynamicPacket m_packet, m_reply;
diff --git a/game/main.cpp b/game/main.cpp
index 9d2e7daf..b4f3b9c6 100644
--- a/game/main.cpp
+++ b/game/main.cpp
@@ -53,11 +53,8 @@ static const char *Version =
"Maelstrom v1.4.3 (GPL version 4.0.0) -- 10/08/2011 by Sam Lantinga\n";
// Global variables set in this file...
-int gStartLives;
-int gStartLevel;
Bool gUpdateBuffer;
Bool gRunning;
-int gNoDelay;
// Main Menu actions:
@@ -75,9 +72,9 @@ static void RunSinglePlayerGame()
}
static void RunPlayGame(void*)
{
- gStartLevel = 1;
- gStartLives = 3;
- gNoDelay = 0;
+ gGameInfo.SetSinglePlayer(DEFAULT_START_WAVE,
+ DEFAULT_START_LIVES,
+ DEFAULT_START_TURBO);
RunSinglePlayerGame();
}
static void RunQuitGame(void*)
@@ -135,30 +132,36 @@ static void CheatDialogDone(UIDialog *dialog, int status)
{
UIElementEditbox *editbox;
UIElementCheckbox *checkbox;
+ Uint8 wave = DEFAULT_START_WAVE;
+ Uint8 lives = DEFAULT_START_LIVES;
+ Uint8 turbo = DEFAULT_START_TURBO;
if (status > 0) {
editbox = dialog->GetElement<UIElementEditbox>("level");
if (editbox) {
- gStartLevel = editbox->GetNumber();
- if (gStartLevel < 1 || gStartLevel > 40) {
- return;
+ wave = editbox->GetNumber();
+ if (wave < 1 || wave > 40) {
+ wave = DEFAULT_START_WAVE;
}
}
editbox = dialog->GetElement<UIElementEditbox>("lives");
if (editbox) {
- gStartLives = editbox->GetNumber();
- if (gStartLives < 1 || gStartLives > 40) {
- gStartLives = 3;
+ lives = editbox->GetNumber();
+ if (lives < 1 || lives > 40) {
+ lives = DEFAULT_START_LIVES;
}
}
checkbox = dialog->GetElement<UIElementCheckbox>("turbofunk");
- gNoDelay = checkbox->IsChecked();
+ if (checkbox) {
+ turbo = checkbox->IsChecked();
+ }
Delay(SOUND_DELAY);
sound->PlaySound(gNewLife, 5);
Delay(SOUND_DELAY);
+ gGameInfo.SetSinglePlayer(wave, lives, turbo);
RunSinglePlayerGame();
}
}
diff --git a/game/netplay.cpp b/game/netplay.cpp
index 6e2840dd..cdca7eb3 100644
--- a/game/netplay.cpp
+++ b/game/netplay.cpp
@@ -34,7 +34,6 @@
int gNumPlayers;
int gOurPlayer;
-int gDeathMatch;
UDPsocket gNetFD;
static int GotPlayer[MAX_PLAYERS];
@@ -113,7 +112,6 @@ int InitNetData(bool hosting)
/* Initialize network game variables */
FoundUs = 0;
gOurPlayer = -1;
- gDeathMatch = 0;
for ( i=0; i<MAX_PLAYERS; ++i ) {
GotPlayer[i] = 0;
SyncPtrs[0][i] = NULL;
@@ -192,9 +190,9 @@ int CheckPlayers(void)
gOurPlayer+1, gNumPlayers);
return(-1);
}
- if ( (gNumPlayers == 1) && gDeathMatch ) {
+ if ( (gNumPlayers == 1) && gGameInfo.deathMatch ) {
error("Warning: No deathmatch in a single player game!\r\n");
- gDeathMatch = 0;
+ gGameInfo.deathMatch = 0;
}
/* Now, so we can send to ourselves... */
@@ -365,13 +363,10 @@ error("Warning! Received packet for really old frame! (%lu, current = %lu)\r\n",
/* Do a consistency check!! */
Uint32 newseed = SDLNet_Read32(&buf[1+sizeof(frame)]);
if ( newseed != seed ) {
-//error("New seed (from player %d) is: 0x%x\r\n", index+1, newseed);
- if ( gOurPlayer == 0 ) {
- error(
-"Warning!! \a Frame consistency error with player %d!! (corrected)\r\n", index+1);
-SDL_Delay(3000);
- } else /* Player 1 sent us good seed */
- SeedRandom(newseed);
+ /* We're hosed, to correct this we would have to sync the complete game state */
+ error(
+"Error!! \a Frame consistency error with player %d!!\r\n", index+1);
+ return(-1);
}
/* Okay, we finally have a valid timely packet */
@@ -423,20 +418,11 @@ inline void SuckPackets(void)
}
}
-static inline void MakeNewPacket(int Wave, int Lives, int Turbo,
- unsigned char *packet)
+static inline void MakeNewPacket(Uint32 gameID, unsigned char *packet)
{
*packet++ = NEW_GAME;
*packet++ = gOurPlayer;
- *packet++ = (unsigned char)Turbo;
- SDLNet_Write32(Wave, packet);
- packet += 4;
- if ( gDeathMatch ) {
- Lives = (gDeathMatch|0x8000);
- }
- SDLNet_Write32(Lives, packet);
- packet += 4;
- SDLNet_Write32(GetRandSeed(), packet);
+ SDLNet_Write32(gameID, packet);
}
/* Flash an error up on the screen and pause for 3 seconds */
@@ -449,13 +435,13 @@ static void ErrorMessage(const char *message)
SDL_Delay(3000);
}
-/* This function sends a NEWGAME packet, and waits for all other players
+/* This function sends a NEW_GAME packet, and waits for all other players
to respond in kind.
This function is not very robust in handling errors such as multiple
machines thinking they are the same player. The address server is
supposed to handle such things gracefully.
*/
-int Send_NewGame(int *Wave, int *Lives, int *Turbo)
+int Send_NewGame()
{
Uint8 netbuf[BUFSIZ], sendbuf[NEW_PACKETLEN];
char message[BUFSIZ];
@@ -465,7 +451,7 @@ int Send_NewGame(int *Wave, int *Lives, int *Turbo)
UDPpacket newgame, sent;
/* Send all the packets */
- MakeNewPacket(*Wave, *Lives, *Turbo, sendbuf);
+ MakeNewPacket(gGameInfo.gameID, sendbuf);
newgame.data = sendbuf;
newgame.len = sizeof(sendbuf);
SDLNet_UDP_Send(gNetFD, 0, &newgame);
@@ -526,6 +512,12 @@ int Send_NewGame(int *Wave, int *Lives, int *Turbo)
continue;
}
+ Uint32 gameID = SDLNet_Read32(&netbuf[2]);
+ if (gameID != gGameInfo.gameID) {
+ /* This must be for a different game */
+ continue;
+ }
+
/* Loop, check the address */
for ( i=gNumPlayers; i--; ) {
if ( acked[i] )
@@ -557,7 +549,7 @@ int Send_NewGame(int *Wave, int *Lives, int *Turbo)
return(0);
}
-int Await_NewGame(int *Wave, int *Lives, int *Turbo)
+int Await_NewGame()
{
unsigned char netbuf[BUFSIZ];
int len, gameon;
@@ -602,21 +594,11 @@ int Await_NewGame(int *Wave, int *Lives, int *Turbo)
continue;
}
- /* Extract the RandomSeed and return the packet */
- *Turbo = (int)netbuf[2];
- len = 3;
- *Wave = SDLNet_Read32(&netbuf[len]);
- len += 4;
- lives = SDLNet_Read32(&netbuf[len]);
- len += 4;
- if ( lives & 0x8000 )
- gDeathMatch = (lives&(~0x8000));
- else
- *Lives = lives;
- seed = SDLNet_Read32(&netbuf[len]);
- len += 4;
- SeedRandom(seed);
-//error("Seed is 0x%x\r\n", seed);
+ Uint32 gameID = SDLNet_Read32(&netbuf[2]);
+ if (gameID != gGameInfo.gameID) {
+ /* This must be for a different game */
+ continue;
+ }
netbuf[1] = gOurPlayer;
SDLNet_UDP_Send(gNetFD, 1, &sent);
diff --git a/game/netplay.h b/game/netplay.h
index 65211462..ded9463e 100644
--- a/game/netplay.h
+++ b/game/netplay.h
@@ -32,11 +32,10 @@ extern int CheckPlayers(void);
extern void QueueKey(unsigned char Op, unsigned char Type);
extern int SyncNetwork(void);
extern int GetSyncBuf(int index, unsigned char **bufptr);
-extern int Send_NewGame(int *Wave, int *Lives, int *Turbo);
-extern int Await_NewGame(int *Wave, int *Lives, int *Turbo);
+extern int Send_NewGame();
+extern int Await_NewGame();
/* Variables from netplay.cpp */
extern int gOurPlayer;
extern int gNumPlayers;
-extern int gDeathMatch;
extern UDPsocket gNetFD;
diff --git a/game/player.cpp b/game/player.cpp
index 5a59fbb8..4b2ad845 100644
--- a/game/player.cpp
+++ b/game/player.cpp
@@ -73,10 +73,10 @@ Player::~Player()
/* Note that the lives argument is ignored during deathmatches */
void
-Player::NewGame(int lives)
+Player::NewGame(int lives, int deathMatch)
{
Playing = 1;
- if ( gDeathMatch )
+ if ( deathMatch )
Lives = 1;
else
Lives = lives;
@@ -146,7 +146,7 @@ Player::NewShip(void)
Dead = 0;
Exploding = 0;
Set_TTL(-1);
- if ( ! gDeathMatch )
+ if ( ! gGameInfo.deathMatch )
--Lives;
return(Lives);
}
@@ -156,7 +156,7 @@ void
Player::IncrFrags(void)
{
++Frags;
- if ( gDeathMatch && (Frags >= gDeathMatch) ) {
+ if ( gGameInfo.deathMatch && (Frags >= gGameInfo.deathMatch) ) {
/* Game over, we got a stud. :) */
int i;
OBJ_LOOP(i, gNumPlayers) {
@@ -172,7 +172,7 @@ error("Killing player %d\n", i+1);
void
Player::IncrLives(int lives)
{
- if ( gDeathMatch && (lives > 0) )
+ if ( gGameInfo.deathMatch && (lives > 0) )
return;
Lives += lives;
}
@@ -245,7 +245,7 @@ Player::BeenTimedOut(void)
*SCALE_FACTOR),
((SCREEN_HEIGHT/2)*SCALE_FACTOR)
);
- if ( gDeathMatch )
+ if ( gGameInfo.deathMatch )
Dead = (DEAD_DELAY/2);
else
Dead = DEAD_DELAY;
diff --git a/game/player.h b/game/player.h
index 42761203..f7fdffc5 100644
--- a/game/player.h
+++ b/game/player.h
@@ -46,7 +46,7 @@ class Player : public Object {
virtual int Kicking(void) {
return(Playing);
}
- virtual void NewGame(int lives);
+ virtual void NewGame(int lives, int deathMatch);
virtual void NewWave(void);
/* NewShip() MUST be called before Move() */
virtual int NewShip(void);
diff --git a/game/protocol.h b/game/protocol.h
index 08654dab..23a64698 100644
--- a/game/protocol.h
+++ b/game/protocol.h
@@ -191,7 +191,7 @@ enum LobbyProtocol {
#define NETPLAY_PORT 0xAF00 /* port 44800 */
/* The minimum length of a new packet buffer */
-#define NEW_PACKETLEN (3+3*4)
+#define NEW_PACKETLEN (1+1+sizeof(Uint32))
/* Note: if you change MAX_PLAYERS, you need to modify the gPlayerColors
array in player.cpp