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
@@ -5,10 +5,14 @@ import {
GOLD_INDEX_TRAIN_OTHER,
GOLD_INDEX_TRAIN_SELF,
GOLD_INDEX_WAR,
PLAYER_INDEX_BOT,
PLAYER_INDEX_HUMAN,
PLAYER_INDEX_NATION,
} from "../../../../core/StatsSchemas";
export enum RankType {
Conquests = "Conquests",
ConquestHumans = "ConquestHumans",
ConquestBots = "ConquestBots",
Atoms = "Atoms",
Hydros = "Hydros",
MIRV = "MIRV",
@@ -27,7 +31,7 @@ export interface PlayerInfo {
tag?: string;
killedAt?: number;
gold: bigint[];
conquests: number;
conquests: bigint[];
flag?: string;
winner: boolean;
atoms: number;
@@ -79,12 +83,13 @@ export class Ranking {
username = match[2];
}
const gold = (stats.gold ?? []).map((v) => BigInt(v ?? 0));
const conquests = (stats.conquests ?? []).map((v) => BigInt(v ?? 0));
players[player.clientID] = {
id: player.clientID,
rawUsername: player.username,
username,
tag: player.clanTag,
conquests: Number(stats.conquests) || 0,
conquests,
flag: player.cosmetics?.flag ?? undefined,
killedAt: stats.killedAt !== null ? Number(stats.killedAt) : undefined,
gold,
@@ -125,8 +130,13 @@ export class Ranking {
return (player.killedAt / Math.max(this.duration, 1)) * 10;
}
return 100;
case RankType.Conquests:
return player.conquests;
case RankType.ConquestHumans:
return Number(player.conquests[PLAYER_INDEX_HUMAN] ?? 0n);
case RankType.ConquestBots:
return (
Number(player.conquests[PLAYER_INDEX_BOT] ?? 0n) +
Number(player.conquests[PLAYER_INDEX_NATION] ?? 0n)
);
case RankType.Atoms:
return player.atoms;
case RankType.Hydros:
@@ -63,7 +63,8 @@ export class PlayerRow extends LitElement {
private renderPlayerInfo() {
switch (this.rankType) {
case RankType.Lifetime:
case RankType.Conquests:
case RankType.ConquestHumans:
case RankType.ConquestBots:
return this.renderScoreAsBar();
case RankType.Atoms:
case RankType.Hydros:
@@ -10,19 +10,25 @@ const economyRankings = new Set([
RankType.NavalTrade,
RankType.TrainTrade,
]);
const tradeRankings = new Set([RankType.NavalTrade, RankType.TrainTrade]);
const bombRankings = new Set([RankType.Atoms, RankType.Hydros, RankType.MIRV]);
const warRankings = new Set([
RankType.Conquests,
RankType.ConquestHumans,
RankType.ConquestBots,
RankType.Atoms,
RankType.Hydros,
RankType.MIRV,
]);
const tradeRankings = new Set([RankType.NavalTrade, RankType.TrainTrade]);
const bombRankings = new Set([RankType.Atoms, RankType.Hydros, RankType.MIRV]);
const conquestRankings = new Set([
RankType.ConquestHumans,
RankType.ConquestBots,
]);
const isEconomyRanking = (t: RankType) => economyRankings.has(t);
const isTradeRanking = (t: RankType) => tradeRankings.has(t);
const isBombRanking = (t: RankType) => bombRankings.has(t);
const isWarRanking = (t: RankType) => warRankings.has(t);
const isConquestRanking = (t: RankType) => conquestRankings.has(t);
@customElement("ranking-controls")
export class RankingControls extends LitElement {
@@ -41,7 +47,7 @@ export class RankingControls extends LitElement {
"game_info_modal.duration",
)}
${this.renderButton(
RankType.Conquests,
RankType.ConquestHumans,
isWarRanking(this.rankType),
"game_info_modal.war",
)}
@@ -78,8 +84,8 @@ export class RankingControls extends LitElement {
"game_info_modal.bombs",
)}
${this.renderSubButton(
RankType.Conquests,
this.rankType === RankType.Conquests,
RankType.ConquestHumans,
isConquestRanking(this.rankType),
"game_info_modal.conquests",
)}
</div>
@@ -14,7 +14,7 @@ export class RankingHeader extends LitElement {
render() {
return html`
<li
class="text-lg border-white/5 bg-white/[0.02] text-white/60 text-xs uppercase tracking-wider relative pt-2 pb-2 pr-5 pl-5 flex justify-between items-center"
class="h-[30px] text-lg border-white/5 bg-white/[0.02] text-white/60 text-xs uppercase tracking-wider relative pt-2 pb-2 pr-5 pl-5 flex justify-between items-center"
>
${this.renderHeaderContent()}
</li>
@@ -27,10 +27,21 @@ export class RankingHeader extends LitElement {
return html`<div class="w-full">
${translateText("game_info_modal.survival_time")}
</div>`;
case RankType.Conquests:
return html`<div class="w-full">
${translateText("game_info_modal.num_of_conquests")}
</div>`;
case RankType.ConquestHumans:
case RankType.ConquestBots:
return html`
<div class="flex justify-between sm:px-17.5 w-full">
${this.renderMultipleChoiceHeaderButton(
translateText("game_info_modal.num_of_conquests_humans"),
RankType.ConquestHumans,
)}
/
${this.renderMultipleChoiceHeaderButton(
translateText("game_info_modal.num_of_conquests_bots"),
RankType.ConquestBots,
)}
</div>
`;
case RankType.Atoms:
case RankType.Hydros:
case RankType.MIRV:
@@ -149,7 +149,7 @@ export class PlayerStatsTreeView extends LitElement {
attacks: this.mergeStatArrays(base.attacks, next.attacks),
betrayals: this.mergeStatValue(base.betrayals, next.betrayals),
killedAt: this.mergeStatValue(base.killedAt, next.killedAt),
conquests: this.mergeStatValue(base.conquests, next.conquests),
conquests: this.mergeStatArrays(base.conquests, next.conquests),
boats: this.mergeStatRecord(base.boats, next.boats),
bombs: this.mergeStatRecord(base.bombs, next.bombs),
gold: this.mergeStatArrays(base.gold, next.gold),
@@ -203,7 +203,7 @@ export class PlayerStatsTreeView extends LitElement {
attacks: stats.attacks ? [...stats.attacks] : undefined,
betrayals: stats.betrayals,
killedAt: stats.killedAt,
conquests: stats.conquests,
conquests: stats.conquests ? [...stats.conquests] : undefined,
boats: stats.boats ? { ...stats.boats } : undefined,
bombs: stats.bombs ? { ...stats.bombs } : undefined,
gold: stats.gold ? [...stats.gold] : undefined,