Replace donate buttons with attack ones for AFK friendly players in radial menu (#2987)

Resolves #2986

## Description:

Shows donate actions in radial menu only when friendly player is NOT
disconnected.
This is needed in order to let mobile/touch users attack AFK teammates.

Current behavior:
<img width="525" height="514" alt="image"
src="https://github.com/user-attachments/assets/78b95e27-443a-4dd5-934b-c8a841b4bf97"
/>

With this PR:
<img width="545" height="457" alt="image"
src="https://github.com/user-attachments/assets/e9792478-6ccd-415f-9199-cff7bfc9356f"
/>


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

deshack_82603
This commit is contained in:
Mattia Migliorini
2026-01-22 13:21:14 +01:00
committed by evanpelle
parent be958dd6c2
commit dfd6a1f5f9
2 changed files with 14 additions and 4 deletions
+3 -1
View File
@@ -134,7 +134,9 @@ export class MainRadialMenu extends LitElement implements Layer {
};
const isFriendlyTarget =
recipient !== null && recipient.isFriendly(myPlayer);
recipient !== null &&
recipient.isFriendly(myPlayer) &&
!recipient.isDisconnected();
this.radialMenu.setCenterButtonAppearance(
isFriendlyTarget ? donateTroopIcon : swordIcon,
@@ -117,6 +117,14 @@ function isFriendlyTarget(params: MenuElementParams): boolean {
return isFriendly.call(selectedPlayer, params.myPlayer);
}
function isDisconnectedTarget(params: MenuElementParams): boolean {
const selectedPlayer = params.selected;
if (selectedPlayer === null) return false;
const isDisconnected = (selectedPlayer as PlayerView).isDisconnected;
if (typeof isDisconnected !== "function") return false;
return isDisconnected.call(selectedPlayer);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const infoChatElement: MenuElement = {
id: "info_chat",
@@ -571,7 +579,7 @@ export const centerButtonElement: CenterButtonElement = {
return false;
}
if (isFriendlyTarget(params)) {
if (isFriendlyTarget(params) && !isDisconnectedTarget(params)) {
return !params.playerActions.interaction?.canDonateTroops;
}
@@ -581,7 +589,7 @@ export const centerButtonElement: CenterButtonElement = {
if (params.game.inSpawnPhase()) {
params.playerActionHandler.handleSpawn(params.tile);
} else {
if (isFriendlyTarget(params)) {
if (isFriendlyTarget(params) && !isDisconnectedTarget(params)) {
const selectedPlayer = params.selected as PlayerView;
const ratio = params.uiState?.attackRatio ?? 1;
const troopsToDonate = Math.floor(ratio * params.myPlayer.troops());
@@ -626,7 +634,7 @@ export const rootMenuElement: MenuElement = {
: [
boatMenuElement,
ally,
isFriendlyTarget(params)
isFriendlyTarget(params) && !isDisconnectedTarget(params)
? donateGoldRadialElement
: attackMenuElement,
]),