## Description:

Make the unit display bar a proper unit build bar
Add shortcuts for all structures and units
Add ranges for ranged structures and units
Changed the shortcuts to use the key instead of the code for
internationalization purposes


![buildbar](https://github.com/user-attachments/assets/6407dc9c-14b4-40cc-8faa-cdd9e88c9fd2)
<img width="285" height="517" alt="image"
src="https://github.com/user-attachments/assets/91bb01e6-e48c-4255-ace1-306af9cdc25b"
/>

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

Mr.Box

---------

Co-authored-by: evanpelle <evanpelle@gmail.com>
Co-authored-by: icslucas <carolinacarazolli@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Vivacious Box
2025-10-02 21:38:28 +02:00
committed by GitHub
parent 6061c97d78
commit 311d43ab4f
17 changed files with 1283 additions and 515 deletions
+87 -5
View File
@@ -2,6 +2,7 @@ import { EventBus, GameEvent } from "../core/EventBus";
import { UnitType } from "../core/game/Game";
import { UnitView } from "../core/game/GameView";
import { UserSettings } from "../core/game/UserSettings";
import { UIState } from "./graphics/UIState";
import { ReplaySpeedMultiplier } from "./utilities/ReplaySpeedMultiplier";
export class MouseUpEvent implements GameEvent {
@@ -75,7 +76,7 @@ export class RefreshGraphicsEvent implements GameEvent {}
export class TogglePerformanceOverlayEvent implements GameEvent {}
export class ToggleStructureEvent implements GameEvent {
constructor(public readonly structureType: UnitType | null) {}
constructor(public readonly structureTypes: UnitType[] | null) {}
}
export class ShowBuildMenuEvent implements GameEvent {
@@ -136,14 +137,36 @@ export class InputHandler {
private readonly PAN_SPEED = 5;
private readonly ZOOM_SPEED = 10;
private userSettings: UserSettings = new UserSettings();
private readonly userSettings: UserSettings = new UserSettings();
constructor(
public uiState: UIState,
private canvas: HTMLCanvasElement,
private eventBus: EventBus,
) {}
initialize() {
let saved: Record<string, string> = {};
try {
const parsed = JSON.parse(
localStorage.getItem("settings.keybinds") ?? "{}",
);
// flatten { key: {key, value} } → { key: value } and accept legacy string values
saved = Object.fromEntries(
Object.entries(parsed)
.map(([k, v]) => {
if (v && typeof v === "object" && "value" in (v as any)) {
return [k, (v as any).value as string];
}
if (typeof v === "string") return [k, v];
return [k, undefined];
})
.filter(([, v]) => typeof v === "string" && v !== "Null"),
) as Record<string, string>;
} catch (e) {
console.warn("Invalid keybinds JSON:", e);
}
this.keybinds = {
toggleView: "Space",
centerCamera: "KeyC",
@@ -153,13 +176,22 @@ export class InputHandler {
moveRight: "KeyD",
zoomOut: "KeyQ",
zoomIn: "KeyE",
attackRatioDown: "Digit1",
attackRatioUp: "Digit2",
attackRatioDown: "KeyT",
attackRatioUp: "KeyY",
boatAttack: "KeyB",
groundAttack: "KeyG",
modifierKey: "ControlLeft",
altKey: "AltLeft",
...JSON.parse(localStorage.getItem("settings.keybinds") ?? "{}"),
buildCity: "Digit1",
buildFactory: "Digit2",
buildPort: "Digit3",
buildDefensePost: "Digit4",
buildMissileSilo: "Digit5",
buildSamLauncher: "Digit6",
buildAtomBomb: "Digit7",
buildHydrogenBomb: "Digit8",
buildWarship: "Digit9",
...saved,
};
// Mac users might have different keybinds
@@ -266,6 +298,7 @@ export class InputHandler {
if (e.code === "Escape") {
e.preventDefault();
this.eventBus.emit(new CloseViewEvent());
this.uiState.ghostStructure = null;
}
if (
@@ -331,6 +364,51 @@ export class InputHandler {
this.eventBus.emit(new CenterCameraEvent());
}
if (e.code === this.keybinds.buildCity) {
e.preventDefault();
this.uiState.ghostStructure = UnitType.City;
}
if (e.code === this.keybinds.buildFactory) {
e.preventDefault();
this.uiState.ghostStructure = UnitType.Factory;
}
if (e.code === this.keybinds.buildPort) {
e.preventDefault();
this.uiState.ghostStructure = UnitType.Port;
}
if (e.code === this.keybinds.buildDefensePost) {
e.preventDefault();
this.uiState.ghostStructure = UnitType.DefensePost;
}
if (e.code === this.keybinds.buildMissileSilo) {
e.preventDefault();
this.uiState.ghostStructure = UnitType.MissileSilo;
}
if (e.code === this.keybinds.buildSamLauncher) {
e.preventDefault();
this.uiState.ghostStructure = UnitType.SAMLauncher;
}
if (e.code === this.keybinds.buildAtomBomb) {
e.preventDefault();
this.uiState.ghostStructure = UnitType.AtomBomb;
}
if (e.code === this.keybinds.buildHydrogenBomb) {
e.preventDefault();
this.uiState.ghostStructure = UnitType.HydrogenBomb;
}
if (e.code === this.keybinds.buildWarship) {
e.preventDefault();
this.uiState.ghostStructure = UnitType.Warship;
}
// Shift-D to toggle performance overlay
console.log(e.code, e.shiftKey, e.ctrlKey, e.altKey, e.metaKey);
if (e.code === "KeyD" && e.shiftKey) {
@@ -489,6 +567,10 @@ export class InputHandler {
private onContextMenu(event: MouseEvent) {
event.preventDefault();
if (this.uiState.ghostStructure !== null) {
this.uiState.ghostStructure = null;
return;
}
this.eventBus.emit(new ContextMenuEvent(event.clientX, event.clientY));
}