Skip to content

Commit 9d5b682

Browse files
committed
tradeship
1 parent 7bf6bfd commit 9d5b682

4 files changed

Lines changed: 17 additions & 52 deletions

File tree

src/core/configuration/Config.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,10 @@ export interface Config {
126126
defaultDonationAmount(sender: Player): number;
127127
unitInfo(type: UnitType): UnitInfo;
128128
tradeShipShortRangeDebuff(): number;
129-
tradeShipGold(dist: number, numPorts: number): Gold;
129+
tradeShipGold(dist: number): Gold;
130130
tradeShipSpawnRate(
131+
tradeShipSpawnRejections: number,
131132
numTradeShips: number,
132-
numPlayerPorts: number,
133-
numPlayerTradeShips: number,
134133
): number;
135134
trainGold(rel: "self" | "team" | "ally" | "other"): Gold;
136135
trainSpawnRate(numPlayerFactories: number): number;

src/core/configuration/DefaultConfig.ts

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { PlayerView } from "../game/GameView";
2020
import { UserSettings } from "../game/UserSettings";
2121
import { GameConfig, GameID, TeamCountConfig } from "../Schemas";
2222
import { NukeType } from "../StatsSchemas";
23-
import { assertNever, sigmoid, simpleHash, within } from "../Util";
23+
import { assertNever, sigmoid, simpleHash, toInt, within } from "../Util";
2424
import { Config, GameEnv, NukeMagnitude, ServerConfig, Theme } from "./Config";
2525
import { Env } from "./Env";
2626
import { PastelTheme } from "./PastelTheme";
@@ -297,52 +297,24 @@ export class DefaultConfig implements Config {
297297
return 120;
298298
}
299299

300-
tradeShipGold(dist: number, numPorts: number): Gold {
301-
// Sigmoid: concave start, sharp S-curve middle, linear end - heavily punishes trades under range debuff.
302-
const debuff = this.tradeShipShortRangeDebuff();
303-
const baseGold =
304-
100_000 / (1 + Math.exp(-0.03 * (dist - debuff))) + 100 * dist;
305-
const numPortBonus = numPorts - 1;
306-
// Hyperbolic decay, midpoint at 5 ports, 3x bonus max.
307-
const bonus = 1 + 2 * (numPortBonus / (numPortBonus + 5));
308-
const multiplier = this.goldMultiplier();
309-
return BigInt(Math.floor(baseGold * bonus * multiplier));
300+
tradeShipGold(dist: number): Gold {
301+
return toInt(10000 + 150 * Math.pow(dist, 1.1));
310302
}
311303

312304
// Probability of trade ship spawn = 1 / tradeShipSpawnRate
313305
tradeShipSpawnRate(
306+
tradeShipSpawnRejections: number,
314307
numTradeShips: number,
315-
numPlayerPorts: number,
316-
numPlayerTradeShips: number,
317308
): number {
318-
// Geometric mean of base spawn rate and port multiplier
319-
const combined = Math.sqrt(
320-
this.tradeShipBaseSpawn(numTradeShips, numPlayerTradeShips) *
321-
this.tradeShipPortMultiplier(numPlayerPorts),
322-
);
309+
const decayRate = Math.LN2 / 50;
323310

324-
return Math.floor(25 / combined);
325-
}
311+
// Approaches 0 as numTradeShips increase
312+
const baseSpawnRate = 1 - sigmoid(numTradeShips, decayRate, 200);
326313

327-
private tradeShipBaseSpawn(
328-
numTradeShips: number,
329-
numPlayerTradeShips: number,
330-
): number {
331-
if (numPlayerTradeShips < 3) {
332-
// If other players have many ports, then they can starve out smaller players.
333-
// So this prevents smaller players from being completely starved out.
334-
return 1;
335-
}
336-
const decayRate = Math.LN2 / 10;
337-
return 1 - sigmoid(numTradeShips, decayRate, 55);
338-
}
314+
// Pity timer: increases spawn chance after consecutive rejections
315+
const rejectionModifier = 1 / (tradeShipSpawnRejections + 1);
339316

340-
private tradeShipPortMultiplier(numPlayerPorts: number): number {
341-
// Hyperbolic decay function with midpoint at 10 ports
342-
// Expected trade ship spawn rate is proportional to numPlayerPorts * multiplier
343-
// Gradual decay prevents scenario where more ports => fewer ships
344-
const decayRate = 1 / 10;
345-
return 1 / (1 + decayRate * numPlayerPorts);
317+
return Math.floor((100 * rejectionModifier) / baseSpawnRate);
346318
}
347319

348320
unitInfo(type: UnitType): UnitInfo {

src/core/execution/PortExecution.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export class PortExecution implements Execution {
99
private port: Unit;
1010
private random: PseudoRandom;
1111
private checkOffset: number;
12+
private tradeShipSpawnRejections = 0;
1213

1314
constructor(port: Unit) {
1415
this.port = port;
@@ -69,17 +70,15 @@ export class PortExecution implements Execution {
6970

7071
shouldSpawnTradeShip(): boolean {
7172
const numTradeShips = this.mg.unitCount(UnitType.TradeShip);
72-
const numPlayerPorts = this.port!.owner().unitCount(UnitType.Port);
73-
const numPlayerTradeShips = this.port!.owner().unitCount(
74-
UnitType.TradeShip,
75-
);
7673
const spawnRate = this.mg
7774
.config()
78-
.tradeShipSpawnRate(numTradeShips, numPlayerPorts, numPlayerTradeShips);
75+
.tradeShipSpawnRate(this.tradeShipSpawnRejections, numTradeShips);
7976
for (let i = 0; i < this.port!.level(); i++) {
8077
if (this.random.chance(spawnRate)) {
78+
this.tradeShipSpawnRejections = 0;
8179
return true;
8280
}
81+
this.tradeShipSpawnRejections++;
8382
}
8483
return false;
8584
}

src/core/execution/TradeShipExecution.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,7 @@ export class TradeShipExecution implements Execution {
133133
private complete() {
134134
this.active = false;
135135
this.tradeShip!.delete(false);
136-
const gold = this.mg
137-
.config()
138-
.tradeShipGold(
139-
this.tilesTraveled,
140-
this.tradeShip!.owner().unitCount(UnitType.Port),
141-
);
136+
const gold = this.mg.config().tradeShipGold(this.tilesTraveled);
142137

143138
if (this.wasCaptured) {
144139
this.tradeShip!.owner().addGold(gold, this._dstPort.tile());

0 commit comments

Comments
 (0)