From 137fdeecacb33b33c6aced8279abe2664ab2efd0 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 6 Apr 2026 00:30:48 -0700
Subject: [PATCH] Disable the play button if multiplayer setup isn't complete
---
game/gameinfo.cpp | 14 ++++++++++++++
game/gameinfo.h | 1 +
game/lobby.cpp | 28 +++++++++++++++++++++++-----
game/lobby.h | 4 ++--
4 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/game/gameinfo.cpp b/game/gameinfo.cpp
index 44cd4265..eca76276 100644
--- a/game/gameinfo.cpp
+++ b/game/gameinfo.cpp
@@ -406,6 +406,20 @@ GameInfo::IsNetworkPlayer(int index) const
return (players[index].nodeID != localID);
}
+bool
+GameInfo::HasLocalControl() const
+{
+ for (int i = 0; i < MAX_PLAYERS; ++i) {
+ if (!IsLocalPlayer(i)) {
+ continue;
+ }
+ if (IS_LOCAL_CONTROL(players[i].controlMask)) {
+ return true;
+ }
+ }
+ return false;
+}
+
int
GameInfo::GetNumPlayers() const
{
diff --git a/game/gameinfo.h b/game/gameinfo.h
index b4854cc9..dc8947b4 100644
--- a/game/gameinfo.h
+++ b/game/gameinfo.h
@@ -193,6 +193,7 @@ class GameInfo
bool IsValidPlayer(int index) const;
bool IsLocalPlayer(int index) const;
bool IsNetworkPlayer(int index) const;
+ bool HasLocalControl() const;
int GetNumPlayers() const;
bool IsFull() const;
diff --git a/game/lobby.cpp b/game/lobby.cpp
index e9a1d01a..e711ba8e 100644
--- a/game/lobby.cpp
+++ b/game/lobby.cpp
@@ -83,6 +83,8 @@ class SelectControlCallback : public UIClickCallback
}
m_game.SetPlayerSlot(m_index, name, m_controlType);
m_dialog->Hide();
+
+ m_lobby->UpdateUI();
}
private:
@@ -116,14 +118,14 @@ class ControlClickCallback : public UIClickCallback
// Show the control dialog
unsigned int num_gamepads = GetNumGamepads();
- SetControl(CONTROL_NONE, (m_index > 0) && m_game.IsHosting());
+ SetControl(CONTROL_NONE, m_game.IsHosting());
SetControl(CONTROL_LOCAL, true);
SetControl(CONTROL_JOYSTICK1, num_gamepads >= 1);
SetControl(CONTROL_JOYSTICK2, num_gamepads >= 2);
SetControl(CONTROL_JOYSTICK3, num_gamepads >= 3);
- SetControl(CONTROL_REMOTE1, (m_index > 0) && m_game.IsHosting() && GetRemotePlayerName(CONTROL_REMOTE1));
- SetControl(CONTROL_REMOTE2, (m_index > 0) && m_game.IsHosting() && GetRemotePlayerName(CONTROL_REMOTE2));
- SetControl(CONTROL_NETWORK, (m_index > 0) && m_game.IsHosting());
+ SetControl(CONTROL_REMOTE1, m_game.IsHosting() && GetRemotePlayerName(CONTROL_REMOTE1));
+ SetControl(CONTROL_REMOTE2, m_game.IsHosting() && GetRemotePlayerName(CONTROL_REMOTE2));
+ SetControl(CONTROL_NETWORK, m_game.IsHosting());
m_dialog->SetAnchor(LEFT, RIGHT, m_button, -4, 0);
m_dialog->Show();
@@ -430,7 +432,23 @@ LobbyDialogDelegate::UpdateUI()
}
if (m_state == STATE_HOSTING) {
- m_playButton->SetDisabled(false);
+ bool play_enabled = true;
+ if (m_game.IsDeathmatch()) {
+ // Make sure we have multiple players for deathmatch
+ if (m_game.GetNumPlayers() <= 1) {
+ play_enabled = false;
+ }
+ } else {
+ // Make sure there is a local player for PvE
+ if (!m_game.HasLocalControl()) {
+ play_enabled = false;
+ }
+ }
+ if (play_enabled) {
+ m_playButton->SetDisabled(false);
+ } else {
+ m_playButton->SetDisabled(true);
+ }
if (m_deathmatch) {
m_deathmatch->SetDisabled(false);
}
diff --git a/game/lobby.h b/game/lobby.h
index c9a6555d..ffc1f82c 100644
--- a/game/lobby.h
+++ b/game/lobby.h
@@ -48,6 +48,8 @@ class LobbyDialogDelegate : public UIDialogDelegate
virtual void OnPoll() override;
virtual bool HandleEvent(const SDL_Event &event) override;
+ void UpdateUI();
+
void SendKick(int index);
protected:
@@ -57,8 +59,6 @@ class LobbyDialogDelegate : public UIDialogDelegate
void DeathmatchChanged(void *, int value);
void LivesChanged(void *, const char *text);
- void UpdateUI();
-
void CheckPings();
void GetGameList();
void GetGameInfo();