mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 12:40:46 +00:00
Feature Add retaliate keybind (#3801)
If this PR fixes an issue, link it below. If not, delete these two lines. Resolves #3174 ## Description: This PR implements a keybind for retaliation against incoming non-bot attacks (Players and Nations). It currently will target the most recent (last in array) incoming attack when the keybind is pressed, choosing the minimum of attack ratio or incoming attack troop size to retaliate with. This correlates with the last displayed incoming attack on the bottom modal. It works when there are multiple attacks (press multiple times to retaliate against each consecutive attack). If the retaliation size is smaller than the attack, the keybind can be pressed multiple times to repeatedly blunt the incoming troop count. Due to the current keybind logic KeyR cannot be used but Shift+KeyR can so it is set to that until refactor. <img width="867" height="121" alt="image" src="https://github.com/user-attachments/assets/56e80810-4900-4db0-8ce7-1856e13529e5" /> No tests have been added as the retaliation feature doesn't seem to have any to begin with since it is just an attack intent. The keybind is not configured any differently than others. I did run all current tests and was all good. ## 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: n1ghtingal3
This commit is contained in:
@@ -749,6 +749,8 @@
|
||||
"boat_attack_desc": "Send a boat attack to the tile under your cursor.",
|
||||
"ground_attack": "Ground Attack",
|
||||
"ground_attack_desc": "Send a ground attack to the tile under your cursor.",
|
||||
"retaliate_attack": "Retaliate",
|
||||
"retaliate_attack_desc": "Send a retaliation attack to blunt/negate the force of the most recent active attacker. Only available when you are being attacked.",
|
||||
"ally_keybinds": "Ally Keybinds",
|
||||
"request_alliance": "Request Alliance",
|
||||
"request_alliance_desc": "Send an alliance request to the player whose tile is under your cursor.",
|
||||
|
||||
@@ -13,7 +13,12 @@ import {
|
||||
import { createPartialGameRecord, findClosestBy, replacer } from "../core/Util";
|
||||
import { ServerConfig } from "../core/configuration/Config";
|
||||
import { getGameLogicConfig } from "../core/configuration/ConfigLoader";
|
||||
import { BuildableUnit, Structures, UnitType } from "../core/game/Game";
|
||||
import {
|
||||
BuildableUnit,
|
||||
PlayerType,
|
||||
Structures,
|
||||
UnitType,
|
||||
} from "../core/game/Game";
|
||||
import { TileRef } from "../core/game/GameMap";
|
||||
import { GameMapLoader } from "../core/game/GameMapLoader";
|
||||
import {
|
||||
@@ -34,6 +39,7 @@ import {
|
||||
DoBreakAllianceEvent,
|
||||
DoGroundAttackEvent,
|
||||
DoRequestAllianceEvent,
|
||||
DoRetaliateAttackEvent,
|
||||
InputHandler,
|
||||
MouseMoveEvent,
|
||||
MouseUpEvent,
|
||||
@@ -391,6 +397,10 @@ export class ClientGameRunner {
|
||||
DoGroundAttackEvent,
|
||||
this.doGroundAttackUnderCursor.bind(this),
|
||||
);
|
||||
this.eventBus.on(
|
||||
DoRetaliateAttackEvent,
|
||||
this.doRetaliateAttackMostRecent.bind(this),
|
||||
);
|
||||
this.eventBus.on(
|
||||
DoRequestAllianceEvent,
|
||||
this.doRequestAllianceUnderCursor.bind(this),
|
||||
@@ -783,6 +793,41 @@ export class ClientGameRunner {
|
||||
});
|
||||
}
|
||||
|
||||
private doRetaliateAttackMostRecent(): void {
|
||||
if (!this.isActive || this.gameView.inSpawnPhase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.myPlayer === null) {
|
||||
if (!this.clientID) return;
|
||||
const myPlayer = this.gameView.playerByClientID(this.clientID);
|
||||
if (myPlayer === null) return;
|
||||
this.myPlayer = myPlayer;
|
||||
}
|
||||
|
||||
const incomingAttacks = this.myPlayer.incomingAttacks().filter((a) => {
|
||||
const t = (
|
||||
this.gameView.playerBySmallID(a.attackerID) as PlayerView
|
||||
).type();
|
||||
return t !== PlayerType.Bot;
|
||||
});
|
||||
|
||||
if (incomingAttacks.length === 0) return;
|
||||
|
||||
const mostRecentAttack = incomingAttacks[incomingAttacks.length - 1];
|
||||
|
||||
const attacker = this.gameView.playerBySmallID(
|
||||
mostRecentAttack.attackerID,
|
||||
) as PlayerView;
|
||||
if (!attacker) return;
|
||||
|
||||
const counterTroops = Math.min(
|
||||
mostRecentAttack.troops,
|
||||
this.renderer.uiState.attackRatio * this.myPlayer.troops(),
|
||||
);
|
||||
this.eventBus.emit(new SendAttackIntentEvent(attacker.id(), counterTroops));
|
||||
}
|
||||
|
||||
private doRequestAllianceUnderCursor(): void {
|
||||
const tile = this.getTileUnderCursor();
|
||||
if (tile === null) return;
|
||||
|
||||
@@ -153,6 +153,8 @@ export class DoBoatAttackEvent implements GameEvent {}
|
||||
|
||||
export class DoGroundAttackEvent implements GameEvent {}
|
||||
|
||||
export class DoRetaliateAttackEvent implements GameEvent {}
|
||||
|
||||
export class DoRequestAllianceEvent implements GameEvent {}
|
||||
|
||||
export class DoBreakAllianceEvent implements GameEvent {}
|
||||
@@ -496,6 +498,11 @@ export class InputHandler {
|
||||
this.eventBus.emit(new DoGroundAttackEvent());
|
||||
}
|
||||
|
||||
if (this.keybindMatchesEvent(e, this.keybinds.retaliateAttack)) {
|
||||
e.preventDefault();
|
||||
this.eventBus.emit(new DoRetaliateAttackEvent());
|
||||
}
|
||||
|
||||
if (this.keybindMatchesEvent(e, this.keybinds.attackRatioDown)) {
|
||||
e.preventDefault();
|
||||
const increment = this.userSettings.attackRatioIncrement();
|
||||
|
||||
@@ -647,6 +647,16 @@ export class UserSettingModal extends BaseModal {
|
||||
@change=${this.handleKeybindChange}
|
||||
></setting-keybind>
|
||||
|
||||
<setting-keybind
|
||||
action="retaliateAttack"
|
||||
label=${translateText("user_setting.retaliate_attack")}
|
||||
description=${translateText("user_setting.retaliate_attack_desc")}
|
||||
defaultKey="Shift+KeyR"
|
||||
.value=${this.getKeyValue("retaliateAttack")}
|
||||
.display=${this.getKeyChar("retaliateAttack")}
|
||||
@change=${this.handleKeybindChange}
|
||||
></setting-keybind>
|
||||
|
||||
<setting-keybind
|
||||
action="swapDirection"
|
||||
label=${translateText("user_setting.swap_direction")}
|
||||
|
||||
@@ -19,6 +19,7 @@ export function getDefaultKeybinds(isMac: boolean): Record<string, string> {
|
||||
attackRatioUp: "KeyY",
|
||||
boatAttack: "KeyB",
|
||||
groundAttack: "KeyG",
|
||||
retaliateAttack: "Shift+KeyR",
|
||||
requestAlliance: "KeyK",
|
||||
breakAlliance: "KeyL",
|
||||
swapDirection: "KeyU",
|
||||
|
||||
Reference in New Issue
Block a user