new trade ship meta

This commit is contained in:
evanpelle
2025-08-12 09:42:42 -07:00
parent 754db60a00
commit 35dca075c3
4 changed files with 44 additions and 20 deletions
+8
View File
@@ -287,3 +287,11 @@ export const flattenedEmojiTable: string[] = emojiTable.flat();
export function replacer(_key: string, value: any): any {
return typeof value === "bigint" ? value.toString() : value;
}
export function sigmoid(
value: number,
decayRate: number,
midpoint: number,
): number {
return 1 / (1 + Math.exp(-decayRate * (value - midpoint)));
}
+1 -1
View File
@@ -129,7 +129,7 @@ export interface Config {
defaultDonationAmount(sender: Player): number;
unitInfo(type: UnitType): UnitInfo;
tradeShipGold(dist: number, numPorts: number): Gold;
tradeShipSpawnRate(numberOfPorts: number): number;
tradeShipSpawnRate(numTradeShips: number, numPlayerPorts: number): number;
trainGold(isFriendly: boolean): Gold;
trainSpawnRate(numberOfStations: number): number;
trainStationMinRange(): number;
+31 -18
View File
@@ -24,7 +24,7 @@ import { PlayerView } from "../game/GameView";
import { UserSettings } from "../game/UserSettings";
import { GameConfig, GameID, TeamCountConfig } from "../Schemas";
import { NukeType } from "../StatsSchemas";
import { assertNever, simpleHash, within } from "../Util";
import { assertNever, sigmoid, simpleHash, within } from "../Util";
import { Config, GameEnv, NukeMagnitude, ServerConfig, Theme } from "./Config";
import { PastelTheme } from "./PastelTheme";
import { PastelThemeDark } from "./PastelThemeDark";
@@ -343,28 +343,41 @@ export class DefaultConfig implements Config {
}
tradeShipGold(dist: number, numPorts: number): Gold {
const baseGold = Math.floor(50000 + 100 * dist);
const basePortBonus = 0.25;
const diminishingFactor = 0.9;
const baseGold = Math.floor(50_000 + 100 * dist);
const basePortBonus = 0.5;
const diminishingFactor = 0.8;
let totalMultiplier = 1;
for (let i = 0; i < numPorts; i++) {
totalMultiplier += basePortBonus * Math.pow(diminishingFactor, i);
for (let i = 1; i < numPorts; i++) {
totalMultiplier += Math.max(
0.05,
basePortBonus * Math.pow(diminishingFactor, i - 1),
);
}
return BigInt(Math.floor(baseGold * totalMultiplier));
}
// Chance to spawn a trade ship in one second,
tradeShipSpawnRate(numTradeShips: number): number {
if (numTradeShips < 20) {
return 5;
}
if (numTradeShips <= 150) {
const additional = numTradeShips - 20;
return Math.floor(Math.pow(additional, 0.85) + 5);
}
return 1_000_000;
// Probability of trade ship spawn = 1 / tradeShipSpawnRate
tradeShipSpawnRate(numTradeShips: number, numPlayerPorts: number): number {
// Geometric mean of base spawn rate and port multiplier
const combined = Math.sqrt(
this.tradeShipBaseSpawn(numTradeShips) *
this.tradeShipPortMultiplier(numPlayerPorts),
);
return Math.floor(10 / combined);
}
private tradeShipBaseSpawn(numTradeShips: number): number {
const decayRate = Math.log(2) / 30;
return 1 - sigmoid(numTradeShips, decayRate, 100);
}
private tradeShipPortMultiplier(numPlayerPorts: number): number {
// Higher number => faster expected number of trade ships levels off
// This decays gradually to prevent the scenario where more ports => fewer trade ships
// Expected number of trade ships is proportional to numPlayerPorts * tradeShipPortMultiplier
const decayRate = 0.1;
return 1 / (1 + decayRate * numPlayerPorts);
}
unitInfo(type: UnitType): UnitInfo {
+4 -1
View File
@@ -78,7 +78,10 @@ export class PortExecution implements Execution {
shouldSpawnTradeShip(): boolean {
const numTradeShips = this.mg.unitCount(UnitType.TradeShip);
const spawnRate = this.mg.config().tradeShipSpawnRate(numTradeShips);
const numPlayerPorts = this.player.unitCount(UnitType.Port);
const spawnRate = this.mg
.config()
.tradeShipSpawnRate(numTradeShips, numPlayerPorts);
for (let i = 0; i < this.port!.level(); i++) {
if (this.random.chance(spawnRate)) {
return true;