mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-24 03:42:37 +00:00
## Description: Enriches the admin-bot live-stats snapshot (`/api/adminbot/game/:id/stats`) with the per-player fields a semi-live standings board needs, so it can score kills + placement live instead of waiting for the post-game record. Per player in `liveStats.players[]`: - **`killedBy`** — the eliminator's clientID (null while alive / non-client killer). Invert → live kill points. - **`deathPosition`** — finishing place at elimination = non-bot players still standing + 1 (frozen at "last of the then-standing"). Null while alive → live placement. The **full roster** is reported (dead players are retained in the client view), plus top-level **`winner`** (the decided winner's clientID, else null). Deterministic / consensus-safe: `killedBy` (stamped at `recordKill`) and `deathPosition` (stamped in `PlayerExecution`) are pure sim values, so in-sync clients agree on the majority vote; `winner` is added server-side in `GameServer.liveStats()` from the winner vote (like the existing publicID/username/connected enrichment). ## 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
122 lines
3.7 KiB
TypeScript
122 lines
3.7 KiB
TypeScript
import { AllPlayersStats, ClientID } from "../Schemas";
|
|
import { NukeType, OtherUnitType, PlayerStats } from "../StatsSchemas";
|
|
import { Player, TerraNullius } from "./Game";
|
|
|
|
export interface Stats {
|
|
getPlayerStats(player: Player): PlayerStats | null;
|
|
stats(): AllPlayersStats;
|
|
|
|
numMirvsLaunched(): bigint;
|
|
|
|
// Player attacks target
|
|
attack(
|
|
player: Player,
|
|
target: Player | TerraNullius,
|
|
troops: number | bigint,
|
|
): void;
|
|
|
|
// Player cancels attack on target
|
|
attackCancel(
|
|
player: Player,
|
|
target: Player | TerraNullius,
|
|
troops: number | bigint,
|
|
): void;
|
|
|
|
// Player betrays another player
|
|
betray(player: Player): void;
|
|
|
|
// Time between lobby creation and game start (ms)
|
|
lobbyFillTime(fillTimeMs: number): void;
|
|
|
|
// Player sends a trade ship to target
|
|
boatSendTrade(player: Player, target: Player): void;
|
|
|
|
// Player's trade ship arrives at target, both players earn gold
|
|
boatArriveTrade(player: Player, target: Player, gold: number | bigint): void;
|
|
|
|
// Player's trade ship, captured from target, arrives. Player earns gold.
|
|
boatCapturedTrade(
|
|
player: Player,
|
|
target: Player,
|
|
gold: number | bigint,
|
|
): void;
|
|
|
|
// Player destroys target's trade ship
|
|
boatDestroyTrade(player: Player, target: Player): void;
|
|
|
|
// Player sends a transport ship to target with troops
|
|
boatSendTroops(
|
|
player: Player,
|
|
target: Player | TerraNullius,
|
|
troops: number | bigint,
|
|
): void;
|
|
|
|
// Player's transport ship arrives at target with troops
|
|
boatArriveTroops(
|
|
player: Player,
|
|
target: Player | TerraNullius,
|
|
troops: number | bigint,
|
|
): void;
|
|
|
|
// Player destroys target's transport ship with troops
|
|
boatDestroyTroops(
|
|
player: Player,
|
|
target: Player,
|
|
troops: number | bigint,
|
|
): void;
|
|
|
|
// Player launches bomb at target
|
|
bombLaunch(
|
|
player: Player,
|
|
target: Player | TerraNullius,
|
|
type: NukeType,
|
|
): void;
|
|
|
|
// Player's bomb lands at target
|
|
bombLand(player: Player, target: Player | TerraNullius, type: NukeType): void;
|
|
|
|
// Player's SAM intercepts a bomb from attacker
|
|
bombIntercept(player: Player, type: NukeType, count: number | bigint): void;
|
|
|
|
// Player earns gold from conquering tiles or trade ships from captured
|
|
goldWar(player: Player, captured: Player, gold: number | bigint): void;
|
|
|
|
// Player earns gold from workers
|
|
goldWork(player: Player, gold: number | bigint): void;
|
|
|
|
// Player builds a unit of type
|
|
unitBuild(player: Player, type: OtherUnitType): void;
|
|
|
|
// Player captures a unit of type
|
|
unitCapture(player: Player, type: OtherUnitType): void;
|
|
|
|
// Player upgrades a unit of type
|
|
unitUpgrade(player: Player, type: OtherUnitType): void;
|
|
|
|
// Player destroys a unit of type
|
|
unitDestroy(player: Player, type: OtherUnitType): void;
|
|
|
|
// Player loses a unit of type
|
|
unitLose(player: Player, type: OtherUnitType): void;
|
|
|
|
// player was killed (0 tiles)
|
|
playerKilled(player: Player, tick: number): void;
|
|
|
|
// OFM live standings: who eliminated the player (null = non-client killer) and
|
|
// their finishing place. Both first-write-wins.
|
|
recordKilledBy(victim: Player, killerClientID: ClientID | null): void;
|
|
recordDeathPosition(victim: Player, position: number): void;
|
|
|
|
// Record tiles owned at game end (final standings).
|
|
recordFinalTiles(player: Player, tiles: number | bigint): void;
|
|
|
|
// Record that player eliminated human victim at tick (OFM kill scoring).
|
|
recordKill(player: Player, victim: Player, tick: number | bigint): void;
|
|
|
|
// Player's train arrives at any station, generating gold
|
|
trainSelfTrade(player: Player, gold: number | bigint): void;
|
|
|
|
// Another player's train arrives at own station
|
|
trainExternalTrade(player: Player, goldPlayer: number | bigint): void;
|
|
}
|