Record human/nation/bot conquests (#2949)

## Description:

Conquests are currently mixing all player types.

This is not ideal as people wonders why a 50 player game can lead to
hundred of kills.
Having separate records can also help with achievements and better
balancing.

This PR splits the conquests record into 3 categories: human, nations
and bots.

It is linked to this infra PR:
https://github.com/openfrontio/infra/pull/246

<img width="895" height="497" alt="image"
src="https://github.com/user-attachments/assets/66e49100-8114-4406-84ab-d9627355956d"
/>

While the recorded data make a distinction between bots/nations, it's
only displayed here as a single "bot" category.

## 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:

IngloriousTom
This commit is contained in:
DevelopingTom
2026-01-19 05:51:12 +01:00
committed by GitHub
parent d92008f96b
commit f367ea1940
10 changed files with 83 additions and 39 deletions
+6 -1
View File
@@ -62,6 +62,11 @@ export const ATTACK_INDEX_SENT = 0; // Outgoing attack troops
export const ATTACK_INDEX_RECV = 1; // Incmoing attack troops
export const ATTACK_INDEX_CANCEL = 2; // Cancelled attack troops
// Player types
export const PLAYER_INDEX_HUMAN = 0;
export const PLAYER_INDEX_NATION = 1;
export const PLAYER_INDEX_BOT = 2;
// Boats
export const BOAT_INDEX_SENT = 0; // Boats launched
export const BOAT_INDEX_ARRIVE = 1; // Boats arrived
@@ -102,7 +107,7 @@ export const PlayerStatsSchema = z
attacks: AtLeastOneNumberSchema.optional(),
betrayals: BigIntStringSchema.optional(),
killedAt: BigIntStringSchema.optional(),
conquests: BigIntStringSchema.optional(),
conquests: AtLeastOneNumberSchema.optional(),
boats: z.partialRecord(BoatUnitSchema, AtLeastOneNumberSchema).optional(),
bombs: z.partialRecord(BombUnitSchema, AtLeastOneNumberSchema).optional(),
gold: AtLeastOneNumberSchema.optional(),
+18 -8
View File
@@ -24,11 +24,14 @@ import {
OTHER_INDEX_LOST,
OTHER_INDEX_UPGRADE,
OtherUnitType,
PLAYER_INDEX_BOT,
PLAYER_INDEX_HUMAN,
PLAYER_INDEX_NATION,
PlayerStats,
unitTypeToBombUnit,
unitTypeToOtherUnit,
} from "../StatsSchemas";
import { Player, TerraNullius, UnitType } from "./Game";
import { Player, PlayerType, TerraNullius, UnitType } from "./Game";
import { Stats } from "./Stats";
type BigIntLike = bigint | number;
@@ -41,6 +44,12 @@ function _bigint(value: BigIntLike): bigint {
}
}
const conquest_by_type: Record<PlayerType, number> = {
[PlayerType.Human]: PLAYER_INDEX_HUMAN,
[PlayerType.Nation]: PLAYER_INDEX_NATION,
[PlayerType.Bot]: PLAYER_INDEX_BOT,
};
export class StatsImpl implements Stats {
private readonly data: AllPlayersStats = {};
@@ -138,14 +147,12 @@ export class StatsImpl implements Stats {
p.units[type][index] += _bigint(value);
}
private _addConquest(player: Player) {
private _addConquest(player: Player, index: number) {
const p = this._makePlayerStats(player);
if (p === undefined) return;
if (p.conquests === undefined) {
p.conquests = _bigint(1);
} else {
p.conquests += _bigint(1);
}
p.conquests ??= [0n];
while (p.conquests.length <= index) p.conquests.push(0n);
p.conquests[index] += _bigint(1);
}
private _addPlayerKilled(player: Player, tick: number) {
@@ -249,7 +256,10 @@ export class StatsImpl implements Stats {
goldWar(player: Player, captured: Player, gold: BigIntLike): void {
this._addGold(player, GOLD_INDEX_WAR, gold);
this._addConquest(player);
const conquestType = conquest_by_type[captured.type()];
if (conquestType !== undefined) {
this._addConquest(player, conquestType);
}
}
unitBuild(player: Player, type: OtherUnitType): void {