diff --git a/.gitignore b/.gitignore index 976703fa9..8652c3158 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ TODO.txt resources/images/.DS_Store resources/.DS_Store .env -.prettierrc \ No newline at end of file +.prettierrc +.prettierignore \ No newline at end of file diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index 298fbaa5e..7f3ec7904 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -56,6 +56,8 @@ export interface LobbyConfig { gameID: GameID; map: GameMapType | null; difficulty: Difficulty | null; + disableBots: boolean | null; + disableNPCs: boolean | null; } export function joinLobby( @@ -77,6 +79,8 @@ export function joinLobby( gameType: GameType.Singleplayer, gameMap: lobbyConfig.map, difficulty: lobbyConfig.difficulty, + disableBots: lobbyConfig.disableBots, + disableNPCs: lobbyConfig.disableNPCs, }; } diff --git a/src/client/HostLobbyModal.ts b/src/client/HostLobbyModal.ts index 8233cd584..28dc377d7 100644 --- a/src/client/HostLobbyModal.ts +++ b/src/client/HostLobbyModal.ts @@ -9,6 +9,8 @@ export class HostLobbyModal extends LitElement { @state() private isModalOpen = false; @state() private selectedMap: GameMapType = GameMapType.World; @state() private selectedDiffculty: Difficulty = Difficulty.Medium; + @state() private disableNPCs = false; + @state() private disableBots = false; @state() private lobbyId = ""; @state() private copySuccess = false; @state() private players: string[] = []; @@ -165,6 +167,22 @@ export class HostLobbyModal extends LitElement { )} +
+ + +
+
+ + +

Players: ${this.players.join(", ")}

