diff --git a/TODO.txt b/TODO.txt index 8a1c40083..8f3a296f2 100644 --- a/TODO.txt +++ b/TODO.txt @@ -98,15 +98,14 @@ * BUG: attacks speed up DONE 9/6/2024 * rebalance income DONE 9/7/2024 * Make fake humans DONE 9/8/2024 -* Have fake humans join lobby -* Make more colors +* Make more colors DONE 9/8/2024 +* Have fake humans join lobby DONE 9/9/2024 * BUG: fix tile per turn pacing issues --- v3 Release * BUG: when clicking on enemy sometimes boat goes all the way around * names dissappear too much (maybe screen size) -* directed expansion * UI: win condition & popup * UI: boats * UI: current attacks diff --git a/src/client/Client.ts b/src/client/Client.ts index dc6adc39d..186f3bb91 100644 --- a/src/client/Client.ts +++ b/src/client/Client.ts @@ -1,4 +1,4 @@ -import {getConfig} from "../core/configuration/Config"; +import {Config, getConfig} from "../core/configuration/Config"; import {GameID, Lobby, ServerMessage, ServerMessageSchema} from "../core/Schemas"; import {loadTerrainMap, TerrainMap} from "../core/TerrainMapLoader"; import {ClientGame, createClientGame} from "./ClientGame"; @@ -8,6 +8,8 @@ import {v4 as uuidv4} from 'uuid'; import './styles.css'; +import {simpleHash} from "../core/Util"; +import {PseudoRandom} from "../core/PseudoRandom"; class Client { @@ -18,10 +20,13 @@ class Client { private ip: Promise = null + private config: Config + constructor() { } initialize(): void { + this.config = getConfig() setFavicon() this.terrainMap = loadTerrainMap() this.startLobbyPolling() @@ -73,7 +78,8 @@ class Client { const timeRemaining = Math.max(0, Math.floor((lobby.msUntilStart) / 1000)); timerElement.textContent = `Starts in: ${timeRemaining}s`; } - if (playerCountElement) playerCountElement.textContent = `Players: ${lobby.numClients}`; + + if (playerCountElement) playerCountElement.textContent = `Players: ${lobby.numClients + this.numFakeHumans(lobby)}`; if (lobbies.length > 1) { const nextLobby = lobbies[1] @@ -124,7 +130,7 @@ class Client { uuidv4(), clientIP, lobby.id, - getConfig(), + this.config, terrainMap ); this.game.join(); @@ -134,6 +140,28 @@ class Client { g.stop(); }); } + + numFakeHumans(lobby: Lobby): number { + const gameHash = simpleHash(lobby.id) + const totalNumFakeHumans = this.config.numFakeHumans(lobby.id) + const timeLeft = lobby.msUntilStart + const rand = new PseudoRandom(gameHash) + const startTimes: number[] = [] + const lobbyTime = this.config.lobbyLifetime() / this.config.gameCreationRate() + for (let i = 0; i < totalNumFakeHumans; i++) { + startTimes.push(rand.nextInt(0, lobbyTime)) + } + + startTimes.sort() + + let currNumFakeHumans = 0 + for (const joinTime of startTimes) { + if (timeLeft < joinTime) { + currNumFakeHumans++ + } + } + return currNumFakeHumans + } } function getUsername(): string { diff --git a/src/client/ClientGame.ts b/src/client/ClientGame.ts index a0800bfc5..ce81f1523 100644 --- a/src/client/ClientGame.ts +++ b/src/client/ClientGame.ts @@ -133,7 +133,7 @@ export class ClientGame { this.input.initialize() this.gs.addExecution(...this.executor.spawnBots(this.gs.config().numBots())) console.log('!!! number fake humans 15') - this.gs.addExecution(...this.executor.fakeHumanExecutions(15)) + this.gs.addExecution(...this.executor.fakeHumanExecutions(this.gs.config().numFakeHumans(this.gameID))) this.intervalID = setInterval(() => this.tick(), 10); } diff --git a/src/client/graphics/TerritoryRenderer.ts b/src/client/graphics/TerritoryRenderer.ts index c543adad2..f9aa3c289 100644 --- a/src/client/graphics/TerritoryRenderer.ts +++ b/src/client/graphics/TerritoryRenderer.ts @@ -106,7 +106,7 @@ export class TerritoryRenderer { this.paintCell( tile.cell(), this.theme.territoryColor(tile.owner().id()), - 60 + 70 ) } } diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index f853aa769..542e2634e 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -2,6 +2,7 @@ import {Player, PlayerID, PlayerInfo, TerraNullius, Tile} from "../Game"; import {Colord, colord} from "colord"; import {devConfig} from "./DevConfig"; import {defaultConfig} from "./DefaultConfig"; +import {GameID} from "../Schemas"; export enum GameEnv { Dev, @@ -29,6 +30,7 @@ export interface Config { gameCreationRate(): number lobbyLifetime(): number numBots(): number + numFakeHumans(gameID: GameID): number numSpawnPhaseTurns(): number startTroops(playerInfo: PlayerInfo): number diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 594ac7e30..62ddbff6f 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -1,5 +1,6 @@ import {Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile} from "../Game"; -import {within} from "../Util"; +import {GameID} from "../Schemas"; +import {simpleHash, within} from "../Util"; import {Config, Theme} from "./Config"; import {pastelTheme} from "./PastelTheme"; @@ -18,6 +19,9 @@ export class DefaultConfig implements Config { numBots(): number { return 400 } + numFakeHumans(gameID: GameID): number { + return simpleHash(gameID) % 3 + } turnIntervalMs(): number { return 100 }