mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 12:10:46 +00:00
Add configurable attack ratio keybind increment setting (#2835)
If this PR fixes an issue, link it below. If not, delete these two lines. Resolves #2822 ## Description: Adds an attack ratio keybind increment setting with a new dropdown UI, wires keybinds to use the configured step, updates the attack ratio adjustment logic, and makes the select reflect stored settings. <img width="806" height="165" alt="スクリーンショット 2026-01-12 9 11 12" src="https://github.com/user-attachments/assets/c6eaa96d-e147-4927-b3ed-964e832ecc36" /> ## 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: aotumuri --------- Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com> Co-authored-by: iamlewis <lewismmmm@gmail.com>
This commit is contained in:
@@ -550,9 +550,11 @@
|
||||
"emoji_menu_modifier_desc": "Hold this key while clicking to open the emoji menu.",
|
||||
"attack_ratio_controls": "Attack Ratio Controls",
|
||||
"attack_ratio_up": "Increase Attack Ratio",
|
||||
"attack_ratio_up_desc": "Increase attack ratio by 10%",
|
||||
"attack_ratio_up_desc": "Increase attack ratio by {amount}%",
|
||||
"attack_ratio_down": "Decrease Attack Ratio",
|
||||
"attack_ratio_down_desc": "Decrease attack ratio by 10%",
|
||||
"attack_ratio_down_desc": "Decrease attack ratio by {amount}%",
|
||||
"attack_ratio_increment_label": "Attack Ratio Keybind Increment",
|
||||
"attack_ratio_increment_desc": "How much the attack ratio keybinds change per press.",
|
||||
"attack_keybinds": "Attack Keybinds",
|
||||
"boat_attack": "Boat Attack",
|
||||
"boat_attack_desc": "Send a boat attack to the tile under your cursor.",
|
||||
|
||||
@@ -378,12 +378,14 @@ export class InputHandler {
|
||||
|
||||
if (e.code === this.keybinds.attackRatioDown) {
|
||||
e.preventDefault();
|
||||
this.eventBus.emit(new AttackRatioEvent(-10));
|
||||
const increment = this.userSettings.attackRatioIncrement();
|
||||
this.eventBus.emit(new AttackRatioEvent(-increment));
|
||||
}
|
||||
|
||||
if (e.code === this.keybinds.attackRatioUp) {
|
||||
e.preventDefault();
|
||||
this.eventBus.emit(new AttackRatioEvent(10));
|
||||
const increment = this.userSettings.attackRatioIncrement();
|
||||
this.eventBus.emit(new AttackRatioEvent(increment));
|
||||
}
|
||||
|
||||
if (e.code === this.keybinds.centerCamera) {
|
||||
@@ -538,7 +540,8 @@ export class InputHandler {
|
||||
private onShiftScroll(event: WheelEvent) {
|
||||
if (event.shiftKey) {
|
||||
const scrollValue = event.deltaY === 0 ? event.deltaX : event.deltaY;
|
||||
const ratio = scrollValue > 0 ? -10 : 10;
|
||||
const increment = this.userSettings.attackRatioIncrement();
|
||||
const ratio = scrollValue > 0 ? -increment : increment;
|
||||
this.eventBus.emit(new AttackRatioEvent(ratio));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { UserSettings } from "../core/game/UserSettings";
|
||||
import "./components/baseComponents/setting/SettingKeybind";
|
||||
import { SettingKeybind } from "./components/baseComponents/setting/SettingKeybind";
|
||||
import "./components/baseComponents/setting/SettingNumber";
|
||||
import "./components/baseComponents/setting/SettingSelect";
|
||||
import "./components/baseComponents/setting/SettingSlider";
|
||||
import "./components/baseComponents/setting/SettingToggle";
|
||||
import { BaseModal } from "./components/BaseModal";
|
||||
@@ -361,6 +362,23 @@ export class UserSettingModal extends BaseModal {
|
||||
}
|
||||
}
|
||||
|
||||
private changeAttackRatioIncrement(
|
||||
e: CustomEvent<{ value: number | string }>,
|
||||
) {
|
||||
const rawValue = e.detail?.value;
|
||||
const value =
|
||||
typeof rawValue === "number" ? rawValue : parseInt(String(rawValue), 10);
|
||||
if (!Number.isFinite(value)) {
|
||||
console.warn("Select event missing detail.value", e);
|
||||
return;
|
||||
}
|
||||
this.userSettings.setFloat(
|
||||
"settings.attackRatioIncrement",
|
||||
Math.round(value),
|
||||
);
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private toggleTerritoryPatterns(e: CustomEvent<{ checked: boolean }>) {
|
||||
const enabled = e.detail?.checked;
|
||||
if (typeof enabled !== "boolean") return;
|
||||
@@ -614,7 +632,9 @@ export class UserSettingModal extends BaseModal {
|
||||
<setting-keybind
|
||||
action="attackRatioDown"
|
||||
label=${translateText("user_setting.attack_ratio_down")}
|
||||
description=${translateText("user_setting.attack_ratio_down_desc")}
|
||||
description=${translateText("user_setting.attack_ratio_down_desc", {
|
||||
amount: this.userSettings.attackRatioIncrement(),
|
||||
})}
|
||||
defaultKey="KeyT"
|
||||
.value=${this.getKeyValue("attackRatioDown")}
|
||||
.display=${this.getKeyChar("attackRatioDown")}
|
||||
@@ -624,7 +644,9 @@ export class UserSettingModal extends BaseModal {
|
||||
<setting-keybind
|
||||
action="attackRatioUp"
|
||||
label=${translateText("user_setting.attack_ratio_up")}
|
||||
description=${translateText("user_setting.attack_ratio_up_desc")}
|
||||
description=${translateText("user_setting.attack_ratio_up_desc", {
|
||||
amount: this.userSettings.attackRatioIncrement(),
|
||||
})}
|
||||
defaultKey="KeyY"
|
||||
.value=${this.getKeyValue("attackRatioUp")}
|
||||
.display=${this.getKeyChar("attackRatioUp")}
|
||||
@@ -893,6 +915,21 @@ export class UserSettingModal extends BaseModal {
|
||||
@change=${this.sliderAttackRatio}
|
||||
></setting-slider>
|
||||
|
||||
<!-- ⚔️ Attack Ratio Increment -->
|
||||
<setting-select
|
||||
label=${translateText("user_setting.attack_ratio_increment_label")}
|
||||
description=${translateText("user_setting.attack_ratio_increment_desc")}
|
||||
.options=${[
|
||||
{ value: 1, label: "1%" },
|
||||
{ value: 2, label: "2%" },
|
||||
{ value: 5, label: "5%" },
|
||||
{ value: 10, label: "10%" },
|
||||
{ value: 20, label: "20%" },
|
||||
]}
|
||||
.value=${String(this.userSettings.attackRatioIncrement())}
|
||||
@change=${this.changeAttackRatioIncrement}
|
||||
></setting-select>
|
||||
|
||||
${this.showEasterEggSettings
|
||||
? html`
|
||||
<setting-slider
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
|
||||
type SelectOption = {
|
||||
value: number | string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
@customElement("setting-select")
|
||||
export class SettingSelect extends LitElement {
|
||||
@property() label = "Setting";
|
||||
@property() description = "";
|
||||
@property({ type: Array }) options: SelectOption[] = [];
|
||||
@property({ type: String }) value = "";
|
||||
|
||||
createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private handleChange(e: Event) {
|
||||
const input = e.target as HTMLSelectElement;
|
||||
const selected = this.options.find(
|
||||
(option) => String(option.value) === input.value,
|
||||
);
|
||||
const selectedValue = selected?.value ?? input.value;
|
||||
this.value = String(selectedValue);
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("change", {
|
||||
detail: { value: selectedValue },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div
|
||||
class="flex flex-row items-center justify-between w-full p-4 bg-white/5 border border-white/10 rounded-xl hover:bg-white/10 transition-all gap-4"
|
||||
>
|
||||
<div class="flex flex-col flex-1 min-w-0 mr-4">
|
||||
<label
|
||||
class="text-white font-bold text-base block mb-1"
|
||||
for="setting-select-input"
|
||||
>${this.label}</label
|
||||
>
|
||||
<div class="text-white/50 text-sm leading-snug">
|
||||
${this.description}
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative shrink-0 w-[200px]">
|
||||
<select
|
||||
id="setting-select-input"
|
||||
class="w-full appearance-none py-2 pl-3 pr-9 border border-white/20 rounded-lg bg-black/40 text-white font-mono text-sm focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-all"
|
||||
.value=${String(this.value)}
|
||||
@change=${this.handleChange}
|
||||
>
|
||||
${this.options.map(
|
||||
(option) =>
|
||||
html`<option
|
||||
value=${String(option.value)}
|
||||
?selected=${String(option.value) === String(this.value)}
|
||||
>
|
||||
${option.label}
|
||||
</option>`,
|
||||
)}
|
||||
</select>
|
||||
<span
|
||||
class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-white/60"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.24a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -222,6 +222,14 @@ export class UserSettings {
|
||||
this.setFloat("settings.backgroundMusicVolume", volume);
|
||||
}
|
||||
|
||||
attackRatioIncrement(): number {
|
||||
const increment = Math.round(
|
||||
this.getFloat("settings.attackRatioIncrement", 10),
|
||||
);
|
||||
if (!Number.isFinite(increment) || increment <= 0) return 10;
|
||||
return increment;
|
||||
}
|
||||
|
||||
soundEffectsVolume(): number {
|
||||
return this.getFloat("settings.soundEffectsVolume", 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user