increase mirv price with total number of merged launched (#2621)

## Description:

To prevent MAD stalemates, have the price of MIRVs increase after each
launch. This will encourage players to launch a MIRV once they have
enough money for it. Also reduce the price of the first MIRV to 25
million to reduce snowballing, each subsequent MIRV cost an extra 15
million:

1. 25 million
2. 40 million
3. 60 million
4. etc



## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

evan
This commit is contained in:
Evan
2025-12-14 19:52:54 -08:00
committed by GitHub
parent 4f6a433dc8
commit 71cf309252
9 changed files with 84 additions and 33 deletions
+1 -2
View File
@@ -175,7 +175,7 @@ export enum GameMapSize {
}
export interface UnitInfo {
cost: (player: Player) => Gold;
cost: (game: Game, player: Player) => Gold;
// Determines if its owner changes when its tile is conquered.
territoryBound: boolean;
maxHealth?: number;
@@ -753,7 +753,6 @@ export interface Game extends GameMap {
nations(): Nation[];
numTilesWithFallout(): number;
// Optional as it's not initialized before the end of spawn phase
stats(): Stats;
addUpdate(update: GameUpdate): void;
+7 -5
View File
@@ -864,7 +864,7 @@ export class PlayerImpl implements Player {
);
}
const cost = this.mg.unitInfo(type).cost(this);
const cost = this.mg.unitInfo(type).cost(this.mg, this);
const b = new UnitImpl(
type,
this.mg,
@@ -911,7 +911,9 @@ export class PlayerImpl implements Player {
if (this.mg.config().isUnitDisabled(unit.type())) {
return false;
}
if (this._gold < this.mg.config().unitInfo(unit.type()).cost(this)) {
if (
this._gold < this.mg.config().unitInfo(unit.type()).cost(this.mg, this)
) {
return false;
}
if (unit.owner() !== this) {
@@ -921,7 +923,7 @@ export class PlayerImpl implements Player {
}
upgradeUnit(unit: Unit) {
const cost = this.mg.unitInfo(unit.type()).cost(this);
const cost = this.mg.unitInfo(unit.type()).cost(this.mg, this);
this.removeGold(cost);
unit.increaseLevel();
this.recordUnitConstructed(unit.type());
@@ -944,7 +946,7 @@ export class PlayerImpl implements Player {
? false
: this.canBuild(u, tile, validTiles),
canUpgrade: canUpgrade,
cost: this.mg.config().unitInfo(u).cost(this),
cost: this.mg.config().unitInfo(u).cost(this.mg, this),
} as BuildableUnit;
});
}
@@ -958,7 +960,7 @@ export class PlayerImpl implements Player {
return false;
}
const cost = this.mg.unitInfo(unitType).cost(this);
const cost = this.mg.unitInfo(unitType).cost(this.mg, this);
if (!this.isAlive() || this.gold() < cost) {
return false;
}
+2
View File
@@ -6,6 +6,8 @@ export interface Stats {
getPlayerStats(player: Player): PlayerStats | null;
stats(): AllPlayersStats;
numMirvsLaunched(): bigint;
// Player attacks target
attack(
player: Player,
+10 -1
View File
@@ -26,7 +26,7 @@ import {
unitTypeToBombUnit,
unitTypeToOtherUnit,
} from "../StatsSchemas";
import { Player, TerraNullius } from "./Game";
import { Player, TerraNullius, UnitType } from "./Game";
import { Stats } from "./Stats";
type BigIntLike = bigint | number;
@@ -42,6 +42,12 @@ function _bigint(value: BigIntLike): bigint {
export class StatsImpl implements Stats {
private readonly data: AllPlayersStats = {};
private _numMirvLaunched: bigint = 0n;
numMirvsLaunched(): bigint {
return this._numMirvLaunched;
}
getPlayerStats(player: Player): PlayerStats {
const clientID = player.clientID();
if (clientID === null) return undefined;
@@ -217,6 +223,9 @@ export class StatsImpl implements Stats {
target: Player | TerraNullius,
type: NukeType,
): void {
if (type === UnitType.MIRV) {
this._numMirvLaunched++;
}
this._addBomb(player, type, BOMB_INDEX_LAUNCH, 1);
}