outgoing attacks (#3398)

## Description:

Show outgoing attacks on the PlayerInfoPanel. Also update the
AttacksDisplay so it uses the same icon for incoming & outgoing attacks

<img width="502" height="97" alt="Screenshot 2026-03-10 at 2 02 49 PM"
src="https://github.com/user-attachments/assets/de83bf4d-b1b9-4fec-a8c6-e25bbf82c942"
/>

<img width="483" height="167" alt="Screenshot 2026-03-10 at 2 03 02 PM"
src="https://github.com/user-attachments/assets/cf43106f-5f3a-4a78-abae-dff019de4fb4"
/>

<img width="509" height="203" alt="Screenshot 2026-03-10 at 2 03 28 PM"
src="https://github.com/user-attachments/assets/79db2081-dd93-4ff4-aaa7-75281c16c037"
/>


## 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
2026-03-10 14:08:31 -07:00
committed by GitHub
parent 8eb879aff4
commit 3a195005d8
2 changed files with 57 additions and 37 deletions
+24 -26
View File
@@ -22,6 +22,7 @@ import {
GoToPositionEvent,
GoToUnitEvent,
} from "./Leaderboard";
import soldierIcon from "/images/SoldierIcon.svg?url";
import swordIcon from "/images/SwordIcon.svg?url";
@customElement("attacks-display")
@@ -224,14 +225,13 @@ export class AttacksDisplay extends LitElement implements Layer {
class="flex items-center gap-0.5 w-full bg-gray-800/70 backdrop-blur-xs sm:rounded-lg px-1.5 py-0.5 overflow-hidden"
>
${this.renderButton({
content: html`<img
src="${swordIcon}"
class="h-4 w-4 inline-block"
style="filter: brightness(0) saturate(100%) invert(27%) sepia(91%) saturate(4551%) hue-rotate(348deg) brightness(89%) contrast(97%)"
/>
<span class="inline-block min-w-[3rem] text-right"
>${renderTroops(attack.troops)}</span
>
content: html`<span class="inline-flex items-center"
><img
src="${soldierIcon}"
class="h-4 w-4"
style="filter: brightness(0) saturate(100%) invert(27%) sepia(91%) saturate(4551%) hue-rotate(348deg) brightness(89%) contrast(97%)"
/>↓</span
><span class="ml-1">${renderTroops(attack.troops)}</span>
<span class="truncate ml-1"
>${(
this.game.playerBySmallID(attack.attackerID) as PlayerView
@@ -272,14 +272,13 @@ export class AttacksDisplay extends LitElement implements Layer {
class="flex items-center gap-0.5 w-full bg-gray-800/70 backdrop-blur-xs sm:rounded-lg px-1.5 py-0.5 overflow-hidden"
>
${this.renderButton({
content: html`<img
src="${swordIcon}"
class="h-4 w-4 inline-block"
style="filter: invert(1)"
/>
<span class="inline-block min-w-[3rem] text-right"
>${renderTroops(attack.troops)}</span
>
content: html`<span class="inline-flex items-center"
><img
src="${soldierIcon}"
class="h-4 w-4"
style="filter: brightness(0) saturate(100%) invert(62%) sepia(80%) saturate(500%) hue-rotate(175deg) brightness(100%)"
/>↑</span
><span class="ml-1">${renderTroops(attack.troops)}</span>
<span class="truncate ml-1"
>${(
this.game.playerBySmallID(attack.targetID) as PlayerView
@@ -287,7 +286,7 @@ export class AttacksDisplay extends LitElement implements Layer {
> `,
onClick: async () => this.attackWarningOnClick(attack),
className:
"text-left text-blue-400 inline-flex items-center gap-0.5 lg:gap-1 min-w-0",
"text-left text-sky-400 inline-flex items-center gap-0.5 lg:gap-1 min-w-0",
translate: false,
})}
${!attack.retreating
@@ -314,17 +313,16 @@ export class AttacksDisplay extends LitElement implements Layer {
class="flex items-center gap-0.5 w-full bg-gray-800/70 backdrop-blur-xs sm:rounded-lg px-1.5 py-0.5 overflow-hidden"
>
${this.renderButton({
content: html`<img
src="${swordIcon}"
class="h-4 w-4 inline-block"
style="filter: invert(1)"
/>
<span class="inline-block min-w-[3rem] text-right"
>${renderTroops(landAttack.troops)}</span
>
content: html`<span class="inline-flex items-center"
><img
src="${soldierIcon}"
class="h-4 w-4"
style="filter: brightness(0) saturate(100%) invert(62%) sepia(80%) saturate(500%) hue-rotate(175deg) brightness(100%)"
/>↑</span
><span class="ml-1">${renderTroops(landAttack.troops)}</span>
${translateText("help_modal.ui_wilderness")}`,
className:
"text-left text-gray-400 inline-flex items-center gap-0.5 lg:gap-1 min-w-0",
"text-left text-sky-400 inline-flex items-center gap-0.5 lg:gap-1 min-w-0",
translate: false,
})}
${!landAttack.retreating
+33 -11
View File
@@ -318,17 +318,39 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
const playerTeam = getTranslatedPlayerTeamLabel(player.team());
return html`
<div class="flex items-start gap-2 lg:gap-3 p-1.5 lg:p-2">
<div class="flex items-start gap-1 lg:gap-2 p-1.5 lg:p-2">
<!-- Left: Gold & Troop bar -->
<div class="flex flex-col gap-1 shrink-0 w-28">
<div
class="flex items-center justify-center p-1 border rounded-md border-yellow-400 font-bold text-yellow-400 text-xs w-28 lg:gap-1"
translate="no"
>
<img src=${goldCoinIcon} width="13" height="13" />
<span class="px-0.5">${renderNumber(player.gold())}</span>
<div class="flex flex-col gap-1 shrink-0 w-36">
<div class="flex items-center gap-1">
<div
class="flex flex-1 items-center justify-center p-1 border rounded-md border-yellow-400 font-bold text-yellow-400 text-sm lg:gap-1"
translate="no"
>
<img src=${goldCoinIcon} width="13" height="13" />
<span class="px-0.5">${renderNumber(player.gold())}</span>
</div>
<div
class="flex flex-1 flex-col items-center justify-center text-xs font-bold ${attackingTroops >
0
? "text-sky-400"
: "text-white/40"} drop-shadow-[0_1px_1px_rgba(0,0,0,0.8)]"
translate="no"
>
<span class="flex items-center gap-px leading-none text-xs"
><img
src=${soldierIcon}
class="w-2.5 h-2.5"
style="${attackingTroops > 0
? "filter: brightness(0) saturate(100%) invert(62%) sepia(80%) saturate(500%) hue-rotate(175deg) brightness(100%); opacity:1"
: "filter: brightness(0) invert(1); opacity:0.4"}"
/>↑</span
>
<span class="tabular-nums leading-none text-sm mt-0.5"
>${renderTroops(attackingTroops)}</span
>
</div>
</div>
<div class="w-28" translate="no">
<div class="w-36" translate="no">
${this.renderTroopBar(totalTroops, attackingTroops, maxTroops)}
</div>
</div>
@@ -418,7 +440,7 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
return html`
<div
class="w-full mt-1 lg:mt-2 h-5 lg:h-6 border border-gray-600 rounded-md bg-gray-900/60 overflow-hidden relative"
class="w-full mt-0.5 lg:mt-1 h-5 lg:h-6 border border-gray-600 rounded-md bg-gray-900/60 overflow-hidden relative"
>
<div class="h-full flex">
${greenPercent > 0
@@ -435,7 +457,7 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
: ""}
</div>
<div
class="absolute inset-0 flex items-center justify-between px-1.5 text-xs font-bold leading-none pointer-events-none"
class="absolute inset-0 flex items-center justify-between px-1.5 text-sm font-bold leading-none pointer-events-none"
translate="no"
>
<span class="text-white drop-shadow-[0_1px_1px_rgba(0,0,0,0.8)]"