Feat: Add troop count bar to PlayerInfoOverlay (#2773)

## Description:

This feature adds a troop count bar into the PlayerInfoOverlay that
visualizes how many troops a player/nation has, how big of an attack
they are sending, and in general the percentages of their overall troop
count. I originally added the toggling of this feature as a setting but
thought it might be too narrow to need it's own setting. Would
appreciate anyone's thoughts on adding it back in or not.

Inspired by [this
comment](https://discord.com/channels/1359946986937258015/1359949371956789289/1452559404401430674)
in the Dev Discord.

### Video Demo


https://github.com/user-attachments/assets/4a4397f7-c0a1-475a-867d-ef00b57661c4



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

bijx
This commit is contained in:
bijx
2026-01-02 19:19:51 -05:00
committed by GitHub
parent 5f4efacea2
commit cdecdc5fa5
@@ -259,6 +259,7 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
.outgoingAttacks()
.map((a) => a.troops)
.reduce((a, b) => a + b, 0);
const totalTroops = player.troops();
if (player.type() === PlayerType.Nation && myPlayer !== null && !isAllied) {
const relation =
@@ -378,6 +379,7 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
</span>
</div>`
: ""}
${this.renderTroopBar(totalTroops, attackingTroops, maxTroops)}
<div
class="flex p-1 mb-1 mt-1 w-full border rounded-md border-yellow-400
font-bold text-yellow-400 text-sm opacity-80"
@@ -438,6 +440,43 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
`;
}
private renderTroopBar(
totalTroops: number,
attackingTroops: number,
maxTroops: number,
) {
const base = Math.max(maxTroops, 1);
const greenPercentRaw = (totalTroops / base) * 100;
const orangePercentRaw = (attackingTroops / base) * 100;
const greenPercent = Math.max(0, Math.min(100, greenPercentRaw));
const orangePercent = Math.max(
0,
Math.min(100 - greenPercent, orangePercentRaw),
);
return html`
<div
class="w-full mt-2 mb-2 h-5 border border-gray-600 rounded-md bg-gray-900/60 overflow-hidden"
>
<div class="h-full flex">
${greenPercent > 0
? html`<div
class="h-full bg-green-500 transition-[width] duration-200"
style="width: ${greenPercent}%;"
></div>`
: ""}
${orangePercent > 0
? html`<div
class="h-full bg-orange-400 transition-[width] duration-200"
style="width: ${orangePercent}%;"
></div>`
: ""}
</div>
</div>
`;
}
private renderUnitInfo(unit: UnitView) {
const isAlly =
(unit.owner() === this.game.myPlayer() ||