feat: added retaliate button (#2426)

If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #495 

## Description:

Adds a button to quickly retaliate against a incoming attack

<img width="464" height="212" alt="image"
src="https://github.com/user-attachments/assets/4764d261-a408-4d61-a2d2-2685018aa698"
/>


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

notifxy (1379678982676676639)
This commit is contained in:
Rj Manhas
2025-11-24 10:34:04 -07:00
committed by GitHub
parent 930a79e31c
commit a5cdd23c00
2 changed files with 45 additions and 17 deletions
+1
View File
@@ -575,6 +575,7 @@
},
"events_display": {
"retreating": "retreating",
"retaliate": "Retaliate",
"boat": "Boat",
"alliance_request_status": "{name} {status} your alliance request",
"alliance_accepted": "accepted",
+44 -17
View File
@@ -35,6 +35,7 @@ import {
CancelBoatIntentEvent,
SendAllianceExtensionIntentEvent,
SendAllianceReplyIntentEvent,
SendAttackIntentEvent,
} from "../../Transport";
import { Layer } from "./Layer";
@@ -736,28 +737,54 @@ export class EventsDisplay extends LitElement implements Layer {
}
}
private handleRetaliate(attack: AttackUpdate) {
const attacker = this.game.playerBySmallID(attack.attackerID) as PlayerView;
if (!attacker) return;
const myPlayer = this.game.myPlayer();
if (!myPlayer) return;
// Launch counterattack with the same number of troops as the incoming attack
this.eventBus.emit(new SendAttackIntentEvent(attacker.id(), attack.troops));
}
private renderIncomingAttacks() {
return html`
${this.incomingAttacks.length > 0
? html`
${this.incomingAttacks.map(
(attack) => html`
${this.renderButton({
content: html`
${renderTroops(attack.troops)}
${(
this.game.playerBySmallID(attack.attackerID) as PlayerView
)?.name()}
${attack.retreating
? `(${translateText("events_display.retreating")}...)`
<div class="flex flex-wrap gap-y-1 gap-x-2">
${this.incomingAttacks.map(
(attack) => html`
<div class="inline-flex items-center gap-1">
${this.renderButton({
content: html`
${renderTroops(attack.troops)}
${(
this.game.playerBySmallID(
attack.attackerID,
) as PlayerView
)?.name()}
${attack.retreating
? `(${translateText("events_display.retreating")}...)`
: ""}
`,
onClick: () => this.attackWarningOnClick(attack),
className: "text-left text-red-400",
translate: false,
})}
${!attack.retreating
? this.renderButton({
content: translateText("events_display.retaliate"),
onClick: () => this.handleRetaliate(attack),
className:
"inline-block px-3 py-1 text-white rounded text-md md:text-sm cursor-pointer transition-colors duration-300 bg-red-600 hover:bg-red-700",
translate: true,
})
: ""}
`,
onClick: () => this.attackWarningOnClick(attack),
className: "text-left text-red-400",
translate: false,
})}
`,
)}
</div>
`,
)}
</div>
`
: ""}
`;