From d12ebc5f4b51b280fa678d112618ea27845f881e Mon Sep 17 00:00:00 2001 From: evanpelle Date: Fri, 16 Aug 2024 14:48:51 -0700 Subject: [PATCH] increased game length, balanced attacks --- TODO.txt | 3 +- src/client/ClientGame.ts | 2 +- src/core/Util.ts | 4 +++ src/core/configuration/Config.ts | 2 +- src/core/configuration/DefaultConfig.ts | 29 ++++++++++------ src/core/execution/AttackExecution.ts | 44 ++++++++++++++++--------- src/core/execution/BotExecution.ts | 4 +-- src/server/GameServer.ts | 2 +- 8 files changed, 59 insertions(+), 31 deletions(-) diff --git a/TODO.txt b/TODO.txt index d1349cf20..9a8839e15 100644 --- a/TODO.txt +++ b/TODO.txt @@ -32,4 +32,5 @@ * make coasts look better * add shader to dim border * remove player.info() -* fix enemy islands when attacking +* fix enemy islands when attacking +* BUG: ocean is considered TerraNullius diff --git a/src/client/ClientGame.ts b/src/client/ClientGame.ts index 0eab10379..2fba196c5 100644 --- a/src/client/ClientGame.ts +++ b/src/client/ClientGame.ts @@ -110,7 +110,7 @@ export class ClientGame { this.renderer.initialize() this.input.initialize() - this.executor.spawnBots(1000) + this.executor.spawnBots(this.config.numBots()) this.intervalID = setInterval(() => this.tick(), 10); diff --git a/src/core/Util.ts b/src/core/Util.ts index 914fc3b38..1ddd5fe43 100644 --- a/src/core/Util.ts +++ b/src/core/Util.ts @@ -2,4 +2,8 @@ import {Cell} from "./Game"; export function manhattanDist(c1: Cell, c2: Cell): number { return Math.abs(c1.x - c2.x) + Math.abs(c1.y - c2.y); +} + +export function within(value: number, min: number, max: number): number { + return Math.min(Math.max(value, min), max); } \ No newline at end of file diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index 4d1d00f54..31d164f6f 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -1,6 +1,5 @@ import {Player, PlayerID, PlayerInfo, TerrainType, TerrainTypes, TerraNullius, Tile} from "../Game"; import {Colord, colord} from "colord"; -import {pastelTheme} from "./PastelTheme"; export interface Config { @@ -9,6 +8,7 @@ export interface Config { turnIntervalMs(): number gameCreationRate(): number lobbyLifetime(): number + numBots(): number } export interface PlayerConfig { diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index eb84639ed..3b2486d63 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -1,8 +1,12 @@ import {Player, PlayerInfo, TerraNullius, Tile} from "../Game"; +import {within} from "../Util"; import {Config, PlayerConfig, Theme} from "./Config"; import {pastelTheme} from "./PastelTheme"; export const defaultConfig = new class implements Config { + numBots(): number { + return 1000 + } player(): PlayerConfig { return defaultPlayerConfig } @@ -23,9 +27,9 @@ export const defaultPlayerConfig = new class implements PlayerConfig { attackLogic(attacker: Player, defender: Player | TerraNullius, tileToConquer: Tile): {attackerTroopLoss: number; defenderTroopLoss: number; tilesPerTickUsed: number} { if (defender.isPlayer()) { return { - attackerTroopLoss: Math.max(defender.troops() / attacker.troops(), 1), - defenderTroopLoss: 0, - tilesPerTickUsed: Math.max(defender.troops() / attacker.troops(), .25) + attackerTroopLoss: Math.min(defender.troops() / 1000, 10), + defenderTroopLoss: Math.min(attacker.troops() / 2000, 5), + tilesPerTickUsed: 1 } } else { return {attackerTroopLoss: 1, defenderTroopLoss: 0, tilesPerTickUsed: 1} @@ -34,7 +38,11 @@ export const defaultPlayerConfig = new class implements PlayerConfig { } attackTilesPerTick(attacker: Player, defender: Player | TerraNullius, numAdjacentTilesWithEnemy: number): number { - return numAdjacentTilesWithEnemy / 4 + if (defender.isPlayer()) { + return within(attacker.numTilesOwned() / defender.numTilesOwned(), .01, .5) * numAdjacentTilesWithEnemy + } else { + return numAdjacentTilesWithEnemy / 4 + } } boatAttackAmount(attacker: Player, defender: Player | TerraNullius): number { @@ -50,16 +58,17 @@ export const defaultPlayerConfig = new class implements PlayerConfig { } startTroops(playerInfo: PlayerInfo): number { - return 1000 + if (playerInfo.isBot) { + return 1000 + } + return 5000 } troopAdditionRate(player: Player): number { - let toAdd = Math.sqrt(player.numTilesOwned() * player.troops()) / 5 + const max = Math.sqrt(player.numTilesOwned()) * 1000 + 1000 + + let toAdd = 10 + (player.troops() + Math.sqrt(player.troops() * player.numTilesOwned())) / 250 - const max = Math.sqrt(player.numTilesOwned()) * 100 + 1000 - const ratio = 1 - player.troops() / max - toAdd *= ratio * ratio * ratio - toAdd = Math.max(2, toAdd) return Math.min(player.troops() + toAdd, max) } diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index 2ddb98af7..c387ac6de 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -36,22 +36,28 @@ export class AttackExecution implements Execution { this._owner.setTroops(this._owner.troops() - this.troops) this.mg = mg - if (this.target.isPlayer()) { - for (const exec of mg.executions()) { - if (exec instanceof AttackExecution) { - const otherAttack = exec as AttackExecution - if (otherAttack.target == this._owner && this.target == otherAttack._owner) { - if (otherAttack.troops > this.troops) { - otherAttack.troops -= this.troops - otherAttack.calculateToConquer() - this.active = false - return - } else { - this.troops -= otherAttack.troops - otherAttack.active = false - } + for (const exec of mg.executions()) { + if (exec.isActive() && exec instanceof AttackExecution) { + const otherAttack = exec as AttackExecution + // Target has opposing attack, cancel them out + if (this.target.isPlayer() && otherAttack.target == this._owner && this.target == otherAttack._owner) { + if (otherAttack.troops > this.troops) { + otherAttack.troops -= this.troops + otherAttack.calculateToConquer() + this.active = false + return + } else { + this.troops -= otherAttack.troops + otherAttack.active = false } } + // Existing attack on same target, add troops + if (otherAttack._owner == this._owner && otherAttack.target == this.target) { + otherAttack.troops += this.troops + otherAttack.calculateToConquer() + this.active = false + return + } } } @@ -77,7 +83,15 @@ export class AttackExecution implements Execution { if (this.toConquer.size() < this.numTilesWithEnemy / 2) { this.calculateToConquer() } - if (this.toConquer.size() == 0 || badTiles > 100) { + if (badTiles > 1000) { + console.log('bad tiles') + this.borderTiles.clear() + this.calculateToConquer() + badTiles = 0 + continue + } + if (this.toConquer.size() == 0) { + badTiles = 0 this.active = false this._owner.addTroops(this.troops) return diff --git a/src/core/execution/BotExecution.ts b/src/core/execution/BotExecution.ts index f6cc4d108..0189bb37e 100644 --- a/src/core/execution/BotExecution.ts +++ b/src/core/execution/BotExecution.ts @@ -1,5 +1,5 @@ import {PlayerConfig} from "../configuration/Config"; -import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerraNullius} from "../Game" +import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerrainTypes, TerraNullius} from "../Game" import {PseudoRandom} from "../PseudoRandom" import {AttackExecution} from "./AttackExecution"; @@ -33,7 +33,7 @@ export class BotExecution implements Execution { if (this.neighborsTerra) { for (const b of this.bot.borderTiles()) { for (const n of b.neighbors()) { - if (n.owner() == this.gs.terraNullius()) { + if (n.owner() == this.gs.terraNullius() && n.terrain() == TerrainTypes.Land) { this.sendAttack(this.gs.terraNullius()) return } diff --git a/src/server/GameServer.ts b/src/server/GameServer.ts index ad12bb41d..d4ec587b4 100644 --- a/src/server/GameServer.ts +++ b/src/server/GameServer.ts @@ -13,7 +13,7 @@ export enum GamePhase { export class GameServer { - private gameDuration = 5 * 60 * 1000 // TODO!!! fix this + private gameDuration = 20 * 60 * 1000 // TODO!!! fix this private turns: Turn[] = [] private intents: Intent[] = []