Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions backend/src/main/java/server/SecretHitlerServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class SecretHitlerServer {
public static final String PARAM_VETO = "veto";
public static final String PARAM_CHOICE = "choice"; // the index of the chosen policy.
public static final String PARAM_ICON = "icon";
public static final String PARAM_MIN_LOBBY_SIZE = "minLobbySize";

// Passed to client
// The type of the packet tells the client how to parse the contents.
Expand Down Expand Up @@ -694,6 +695,14 @@ private static void onWebSocketMessage(WsMessageContext ctx) {
String iconId = message.getString(PARAM_ICON);
lobby.trySetUserIcon(iconId, ctx);
break;

case COMMAND_SET_LOBBY_SIZE:
// Ensure the game hasn't started yet
if (!lobby.isInGame()) {
int newSize = message.getInt("size");
lobby.setMinLobbySize(newSize);
}
break;

default: // This is an invalid command.
throw new RuntimeException("unrecognized command " + message.get(PARAM_COMMAND));
Expand Down
14 changes: 11 additions & 3 deletions backend/src/main/java/server/util/Lobby.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ public class Lobby implements Serializable {

static String DEFAULT_ICON = "p_default";

private int minLobbySize = SecretHitlerGame.MIN_PLAYERS;
synchronized public void setMinLobbySize(int size) {
if (size >= SecretHitlerGame.MIN_PLAYERS && size <= SecretHitlerGame.MAX_PLAYERS) {
this.minLobbySize = size;
}
}

/**
* Constructs a new Lobby.
*/
Expand Down Expand Up @@ -392,6 +399,7 @@ synchronized public void updateUser(WsContext ctx, String userName) {
message = new JSONObject();
message.put(SecretHitlerServer.PARAM_PACKET_TYPE, SecretHitlerServer.PACKET_LOBBY);
message.put("usernames", activeUsernames.toArray());
message.put(SecretHitlerServer.PARAM_MIN_LOBBY_SIZE, minLobbySize);
}
// Add user icons to the update message
JSONObject icons = new JSONObject(usernameToIcon);
Expand Down Expand Up @@ -494,11 +502,11 @@ synchronized public void startNewGame() {
usersInGame.clear();
usersInGame.addAll(userToUsername.values());

// Generate CpuPlayers if the lobby size has not been met
// Generate CpuPlayers if the target lobby size has not been met
List<String> cpuNames = new ArrayList<>();
cpuPlayers.clear();
if (usersInGame.size() < SecretHitlerGame.MIN_PLAYERS) {
int numCpuPlayersToGenerate = SecretHitlerGame.MIN_PLAYERS - usersInGame.size();
if (usersInGame.size() < minLobbySize) {
int numCpuPlayersToGenerate = minLobbySize - usersInGame.size();
int i = 1;
while (numCpuPlayersToGenerate > 0) {
String botName = "Bot " + i;
Expand Down
40 changes: 39 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
SERVER_PING,
PARAM_ICON,
PARAM_INVESTIGATION,
PARAM_MIN_LOBBY_SIZE,
} from "./constants";

import PlayerDisplay, {
Expand Down Expand Up @@ -146,6 +147,7 @@ type AppState = {
lobbyFromURL: boolean;
usernames: string[];
icons: { [key: string]: string };
minLobbySize: number;
gameState: GameState;
/* Stores the last gameState[PARAM_STATE] value to check for changes. */
lastState: any;
Expand Down Expand Up @@ -177,6 +179,7 @@ const defaultAppState: AppState = {
lobbyFromURL: false,
usernames: [],
icons: {},
minLobbySize: 5,
gameState: DEFAULT_GAME_STATE,
lastState: {},
liberalPolicies: 0,
Expand Down Expand Up @@ -429,6 +432,7 @@ class App extends Component<{}, AppState> {
usernames: message[PARAM_USERNAMES],
icons: message[PARAM_ICON],
page: PAGE.LOBBY,
minLobbySize: message[PARAM_MIN_LOBBY_SIZE] || 5,
});
if (message[PARAM_ICON][this.state.name] === defaultPortrait) {
this.showChangeIconAlert();
Expand Down Expand Up @@ -918,7 +922,7 @@ class App extends Component<{}, AppState> {
<div id={"lobby-player-area-container"}>
<div id={"lobby-player-text-choose-container"}>
<p id={"lobby-player-count-text"}>
Players ({this.state.usernames.length}/10)
Players ({this.state.usernames.length}/{this.state.minLobbySize})
</p>
<button
id={"lobby-change-icon-button"}
Expand All @@ -927,6 +931,40 @@ class App extends Component<{}, AppState> {
CHANGE ICON
</button>
</div>

<div style={{ marginBottom: "15px", display: "flex", flexDirection: "column", alignItems: "flex-start" }}>
{isVIP ? (
<>
<label style={{ color: "white", display: "flex", alignItems: "center", cursor: "pointer" }}>
<span style={{ marginRight: "10px" }}>Game Size:</span>
<select
value={this.state.minLobbySize}
onChange={(e) => this.sendWSCommand({
command: WSCommandType.SET_LOBBY_SIZE,
size: parseInt(e.target.value)
})}
style={{ padding: "5px", borderRadius: "4px", backgroundColor: "#333", color: "white", border: "1px solid #555", cursor: "pointer" }}
>
{[5, 6, 7, 8, 9, 10].map(n => (
<option key={n} value={n}>
{n === 10 ? "10 Players" : `${n}+ Players`}
</option>
))}
</select>
</label>
<span style={{ color: "#aaaaaa", fontSize: "0.8em", marginTop: "4px" }}>
(Empty spots will be filled by bots)
</span>
</>
) : (
<p style={{ color: "gray", fontSize: "0.9em", margin: 0 }}>
Game Size: {this.state.minLobbySize === 10 ? "10 Players" : `${this.state.minLobbySize}+ Players`}
<br/>
<span style={{ fontSize: "0.9em" }}>(Empty spots will be filled by bots)</span>
</p>
)}
</div>

<div id={"lobby-player-container"}>{this.renderPlayerList()}</div>
</div>

Expand Down
1 change: 1 addition & 0 deletions frontend/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export const STATE_FASCIST_VICTORY_ELECTION = "FASCIST_VICTORY_ELECTION"; // Fas
// Lobby
export const PARAM_USER_COUNT = "user-count";
export const PARAM_USERNAMES = "usernames";
export const PARAM_MIN_LOBBY_SIZE = "minLobbySize";

// Peek
export const PARAM_PEEK = "peek";
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/types/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const enum WSCommandType {
PING = "ping",
START_GAME = "start-game",
GET_STATE = "get-state",
SET_LOBBY_SIZE = "set-lobby-size",
REGISTER_CHANCELLOR_VETO = "chancellor-veto",
REGISTER_PRESIDENT_VETO = "president-veto",
REGISTER_PEEK = "register-peek",
Expand All @@ -25,6 +26,7 @@ export const enum WSCommandType {
export type ServerRequestPayload =
| { command: WSCommandType.PING }
| { command: WSCommandType.START_GAME }
| { command: WSCommandType.SET_LOBBY_SIZE; size: number }
| { command: WSCommandType.GET_STATE }
| { command: WSCommandType.REGISTER_CHANCELLOR_VETO }
| { command: WSCommandType.REGISTER_PRESIDENT_VETO; veto: boolean }
Expand Down