@@ -191,6 +209,8 @@ export class HostLobbyModal extends LitElement { }, map: this.selectedMap, difficulty: this.selectedDiffculty, + disableBots: this.disableBots, + disableNPCs: this.disableNPCs, }, bubbles: true, composed: true, @@ -226,6 +246,18 @@ export class HostLobbyModal extends LitElement { this.putGameConfig(); } + private async handleDisableBotsChange(e: Event) { + this.disableBots = Boolean((e.target as HTMLInputElement).checked); + consolex.log(`updating disable bots to ${this.disableBots}`); + this.putGameConfig(); + } + + private async handleDisableNPCsChange(e: Event) { + this.disableNPCs = Boolean((e.target as HTMLInputElement).checked); + consolex.log(`updating disable npcs to ${this.disableNPCs}`); + this.putGameConfig(); + } + private async putGameConfig() { const response = await fetch(`/private_lobby/${this.lobbyId}`, { method: "PUT", @@ -235,6 +267,8 @@ export class HostLobbyModal extends LitElement { body: JSON.stringify({ gameMap: this.selectedMap, difficulty: this.selectedDiffculty, + disableBots: this.disableBots, + disableNPCs: this.disableNPCs, }), }); } diff --git a/src/client/Main.ts b/src/client/Main.ts index dede86905..52b586cff 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -95,6 +95,8 @@ class Client { clientID: generateID(), map: event.detail.map, difficulty: event.detail.difficulty, + disableBots: event.detail.disableBots, + disableNPCs: event.detail.disableNPCs, }, () => this.joinModal.close() ); diff --git a/src/client/SinglePlayerModal.ts b/src/client/SinglePlayerModal.ts index cc3f98480..9645b25f3 100644 --- a/src/client/SinglePlayerModal.ts +++ b/src/client/SinglePlayerModal.ts @@ -9,6 +9,8 @@ export class SinglePlayerModal extends LitElement { @state() private isModalOpen = false; @state() private selectedMap: GameMapType = GameMapType.World; @state() private selectedDifficulty: Difficulty = Difficulty.Medium; + @state() private disableNPCs = false; + @state() private disableBots = false; static styles = css` .modal-overlay { @@ -115,6 +117,22 @@ export class SinglePlayerModal extends LitElement { )}
+
+ + +
+
+ + +
@@ -140,6 +158,12 @@ export class SinglePlayerModal extends LitElement { (e.target as HTMLSelectElement).value, ) as Difficulty; } + private handleDisableBotsChange(e: Event) { + this.disableBots = Boolean((e.target as HTMLInputElement).checked); + } + private handleDisableNPCsChange(e: Event) { + this.disableNPCs = Boolean((e.target as HTMLInputElement).checked); + } private startGame() { consolex.log( `Starting single player game with map: ${GameMapType[this.selectedMap]}`, @@ -153,6 +177,8 @@ export class SinglePlayerModal extends LitElement { }, map: this.selectedMap, difficulty: this.selectedDifficulty, + disableBots: this.disableBots, + disableNPCs: this.disableNPCs, }, bubbles: true, composed: true, diff --git a/src/core/GameRunner.ts b/src/core/GameRunner.ts index b9d07fcca..38bbaa244 100644 --- a/src/core/GameRunner.ts +++ b/src/core/GameRunner.ts @@ -58,9 +58,11 @@ export class GameRunner { ) {} init() { - this.game.addExecution( - ...this.execManager.spawnBots(this.game.config().numBots()) - ); + if (this.game.config().spawnBots()) { + this.game.addExecution( + ...this.execManager.spawnBots(this.game.config().numBots()) + ); + } if (this.game.config().spawnNPCs()) { this.game.addExecution(...this.execManager.fakeHumanExecutions()); } diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index 1c402ccf9..033512851 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -92,6 +92,8 @@ const GameConfigSchema = z.object({ gameMap: z.nativeEnum(GameMapType), difficulty: z.nativeEnum(Difficulty), gameType: z.nativeEnum(GameType), + disableBots: z.boolean(), + disableNPCs: z.boolean(), }); const SafeString = z diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index 1b527c327..09cd5644a 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -70,6 +70,7 @@ export interface Config { percentageTilesOwnedToWin(): number; numBots(): number; spawnNPCs(): boolean; + spawnBots(): boolean; numSpawnPhaseTurns(): number; startManpower(playerInfo: PlayerInfo): number; diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index f210a4450..7f5881410 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -76,7 +76,10 @@ export class DefaultConfig implements Config { return 5; } spawnNPCs(): boolean { - return true; + return !this._gameConfig.disableNPCs; + } + spawnBots(): boolean { + return !this._gameConfig.disableBots; } tradeShipGold(dist: number): Gold { return 10000 + 100 * Math.pow(dist, 1.1); diff --git a/src/server/GameManager.ts b/src/server/GameManager.ts index b4ff3f7c0..6a98b6f41 100644 --- a/src/server/GameManager.ts +++ b/src/server/GameManager.ts @@ -49,6 +49,8 @@ export class GameManager { gameMap: GameMapType.World, gameType: GameType.Private, difficulty: Difficulty.Medium, + disableBots: false, + disableNPCs: false, }) ); return id; @@ -87,6 +89,8 @@ export class GameManager { gameMap: this.random.randElement(Object.values(GameMapType)), gameType: GameType.Public, difficulty: Difficulty.Medium, + disableBots: false, + disableNPCs: false, }) ); } diff --git a/src/server/GameServer.ts b/src/server/GameServer.ts index df12a0013..a69acaaa6 100644 --- a/src/server/GameServer.ts +++ b/src/server/GameServer.ts @@ -57,6 +57,12 @@ export class GameServer { if (gameConfig.difficulty != null) { this.gameConfig.difficulty = gameConfig.difficulty; } + if (gameConfig.disableBots != null) { + this.gameConfig.disableBots = gameConfig.disableBots; + } + if (gameConfig.disableNPCs != null) { + this.gameConfig.disableNPCs = gameConfig.disableNPCs; + } } public addClient(client: Client, lastTurn: number) { diff --git a/src/server/Server.ts b/src/server/Server.ts index baa8030fc..90d847ef9 100644 --- a/src/server/Server.ts +++ b/src/server/Server.ts @@ -94,6 +94,8 @@ app.put("/private_lobby/:id", (req, res) => { gm.updateGameConfig(lobbyID, { gameMap: req.body.gameMap, difficulty: req.body.difficulty, + disableBots: req.body.disableBots, + disableNPCs: req.body.disableNPCs, }); });