Skip to content
Draft

Trade3 #3436

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/core/configuration/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export interface Config {
tradeShipGold(dist: number): Gold;
tradeShipSpawnRate(
tradeShipSpawnRejections: number,
numTradeShips: number,
numPlayerPorts: number,
): number;
trainGold(
rel: "self" | "team" | "ally" | "other",
Expand Down
29 changes: 10 additions & 19 deletions src/core/configuration/DefaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,28 +311,24 @@ export class DefaultConfig implements Config {
}

tradeShipGold(dist: number): Gold {
// Sigmoid: concave start, sharp S-curve middle, linear end - heavily punishes trades under range debuff.
const debuff = this.tradeShipShortRangeDebuff();
const baseGold =
75_000 / (1 + Math.exp(-0.03 * (dist - debuff))) + 50 * dist;
const multiplier = this.goldMultiplier();
return BigInt(Math.floor(baseGold * multiplier));
return toInt(10000 + 150 * Math.pow(dist, 1.1));
}

// Probability of trade ship spawn = 1 / tradeShipSpawnRate
tradeShipSpawnRate(
tradeShipSpawnRejections: number,
numTradeShips: number,
numPlayerPorts: number,
): number {
const decayRate = Math.LN2 / 50;

// Approaches 0 as numTradeShips increase
const baseSpawnRate = 1 - sigmoid(numTradeShips, decayRate, 200);
if (numPlayerPorts <= 3) return 18;
if (numPlayerPorts <= 5) return 25;
if (numPlayerPorts <= 8) return 35;
if (numPlayerPorts <= 10) return 40;
if (numPlayerPorts <= 12) return 45;

// Pity timer: increases spawn chance after consecutive rejections
const rejectionModifier = 1 / (tradeShipSpawnRejections + 1);

return Math.floor((100 * rejectionModifier) / baseSpawnRate);
return Math.floor((100 * rejectionModifier) / 50);
Comment on lines +322 to +331
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Possible logic issue: spawn rate drops sharply for >12 ports.

For numPlayerPorts <= 12, the function returns 45 (about 2.2% spawn chance). But for numPlayerPorts > 12, it returns Math.floor(100 / 50) = 2 when there are no rejections, meaning a 50% spawn chance.

This seems like a big jump. Is this intentional? If you meant to continue the scaling pattern, consider something like:

🐛 If this is unintentional, here is a possible fix
     if (numPlayerPorts <= 12) return 45;

     // Pity timer: increases spawn chance after consecutive rejections
     const rejectionModifier = 1 / (tradeShipSpawnRejections + 1);

-    return Math.floor((100 * rejectionModifier) / 50);
+    // Continue scaling for larger port counts
+    const baseRate = 45 + Math.floor((numPlayerPorts - 12) * 5);
+    return Math.floor(baseRate * rejectionModifier);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/configuration/DefaultConfig.ts` around lines 319 - 328, The current
fallback for numPlayerPorts > 12 uses Math.floor((100 * rejectionModifier) / 50)
which produces an unexpected large jump; replace this with a scaling formula
that continues with numPlayerPorts (e.g., return Math.max(2, Math.min(95,
Math.floor((100 * rejectionModifier) / Math.max(1, numPlayerPorts))))),
referencing numPlayerPorts and tradeShipSpawnRejections/rejectionModifier so
spawn chance scales smoothly and is clamped to reasonable bounds.

}

unitInfo(type: UnitType): UnitInfo {
Expand Down Expand Up @@ -391,13 +387,8 @@ export class DefaultConfig implements Config {
};
break;
case UnitType.MIRV:
info = {
cost: (game: Game, player: Player) => {
if (player.type() === PlayerType.Human && this.infiniteGold()) {
return 0n;
}
return 25_000_000n + game.stats().numMirvsLaunched() * 15_000_000n;
},
return {
cost: this.costWrapper(() => 35_000_000),
};
break;
Comment on lines +390 to 393
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Dead code: break after return is unreachable.

The return statement exits the function, so the break on Line 390 never executes.

🧹 Proposed fix
       case UnitType.MIRV:
         return {
           cost: this.costWrapper(() => 35_000_000),
         };
-        break;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return {
cost: this.costWrapper(() => 35_000_000),
};
break;
return {
cost: this.costWrapper(() => 35_000_000),
};
🧰 Tools
🪛 Biome (2.4.6)

[error] 390-390: This code is unreachable

(lint/correctness/noUnreachable)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/configuration/DefaultConfig.ts` around lines 387 - 390, In
DefaultConfig (method returning the object with cost: this.costWrapper(() =>
35_000_000)), remove the unreachable `break` that follows the `return` — locate
the block in DefaultConfig where the function returns `{ cost:
this.costWrapper(...) }` and delete the redundant `break` statement to eliminate
dead code.

case UnitType.MIRVWarhead:
Expand Down
4 changes: 2 additions & 2 deletions src/core/execution/PortExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ export class PortExecution implements Execution {
}

shouldSpawnTradeShip(): boolean {
const numTradeShips = this.mg.unitCount(UnitType.TradeShip);
const numPlayerPorts = this.port!.owner().unitCount(UnitType.Port);
const spawnRate = this.mg
.config()
.tradeShipSpawnRate(this.tradeShipSpawnRejections, numTradeShips);
.tradeShipSpawnRate(this.tradeShipSpawnRejections, numPlayerPorts);
for (let i = 0; i < this.port!.level(); i++) {
if (this.random.chance(spawnRate)) {
this.tradeShipSpawnRejections = 0;
Expand Down
2 changes: 1 addition & 1 deletion startup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export CLOUDFLARE_TUNNEL_TOKEN=${TUNNEL_TOKEN}

# Start supervisord
if [ "$DOMAIN" = openfront.dev ] && [ "$SUBDOMAIN" != main ]; then
exec timeout 18h /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
else
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
fi
Loading