From a32e9e48ef175309eca5a55f790c420e59b75967 Mon Sep 17 00:00:00 2001 From: evanpelle Date: Thu, 12 Jun 2025 08:41:55 -0700 Subject: [PATCH] update meta --- src/core/configuration/Config.ts | 5 ++- src/core/configuration/DefaultConfig.ts | 47 +++++++++++++++++------- src/core/execution/PortExecution.ts | 5 ++- src/core/execution/TradeShipExecution.ts | 7 +++- tests/Config.test.ts | 23 ++++++++++++ tests/util/Setup.ts | 26 ++++++++----- 6 files changed, 85 insertions(+), 28 deletions(-) create mode 100644 tests/Config.test.ts diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index 46d2875a0..6990856fb 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -123,8 +123,9 @@ export interface Config { donateCooldown(): Tick; defaultDonationAmount(sender: Player): number; unitInfo(type: UnitType): UnitInfo; - tradeShipGold(dist: number): Gold; - tradeShipSpawnRate(numberOfPorts: number): number; + tradeShipGold(dist: number, numTradeShips: number): Gold; + tradeShipSpawnRate(numTradeShips: number): number; + tradeShipCap(): number; safeFromPiratesCooldownMax(): number; defensePostRange(): number; SAMCooldown(): number; diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 2bee2d342..1402f22b5 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -276,11 +276,32 @@ export class DefaultConfig implements Config { infiniteTroops(): boolean { return this._gameConfig.infiniteTroops; } - tradeShipGold(dist: number): Gold { - return BigInt(Math.floor(10000 + 150 * Math.pow(dist, 1.1))); + + tradeShipGold(dist: number, numPorts: number): Gold { + const baseGold = Math.floor(10000 + 150 * Math.pow(dist, 1.1)); + const bonusPortNum = 25; + if (numPorts < bonusPortNum) { + return BigInt(baseGold); + } else { + return BigInt(Math.floor((numPorts / bonusPortNum) * baseGold)); + } } - tradeShipSpawnRate(numberOfPorts: number): number { - return Math.min(50, Math.round(10 * Math.pow(numberOfPorts, 0.6))); + + // Chance to spawn a trade ship in one second, + tradeShipSpawnRate(numTradeShips: number): number { + const baseRate = 5; + + if (numTradeShips <= 20) { + return baseRate; + } + if (numTradeShips > this.tradeShipCap()) { + return 1_000_000; + } + return numTradeShips - 15; + } + + tradeShipCap(): number { + return 100; } unitInfo(type: UnitType): UnitInfo { @@ -355,7 +376,7 @@ export class DefaultConfig implements Config { cost: (p: Player) => p.type() === PlayerType.Human && this.infiniteGold() ? 0n - : 25_000_000n, + : 40_000_000n, territoryBound: false, }; case UnitType.MIRVWarhead: @@ -498,7 +519,7 @@ export class DefaultConfig implements Config { const type = gm.terrainType(tileToConquer); switch (type) { case TerrainType.Plains: - mag = 85; + mag = 80; speed = 16.5; break; case TerrainType.Highland: @@ -547,23 +568,23 @@ export class DefaultConfig implements Config { } } - let largeLossModifier = 1; - if (attacker.numTilesOwned() > 100_000) { - largeLossModifier = Math.sqrt(100_000 / attacker.numTilesOwned()); - } let largeSpeedMalus = 1; if (attacker.numTilesOwned() > 75_000) { // sqrt is only exponent 1/2 which doesn't slow enough huge players - largeSpeedMalus = (75_000 / attacker.numTilesOwned()) ** 0.6; + largeSpeedMalus = (75_000 / attacker.numTilesOwned()) ** 0.5; } if (defender.isPlayer()) { + let largeDefenderDebuff = 1; + if (defender.numTilesOwned() > 100_000) { + largeDefenderDebuff = Math.sqrt(100_000 / defender.numTilesOwned()); + } return { attackerTroopLoss: within(defender.troops() / attackTroops, 0.5, 2) * mag * 0.8 * - largeLossModifier * + largeDefenderDebuff * (defender.isTraitor() ? this.traitorDefenseDebuff() : 1), defenderTroopLoss: defender.troops() / defender.numTilesOwned(), tilesPerTickUsed: @@ -676,7 +697,7 @@ export class DefaultConfig implements Config { populationIncreaseRate(player: Player): number { const max = this.maxPopulation(player); - let toAdd = 10 + Math.pow(player.population(), 0.7) / 4; + let toAdd = 10 + Math.pow(player.population(), 0.7) / 3; const ratio = 1 - player.population() / max; toAdd *= ratio; diff --git a/src/core/execution/PortExecution.ts b/src/core/execution/PortExecution.ts index 74b6554f6..5df070e8e 100644 --- a/src/core/execution/PortExecution.ts +++ b/src/core/execution/PortExecution.ts @@ -64,12 +64,13 @@ export class PortExecution implements Execution { return; } - const totalNbOfPorts = this.mg.units(UnitType.Port).length; + const numTradeShips = this.mg.units(UnitType.TradeShip).length; if ( - !this.random.chance(this.mg.config().tradeShipSpawnRate(totalNbOfPorts)) + !this.random.chance(this.mg.config().tradeShipSpawnRate(numTradeShips)) ) { return; } + console.log(`numTradeShips: ${numTradeShips}`); const ports = this.player().tradingPorts(this.port); diff --git a/src/core/execution/TradeShipExecution.ts b/src/core/execution/TradeShipExecution.ts index 231b3a87c..37ea4143a 100644 --- a/src/core/execution/TradeShipExecution.ts +++ b/src/core/execution/TradeShipExecution.ts @@ -129,7 +129,12 @@ export class TradeShipExecution implements Execution { private complete() { this.active = false; this.tradeShip!.delete(false); - const gold = this.mg.config().tradeShipGold(this.tilesTraveled); + const gold = this.mg + .config() + .tradeShipGold( + this.tilesTraveled, + this.mg.units(UnitType.TradeShip).length, + ); if (this.wasCaptured) { this.tradeShip!.owner().addGold(gold); diff --git a/tests/Config.test.ts b/tests/Config.test.ts new file mode 100644 index 000000000..05a52a63c --- /dev/null +++ b/tests/Config.test.ts @@ -0,0 +1,23 @@ +import { DefaultConfig } from "../src/core/configuration/DefaultConfig"; +import { createGameConfig } from "./util/Setup"; +import { TestServerConfig } from "./util/TestServerConfig"; + +describe("Config", () => { + test("Trade ship spawn rate", async () => { + const config = new DefaultConfig( + new TestServerConfig(), + createGameConfig(), + null, + false, + ); + + expect(config.tradeShipSpawnRate(0)).toBe(5); + expect(config.tradeShipSpawnRate(1)).toBe(5); + expect(config.tradeShipSpawnRate(20)).toBe(5); + expect(config.tradeShipSpawnRate(21)).toBe(6); + expect(config.tradeShipSpawnRate(30)).toBe(15); + expect(config.tradeShipSpawnRate(50)).toBe(35); + expect(config.tradeShipSpawnRate(100)).toBe(85); + expect(config.tradeShipSpawnRate(151)).toBe(1_000_000); + }); +}); diff --git a/tests/util/Setup.ts b/tests/util/Setup.ts index 9f657bffc..dc7fe09d8 100644 --- a/tests/util/Setup.ts +++ b/tests/util/Setup.ts @@ -36,7 +36,21 @@ export async function setup( // Configure the game const serverConfig = new TestServerConfig(); - const gameConfig: GameConfig = { + + const config = new TestConfig( + serverConfig, + createGameConfig(_gameConfig), + new UserSettings(), + false, + ); + + return createGame(humans, [], gameMap, miniGameMap, config); +} + +export function createGameConfig( + gameConfig: Partial = {}, +): GameConfig { + return { gameMap: GameMapType.Asia, gameMode: GameMode.FFA, gameType: GameType.Singleplayer, @@ -46,16 +60,8 @@ export async function setup( infiniteGold: false, infiniteTroops: false, instantBuild: false, - ..._gameConfig, + ...gameConfig, }; - const config = new TestConfig( - serverConfig, - gameConfig, - new UserSettings(), - false, - ); - - return createGame(humans, [], gameMap, miniGameMap, config); } export function playerInfo(name: string, type: PlayerType): PlayerInfo {