diff --git a/resources/lang/en.json b/resources/lang/en.json
index f0ad48559..fdb3e53b5 100644
--- a/resources/lang/en.json
+++ b/resources/lang/en.json
@@ -97,6 +97,8 @@
"action_build": "Open build menu",
"action_emote": "Open emote menu",
"action_center": "Center camera on player",
+ "action_pause_game": "Pause / Resume game",
+ "action_game_speed": "Game speed down / up (single player)",
"action_zoom": "Zoom out/in",
"action_move_camera": "Move camera",
"action_ratio_change": "Decrease/Increase attack ratio",
@@ -571,6 +573,12 @@
"build_menu_modifier_desc": "Hold this key while clicking to open the build menu.",
"emoji_menu_modifier": "Emoji Menu Modifier",
"emoji_menu_modifier_desc": "Hold this key while clicking to open the emoji menu.",
+ "pause_game": "Pause",
+ "pause_game_desc": "Pause or resume the game (single player and custom games for host).",
+ "game_speed_up": "Game Speed Up",
+ "game_speed_up_desc": "Cycle to next game speed (0.5, 1, 2, max). Single player only.",
+ "game_speed_down": "Game Speed Down",
+ "game_speed_down_desc": "Cycle to previous game speed. Single player only.",
"attack_ratio_controls": "Attack Ratio Controls",
"attack_ratio_up": "Increase Attack Ratio",
"attack_ratio_up_desc": "Increase attack ratio by {amount}%",
diff --git a/src/client/HelpModal.ts b/src/client/HelpModal.ts
index c98ce7705..d70accd7e 100644
--- a/src/client/HelpModal.ts
+++ b/src/client/HelpModal.ts
@@ -58,6 +58,9 @@ export class HelpModal extends BaseModal {
modifierKey: isMac ? "MetaLeft" : "ControlLeft",
altKey: "AltLeft",
resetGfx: "KeyR",
+ pauseGame: "KeyP",
+ gameSpeedUp: "Period",
+ gameSpeedDown: "Comma",
...saved,
};
}
@@ -81,6 +84,8 @@ export class HelpModal extends BaseModal {
ArrowDown: "↓",
ArrowLeft: "←",
ArrowRight: "→",
+ Period: ">",
+ Comma: "<",
};
if (specialLabels[code]) return specialLabels[code];
@@ -372,6 +377,25 @@ export class HelpModal extends BaseModal {
${translateText("help_modal.action_center")}
+
|
diff --git a/src/client/InputHandler.ts b/src/client/InputHandler.ts
index 778d284c4..e42d62241 100644
--- a/src/client/InputHandler.ts
+++ b/src/client/InputHandler.ts
@@ -123,6 +123,12 @@ export class ReplaySpeedChangeEvent implements GameEvent {
constructor(public readonly replaySpeedMultiplier: ReplaySpeedMultiplier) {}
}
+export class TogglePauseIntentEvent implements GameEvent {}
+
+export class GameSpeedUpIntentEvent implements GameEvent {}
+
+export class GameSpeedDownIntentEvent implements GameEvent {}
+
export class CenterCameraEvent implements GameEvent {
constructor() {}
}
@@ -236,6 +242,9 @@ export class InputHandler {
buildAtomBomb: "Digit8",
buildHydrogenBomb: "Digit9",
buildMIRV: "Digit0",
+ pauseGame: "KeyP",
+ gameSpeedUp: "Period",
+ gameSpeedDown: "Comma",
...saved,
};
@@ -433,8 +442,20 @@ export class InputHandler {
this.eventBus.emit(new SwapRocketDirectionEvent(nextDirection));
}
+ if (!e.repeat && e.code === this.keybinds.pauseGame) {
+ e.preventDefault();
+ this.eventBus.emit(new TogglePauseIntentEvent());
+ }
+ if (!e.repeat && e.code === this.keybinds.gameSpeedUp) {
+ e.preventDefault();
+ this.eventBus.emit(new GameSpeedUpIntentEvent());
+ }
+ if (!e.repeat && e.code === this.keybinds.gameSpeedDown) {
+ e.preventDefault();
+ this.eventBus.emit(new GameSpeedDownIntentEvent());
+ }
+
// Shift-D to toggle performance overlay
- console.log(e.code, e.shiftKey, e.ctrlKey, e.altKey, e.metaKey);
if (e.code === "KeyD" && e.shiftKey) {
e.preventDefault();
console.log("TogglePerformanceOverlayEvent");
diff --git a/src/client/LocalServer.ts b/src/client/LocalServer.ts
index 58c43306c..e2805235f 100644
--- a/src/client/LocalServer.ts
+++ b/src/client/LocalServer.ts
@@ -20,12 +20,24 @@ import {
} from "../core/Util";
import { getPersistentID } from "./Auth";
import { LobbyConfig } from "./ClientGameRunner";
-import { ReplaySpeedChangeEvent } from "./InputHandler";
+import {
+ GameSpeedDownIntentEvent,
+ GameSpeedUpIntentEvent,
+ ReplaySpeedChangeEvent,
+} from "./InputHandler";
import {
defaultReplaySpeedMultiplier,
ReplaySpeedMultiplier,
} from "./utilities/ReplaySpeedMultiplier";
+// Order: 0.5, 1, 2, max (same as ReplayPanel)
+const SPEED_ORDER: ReplaySpeedMultiplier[] = [
+ ReplaySpeedMultiplier.slow,
+ ReplaySpeedMultiplier.normal,
+ ReplaySpeedMultiplier.fast,
+ ReplaySpeedMultiplier.fastest,
+];
+
// build a small backlog so MAX can catch up.
const MAX_REPLAY_BACKLOG_TURNS = 60;
@@ -94,6 +106,26 @@ export class LocalServer {
this.replaySpeedMultiplier = event.replaySpeedMultiplier;
});
+ if (!this.isReplay) {
+ this.eventBus.on(GameSpeedUpIntentEvent, () => {
+ const idx = SPEED_ORDER.indexOf(this.replaySpeedMultiplier);
+ if (idx < 0 || idx >= SPEED_ORDER.length - 1) return;
+ this.replaySpeedMultiplier = SPEED_ORDER[idx + 1];
+ this.eventBus.emit(
+ new ReplaySpeedChangeEvent(this.replaySpeedMultiplier),
+ );
+ });
+
+ this.eventBus.on(GameSpeedDownIntentEvent, () => {
+ const idx = SPEED_ORDER.indexOf(this.replaySpeedMultiplier);
+ if (idx <= 0) return;
+ this.replaySpeedMultiplier = SPEED_ORDER[idx - 1];
+ this.eventBus.emit(
+ new ReplaySpeedChangeEvent(this.replaySpeedMultiplier),
+ );
+ });
+ }
+
this.startedAt = Date.now();
this.clientConnect();
if (this.lobbyConfig.gameRecord) {
diff --git a/src/client/UserSettingModal.ts b/src/client/UserSettingModal.ts
index 7bf6612d3..cb47ee320 100644
--- a/src/client/UserSettingModal.ts
+++ b/src/client/UserSettingModal.ts
@@ -47,6 +47,9 @@ const DefaultKeybinds: Record = {
moveRight: "KeyD",
modifierKey: isMac ? "MetaLeft" : "ControlLeft",
altKey: "AltLeft",
+ pauseGame: "KeyP",
+ gameSpeedUp: "Period",
+ gameSpeedDown: "Comma",
};
@customElement("user-setting")
@@ -634,6 +637,36 @@ export class UserSettingModal extends BaseModal {
@change=${this.handleKeybindChange}
>
+
+
+
+
+
+
diff --git a/src/client/graphics/layers/GameRightSidebar.ts b/src/client/graphics/layers/GameRightSidebar.ts
index 2d2f78891..f3ddc8278 100644
--- a/src/client/graphics/layers/GameRightSidebar.ts
+++ b/src/client/graphics/layers/GameRightSidebar.ts
@@ -4,6 +4,7 @@ import { EventBus } from "../../../core/EventBus";
import { GameType } from "../../../core/game/Game";
import { GameView } from "../../../core/game/GameView";
import { crazyGamesSDK } from "../../CrazyGamesSDK";
+import { TogglePauseIntentEvent } from "../../InputHandler";
import { PauseGameIntentEvent, SendWinnerEvent } from "../../Transport";
import { translateText } from "../../Utils";
import { ImmunityBarVisibleEvent } from "./ImmunityTimer";
@@ -67,6 +68,14 @@ export class GameRightSidebar extends LitElement implements Layer {
this.requestUpdate();
});
+ this.eventBus.on(TogglePauseIntentEvent, () => {
+ const isReplayOrSingleplayer =
+ this._isSinglePlayer || this.game?.config()?.isReplay();
+ if (isReplayOrSingleplayer || this.isLobbyCreator) {
+ this.onPauseButtonClick();
+ }
+ });
+
this.requestUpdate();
}
diff --git a/src/client/graphics/layers/ReplayPanel.ts b/src/client/graphics/layers/ReplayPanel.ts
index fbef9051d..8c214c2ef 100644
--- a/src/client/graphics/layers/ReplayPanel.ts
+++ b/src/client/graphics/layers/ReplayPanel.ts
@@ -41,6 +41,13 @@ export class ReplayPanel extends LitElement implements Layer {
this.visible = event.visible;
this.isSingleplayer = event.isSingleplayer;
});
+ this.eventBus.on(
+ ReplaySpeedChangeEvent,
+ (event: ReplaySpeedChangeEvent) => {
+ this._replaySpeedMultiplier = event.replaySpeedMultiplier;
+ this.requestUpdate();
+ },
+ );
}
}
|