mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-13 18:21:51 +00:00
Minor Keybindings refactor, add support for keybindings to mods, add support for dialogs to mods
This commit is contained in:
parent
3cfd4aaebd
commit
8a60acc6e3
@ -89,10 +89,10 @@
|
|||||||
@include S(border-radius, $globalBorderRadius);
|
@include S(border-radius, $globalBorderRadius);
|
||||||
background: $accentColorBright;
|
background: $accentColorBright;
|
||||||
@include S(margin-bottom, 4px);
|
@include S(margin-bottom, 4px);
|
||||||
@include S(padding, 7px);
|
@include S(padding, 7px, 10px);
|
||||||
@include S(grid-gap, 5px);
|
@include S(grid-gap, 15px);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr D(100px) D(100px) D(100px);
|
grid-template-columns: 1fr D(100px) D(80px) D(50px);
|
||||||
|
|
||||||
.checkbox {
|
.checkbox {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
@ -120,6 +120,7 @@
|
|||||||
.author {
|
.author {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
align-self: center;
|
||||||
strong {
|
strong {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: $accentColorDark;
|
color: $accentColorDark;
|
||||||
|
|||||||
@ -105,10 +105,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.privacy {
|
|
||||||
@include S(margin-top, 4px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.versionbar {
|
.versionbar {
|
||||||
@include S(margin-top, 10px);
|
@include S(margin-top, 10px);
|
||||||
|
|
||||||
|
|||||||
@ -211,6 +211,7 @@ export class InputDistributor {
|
|||||||
keyCode: keyCode,
|
keyCode: keyCode,
|
||||||
shift: event.shiftKey,
|
shift: event.shiftKey,
|
||||||
alt: event.altKey,
|
alt: event.altKey,
|
||||||
|
ctrl: event.ctrlKey,
|
||||||
initial: isInitial,
|
initial: isInitial,
|
||||||
event,
|
event,
|
||||||
}) === STOP_PROPAGATION
|
}) === STOP_PROPAGATION
|
||||||
|
|||||||
@ -90,8 +90,9 @@ export class Dialog {
|
|||||||
* @param {number} param0.keyCode
|
* @param {number} param0.keyCode
|
||||||
* @param {boolean} param0.shift
|
* @param {boolean} param0.shift
|
||||||
* @param {boolean} param0.alt
|
* @param {boolean} param0.alt
|
||||||
|
* @param {boolean} param0.ctrl
|
||||||
*/
|
*/
|
||||||
handleKeydown({ keyCode, shift, alt }) {
|
handleKeydown({ keyCode, shift, alt, ctrl }) {
|
||||||
if (keyCode === kbEnter && this.enterHandler) {
|
if (keyCode === kbEnter && this.enterHandler) {
|
||||||
this.internalButtonHandler(this.enterHandler);
|
this.internalButtonHandler(this.enterHandler);
|
||||||
return STOP_PROPAGATION;
|
return STOP_PROPAGATION;
|
||||||
|
|||||||
@ -7,118 +7,152 @@ import { Application } from "../application";
|
|||||||
import { Signal, STOP_PROPAGATION } from "../core/signal";
|
import { Signal, STOP_PROPAGATION } from "../core/signal";
|
||||||
import { IS_MOBILE } from "../core/config";
|
import { IS_MOBILE } from "../core/config";
|
||||||
import { T } from "../translations";
|
import { T } from "../translations";
|
||||||
function key(str) {
|
|
||||||
|
export function keyToKeyCode(str) {
|
||||||
return str.toUpperCase().charCodeAt(0);
|
return str.toUpperCase().charCodeAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const KEYCODE_UP_ARROW = 38;
|
export const KEYCODES = {
|
||||||
const KEYCODE_DOWN_ARROW = 40;
|
Tab: 9,
|
||||||
const KEYCODE_LEFT_ARROW = 37;
|
Enter: 13,
|
||||||
const KEYCODE_RIGHT_ARROW = 39;
|
|
||||||
|
Shift: 16,
|
||||||
|
Ctrl: 17,
|
||||||
|
Alt: 18,
|
||||||
|
|
||||||
|
Escape: 27,
|
||||||
|
|
||||||
|
Space: 32,
|
||||||
|
|
||||||
|
ArrowLeft: 37,
|
||||||
|
ArrowUp: 38,
|
||||||
|
ArrowRight: 39,
|
||||||
|
ArrowDown: 40,
|
||||||
|
|
||||||
|
Delete: 46,
|
||||||
|
|
||||||
|
F1: 112,
|
||||||
|
F2: 113,
|
||||||
|
F3: 114,
|
||||||
|
F4: 115,
|
||||||
|
F5: 116,
|
||||||
|
F6: 117,
|
||||||
|
F7: 118,
|
||||||
|
F8: 119,
|
||||||
|
F9: 120,
|
||||||
|
F10: 121,
|
||||||
|
F11: 122,
|
||||||
|
F12: 123,
|
||||||
|
|
||||||
|
Plus: 187,
|
||||||
|
Minus: 189,
|
||||||
|
};
|
||||||
|
|
||||||
export const KEYMAPPINGS = {
|
export const KEYMAPPINGS = {
|
||||||
|
// Make sure mods come first so they can override everything
|
||||||
|
mods: {},
|
||||||
|
|
||||||
general: {
|
general: {
|
||||||
confirm: { keyCode: 13 }, // enter
|
confirm: { keyCode: KEYCODES.Enter },
|
||||||
back: { keyCode: 27, builtin: true }, // escape
|
back: { keyCode: KEYCODES.Escape, builtin: true },
|
||||||
},
|
},
|
||||||
|
|
||||||
ingame: {
|
ingame: {
|
||||||
menuOpenShop: { keyCode: key("F") },
|
menuOpenShop: { keyCode: keyToKeyCode("F") },
|
||||||
menuOpenStats: { keyCode: key("G") },
|
menuOpenStats: { keyCode: keyToKeyCode("G") },
|
||||||
menuClose: { keyCode: key("Q") },
|
menuClose: { keyCode: keyToKeyCode("Q") },
|
||||||
|
|
||||||
toggleHud: { keyCode: 113 }, // F2
|
toggleHud: { keyCode: KEYCODES.F2 },
|
||||||
exportScreenshot: { keyCode: 114 }, // F3PS
|
exportScreenshot: { keyCode: KEYCODES.F3 },
|
||||||
toggleFPSInfo: { keyCode: 115 }, // F4
|
toggleFPSInfo: { keyCode: KEYCODES.F4 },
|
||||||
|
|
||||||
switchLayers: { keyCode: key("E") },
|
switchLayers: { keyCode: keyToKeyCode("E") },
|
||||||
|
|
||||||
showShapeTooltip: { keyCode: 18 }, // ALT
|
showShapeTooltip: { keyCode: KEYCODES.Alt },
|
||||||
},
|
},
|
||||||
|
|
||||||
navigation: {
|
navigation: {
|
||||||
mapMoveUp: { keyCode: key("W") },
|
mapMoveUp: { keyCode: keyToKeyCode("W") },
|
||||||
mapMoveRight: { keyCode: key("D") },
|
mapMoveRight: { keyCode: keyToKeyCode("D") },
|
||||||
mapMoveDown: { keyCode: key("S") },
|
mapMoveDown: { keyCode: keyToKeyCode("S") },
|
||||||
mapMoveLeft: { keyCode: key("A") },
|
mapMoveLeft: { keyCode: keyToKeyCode("A") },
|
||||||
mapMoveFaster: { keyCode: 16 }, //shift
|
mapMoveFaster: { keyCode: KEYCODES.Shift },
|
||||||
|
|
||||||
centerMap: { keyCode: 32 }, // SPACE
|
centerMap: { keyCode: KEYCODES.Space },
|
||||||
mapZoomIn: { keyCode: 187, repeated: true }, // "+"
|
mapZoomIn: { keyCode: KEYCODES.Plus, repeated: true },
|
||||||
mapZoomOut: { keyCode: 189, repeated: true }, // "-"
|
mapZoomOut: { keyCode: KEYCODES.Minus, repeated: true },
|
||||||
|
createMarker: { keyCode: keyToKeyCode("M") },
|
||||||
createMarker: { keyCode: key("M") },
|
|
||||||
},
|
},
|
||||||
|
|
||||||
buildings: {
|
buildings: {
|
||||||
// Puzzle buildings
|
// Puzzle buildings
|
||||||
constant_producer: { keyCode: key("H") },
|
constant_producer: { keyCode: keyToKeyCode("H") },
|
||||||
goal_acceptor: { keyCode: key("N") },
|
goal_acceptor: { keyCode: keyToKeyCode("N") },
|
||||||
block: { keyCode: key("4") },
|
block: { keyCode: keyToKeyCode("4") },
|
||||||
|
|
||||||
// Primary Toolbar
|
// Primary Toolbar
|
||||||
belt: { keyCode: key("1") },
|
belt: { keyCode: keyToKeyCode("1") },
|
||||||
balancer: { keyCode: key("2") },
|
balancer: { keyCode: keyToKeyCode("2") },
|
||||||
underground_belt: { keyCode: key("3") },
|
underground_belt: { keyCode: keyToKeyCode("3") },
|
||||||
miner: { keyCode: key("4") },
|
miner: { keyCode: keyToKeyCode("4") },
|
||||||
cutter: { keyCode: key("5") },
|
cutter: { keyCode: keyToKeyCode("5") },
|
||||||
rotater: { keyCode: key("6") },
|
rotater: { keyCode: keyToKeyCode("6") },
|
||||||
stacker: { keyCode: key("7") },
|
stacker: { keyCode: keyToKeyCode("7") },
|
||||||
mixer: { keyCode: key("8") },
|
mixer: { keyCode: keyToKeyCode("8") },
|
||||||
painter: { keyCode: key("9") },
|
painter: { keyCode: keyToKeyCode("9") },
|
||||||
trash: { keyCode: key("0") },
|
trash: { keyCode: keyToKeyCode("0") },
|
||||||
|
|
||||||
// Sandbox
|
// Sandbox
|
||||||
item_producer: { keyCode: key("L") },
|
item_producer: { keyCode: keyToKeyCode("L") },
|
||||||
|
|
||||||
// Secondary toolbar
|
// Secondary toolbar
|
||||||
storage: { keyCode: key("Y") },
|
storage: { keyCode: keyToKeyCode("Y") },
|
||||||
reader: { keyCode: key("U") },
|
reader: { keyCode: keyToKeyCode("U") },
|
||||||
lever: { keyCode: key("I") },
|
lever: { keyCode: keyToKeyCode("I") },
|
||||||
filter: { keyCode: key("O") },
|
filter: { keyCode: keyToKeyCode("O") },
|
||||||
display: { keyCode: key("P") },
|
display: { keyCode: keyToKeyCode("P") },
|
||||||
|
|
||||||
// Wires toolbar
|
// Wires toolbar
|
||||||
wire: { keyCode: key("1") },
|
wire: { keyCode: keyToKeyCode("1") },
|
||||||
wire_tunnel: { keyCode: key("2") },
|
wire_tunnel: { keyCode: keyToKeyCode("2") },
|
||||||
constant_signal: { keyCode: key("3") },
|
constant_signal: { keyCode: keyToKeyCode("3") },
|
||||||
logic_gate: { keyCode: key("4") },
|
logic_gate: { keyCode: keyToKeyCode("4") },
|
||||||
virtual_processor: { keyCode: key("5") },
|
virtual_processor: { keyCode: keyToKeyCode("5") },
|
||||||
analyzer: { keyCode: key("6") },
|
analyzer: { keyCode: keyToKeyCode("6") },
|
||||||
comparator: { keyCode: key("7") },
|
comparator: { keyCode: keyToKeyCode("7") },
|
||||||
transistor: { keyCode: key("8") },
|
transistor: { keyCode: keyToKeyCode("8") },
|
||||||
},
|
},
|
||||||
|
|
||||||
placement: {
|
placement: {
|
||||||
pipette: { keyCode: key("Q") },
|
pipette: { keyCode: keyToKeyCode("Q") },
|
||||||
rotateWhilePlacing: { keyCode: key("R") },
|
rotateWhilePlacing: { keyCode: keyToKeyCode("R") },
|
||||||
rotateInverseModifier: { keyCode: 16 }, // SHIFT
|
rotateInverseModifier: { keyCode: KEYCODES.Shift },
|
||||||
rotateToUp: { keyCode: KEYCODE_UP_ARROW },
|
rotateToUp: { keyCode: KEYCODES.ArrowUp },
|
||||||
rotateToDown: { keyCode: KEYCODE_DOWN_ARROW },
|
rotateToDown: { keyCode: KEYCODES.ArrowDown },
|
||||||
rotateToRight: { keyCode: KEYCODE_RIGHT_ARROW },
|
rotateToRight: { keyCode: KEYCODES.ArrowRight },
|
||||||
rotateToLeft: { keyCode: KEYCODE_LEFT_ARROW },
|
rotateToLeft: { keyCode: KEYCODES.ArrowLeft },
|
||||||
cycleBuildingVariants: { keyCode: key("T") },
|
cycleBuildingVariants: { keyCode: keyToKeyCode("T") },
|
||||||
cycleBuildings: { keyCode: 9 }, // TAB
|
cycleBuildings: { keyCode: KEYCODES.Tab },
|
||||||
switchDirectionLockSide: { keyCode: key("R") },
|
switchDirectionLockSide: { keyCode: keyToKeyCode("R") },
|
||||||
|
|
||||||
copyWireValue: { keyCode: key("Z") },
|
copyWireValue: { keyCode: keyToKeyCode("Z") },
|
||||||
},
|
},
|
||||||
|
|
||||||
massSelect: {
|
massSelect: {
|
||||||
massSelectStart: { keyCode: 17 }, // CTRL
|
massSelectStart: { keyCode: KEYCODES.Ctrl },
|
||||||
massSelectSelectMultiple: { keyCode: 16 }, // SHIFT
|
massSelectSelectMultiple: { keyCode: KEYCODES.Shift },
|
||||||
massSelectCopy: { keyCode: key("C") },
|
massSelectCopy: { keyCode: keyToKeyCode("C") },
|
||||||
massSelectCut: { keyCode: key("X") },
|
massSelectCut: { keyCode: keyToKeyCode("X") },
|
||||||
massSelectClear: { keyCode: key("B") },
|
massSelectClear: { keyCode: keyToKeyCode("B") },
|
||||||
confirmMassDelete: { keyCode: 46 }, // DEL
|
confirmMassDelete: { keyCode: KEYCODES.Delete },
|
||||||
pasteLastBlueprint: { keyCode: key("V") },
|
pasteLastBlueprint: { keyCode: keyToKeyCode("V") },
|
||||||
},
|
},
|
||||||
|
|
||||||
placementModifiers: {
|
placementModifiers: {
|
||||||
lockBeltDirection: { keyCode: 16 }, // SHIFT
|
lockBeltDirection: { keyCode: KEYCODES.Shift },
|
||||||
placementDisableAutoOrientation: { keyCode: 17 }, // CTRL
|
placementDisableAutoOrientation: { keyCode: KEYCODES.Ctrl },
|
||||||
placeMultiple: { keyCode: 16 }, // SHIFT
|
placeMultiple: { keyCode: KEYCODES.Shift },
|
||||||
placeInverse: { keyCode: 18 }, // ALT
|
placeInverse: { keyCode: KEYCODES.Alt },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -153,23 +187,23 @@ export function getStringForKeyCode(code) {
|
|||||||
return "MB5";
|
return "MB5";
|
||||||
case 8:
|
case 8:
|
||||||
return "⌫";
|
return "⌫";
|
||||||
case 9:
|
case KEYCODES.Tab:
|
||||||
return T.global.keys.tab;
|
return T.global.keys.tab;
|
||||||
case 13:
|
case KEYCODES.Enter:
|
||||||
return "⏎";
|
return "⏎";
|
||||||
case 16:
|
case KEYCODES.Shift:
|
||||||
return "⇪";
|
return "⇪";
|
||||||
case 17:
|
case KEYCODES.Ctrl:
|
||||||
return T.global.keys.control;
|
return T.global.keys.control;
|
||||||
case 18:
|
case KEYCODES.Alt:
|
||||||
return T.global.keys.alt;
|
return T.global.keys.alt;
|
||||||
case 19:
|
case 19:
|
||||||
return "PAUSE";
|
return "PAUSE";
|
||||||
case 20:
|
case 20:
|
||||||
return "CAPS";
|
return "CAPS";
|
||||||
case 27:
|
case KEYCODES.Escape:
|
||||||
return T.global.keys.escape;
|
return T.global.keys.escape;
|
||||||
case 32:
|
case KEYCODES.Space:
|
||||||
return T.global.keys.space;
|
return T.global.keys.space;
|
||||||
case 33:
|
case 33:
|
||||||
return "PGUP";
|
return "PGUP";
|
||||||
@ -179,13 +213,13 @@ export function getStringForKeyCode(code) {
|
|||||||
return "END";
|
return "END";
|
||||||
case 36:
|
case 36:
|
||||||
return "HOME";
|
return "HOME";
|
||||||
case KEYCODE_LEFT_ARROW:
|
case KEYCODES.ArrowLeft:
|
||||||
return "⬅";
|
return "⬅";
|
||||||
case KEYCODE_UP_ARROW:
|
case KEYCODES.ArrowUp:
|
||||||
return "⬆";
|
return "⬆";
|
||||||
case KEYCODE_RIGHT_ARROW:
|
case KEYCODES.ArrowRight:
|
||||||
return "➡";
|
return "➡";
|
||||||
case KEYCODE_DOWN_ARROW:
|
case KEYCODES.ArrowDown:
|
||||||
return "⬇";
|
return "⬇";
|
||||||
case 44:
|
case 44:
|
||||||
return "PRNT";
|
return "PRNT";
|
||||||
@ -225,29 +259,29 @@ export function getStringForKeyCode(code) {
|
|||||||
return ".";
|
return ".";
|
||||||
case 111:
|
case 111:
|
||||||
return "/";
|
return "/";
|
||||||
case 112:
|
case KEYCODES.F1:
|
||||||
return "F1";
|
return "F1";
|
||||||
case 113:
|
case KEYCODES.F2:
|
||||||
return "F2";
|
return "F2";
|
||||||
case 114:
|
case KEYCODES.F3:
|
||||||
return "F3";
|
return "F3";
|
||||||
case 115:
|
case KEYCODES.F4:
|
||||||
return "F4";
|
return "F4";
|
||||||
case 116:
|
case KEYCODES.F5:
|
||||||
return "F5";
|
return "F5";
|
||||||
case 117:
|
case KEYCODES.F6:
|
||||||
return "F6";
|
return "F6";
|
||||||
case 118:
|
case KEYCODES.F7:
|
||||||
return "F7";
|
return "F7";
|
||||||
case 119:
|
case KEYCODES.F8:
|
||||||
return "F8";
|
return "F8";
|
||||||
case 120:
|
case KEYCODES.F9:
|
||||||
return "F9";
|
return "F9";
|
||||||
case 121:
|
case KEYCODES.F10:
|
||||||
return "F10";
|
return "F10";
|
||||||
case 122:
|
case KEYCODES.F11:
|
||||||
return "F11";
|
return "F11";
|
||||||
case 123:
|
case KEYCODES.F12:
|
||||||
return "F12";
|
return "F12";
|
||||||
|
|
||||||
case 144:
|
case 144:
|
||||||
@ -296,8 +330,9 @@ export class Keybinding {
|
|||||||
* @param {number} param0.keyCode
|
* @param {number} param0.keyCode
|
||||||
* @param {boolean=} param0.builtin
|
* @param {boolean=} param0.builtin
|
||||||
* @param {boolean=} param0.repeated
|
* @param {boolean=} param0.repeated
|
||||||
|
* @param {{ shift?: boolean; alt?: boolean; ctrl?: boolean; }=} param0.modifiers
|
||||||
*/
|
*/
|
||||||
constructor(keyMapper, app, { keyCode, builtin = false, repeated = false }) {
|
constructor(keyMapper, app, { keyCode, builtin = false, repeated = false, modifiers = {} }) {
|
||||||
assert(keyCode && Number.isInteger(keyCode), "Invalid key code: " + keyCode);
|
assert(keyCode && Number.isInteger(keyCode), "Invalid key code: " + keyCode);
|
||||||
this.keyMapper = keyMapper;
|
this.keyMapper = keyMapper;
|
||||||
this.app = app;
|
this.app = app;
|
||||||
@ -305,6 +340,8 @@ export class Keybinding {
|
|||||||
this.builtin = builtin;
|
this.builtin = builtin;
|
||||||
this.repeated = repeated;
|
this.repeated = repeated;
|
||||||
|
|
||||||
|
this.modifiers = modifiers;
|
||||||
|
|
||||||
this.signal = new Signal();
|
this.signal = new Signal();
|
||||||
this.toggled = new Signal();
|
this.toggled = new Signal();
|
||||||
}
|
}
|
||||||
@ -395,7 +432,6 @@ export class KeyActionMapper {
|
|||||||
if (overrides[key]) {
|
if (overrides[key]) {
|
||||||
payload.keyCode = overrides[key];
|
payload.keyCode = overrides[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.keybindings[key] = new Keybinding(this, this.root.app, payload);
|
this.keybindings[key] = new Keybinding(this, this.root.app, payload);
|
||||||
|
|
||||||
if (G_IS_DEV) {
|
if (G_IS_DEV) {
|
||||||
@ -459,9 +495,10 @@ export class KeyActionMapper {
|
|||||||
* @param {number} param0.keyCode
|
* @param {number} param0.keyCode
|
||||||
* @param {boolean} param0.shift
|
* @param {boolean} param0.shift
|
||||||
* @param {boolean} param0.alt
|
* @param {boolean} param0.alt
|
||||||
|
* @param {boolean} param0.ctrl
|
||||||
* @param {boolean=} param0.initial
|
* @param {boolean=} param0.initial
|
||||||
*/
|
*/
|
||||||
handleKeydown({ keyCode, shift, alt, initial }) {
|
handleKeydown({ keyCode, shift, alt, ctrl, initial }) {
|
||||||
let stop = false;
|
let stop = false;
|
||||||
|
|
||||||
// Find mapping
|
// Find mapping
|
||||||
@ -469,6 +506,18 @@ export class KeyActionMapper {
|
|||||||
/** @type {Keybinding} */
|
/** @type {Keybinding} */
|
||||||
const binding = this.keybindings[key];
|
const binding = this.keybindings[key];
|
||||||
if (binding.keyCode === keyCode && (initial || binding.repeated)) {
|
if (binding.keyCode === keyCode && (initial || binding.repeated)) {
|
||||||
|
if (binding.modifiers.shift && !shift) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binding.modifiers.ctrl && !ctrl) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binding.modifiers.alt && !alt) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {Signal} */
|
/** @type {Signal} */
|
||||||
const signal = this.keybindings[key].signal;
|
const signal = this.keybindings[key].signal;
|
||||||
if (signal.dispatch() === STOP_PROPAGATION) {
|
if (signal.dispatch() === STOP_PROPAGATION) {
|
||||||
@ -505,4 +554,14 @@ export class KeyActionMapper {
|
|||||||
assert(this.keybindings[id], "Keybinding " + id + " not known!");
|
assert(this.keybindings[id], "Keybinding " + id + " not known!");
|
||||||
return this.keybindings[id];
|
return this.keybindings[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a given keybinding
|
||||||
|
* @param {string} id
|
||||||
|
* @returns {Keybinding}
|
||||||
|
*/
|
||||||
|
getBindingById(id) {
|
||||||
|
assert(this.keybindings[id], "Keybinding " + id + " not known!");
|
||||||
|
return this.keybindings[id];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -194,6 +194,20 @@ registerMod(shapez => {
|
|||||||
element.primaryBuildings.push(MetaDemoModBuilding);
|
element.primaryBuildings.push(MetaDemoModBuilding);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Register keybinding
|
||||||
|
this.modInterface.registerIngameKeybinding({
|
||||||
|
id: "demo_mod_binding",
|
||||||
|
keyCode: shapez.keyToKeyCode("F"),
|
||||||
|
translation: "mymod: Do something (always with SHIFT)",
|
||||||
|
modifiers: {
|
||||||
|
shift: true,
|
||||||
|
},
|
||||||
|
handler: root => {
|
||||||
|
this.dialogs.showInfo("Mod Message", "It worked!");
|
||||||
|
return shapez.STOP_PROPAGATION;
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -29,4 +29,8 @@ export class Mod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {}
|
init() {}
|
||||||
|
|
||||||
|
get dialogs() {
|
||||||
|
return this.modInterface.dialogs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import { MetaBuilding } from "../game/meta_building";
|
|||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
import { defaultBuildingVariant } from "../game/meta_building";
|
import { defaultBuildingVariant } from "../game/meta_building";
|
||||||
import { createLogger } from "../core/logging";
|
|
||||||
import { AtlasSprite, SpriteAtlasLink } from "../core/sprites";
|
import { AtlasSprite, SpriteAtlasLink } from "../core/sprites";
|
||||||
import {
|
import {
|
||||||
enumShortcodeToSubShape,
|
enumShortcodeToSubShape,
|
||||||
@ -22,8 +21,8 @@ import { gComponentRegistry, gMetaBuildingRegistry } from "../core/global_regist
|
|||||||
import { MODS_ADDITIONAL_SHAPE_MAP_WEIGHTS } from "../game/map_chunk";
|
import { MODS_ADDITIONAL_SHAPE_MAP_WEIGHTS } from "../game/map_chunk";
|
||||||
import { MODS_ADDITIONAL_SYSTEMS } from "../game/game_system_manager";
|
import { MODS_ADDITIONAL_SYSTEMS } from "../game/game_system_manager";
|
||||||
import { MOD_CHUNK_DRAW_HOOKS } from "../game/map_chunk_view";
|
import { MOD_CHUNK_DRAW_HOOKS } from "../game/map_chunk_view";
|
||||||
|
import { KEYMAPPINGS } from "../game/key_action_mapper";
|
||||||
const LOG = createLogger("mod-interface");
|
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
||||||
|
|
||||||
export class ModInterface {
|
export class ModInterface {
|
||||||
/**
|
/**
|
||||||
@ -32,9 +31,6 @@ export class ModInterface {
|
|||||||
*/
|
*/
|
||||||
constructor(modLoader) {
|
constructor(modLoader) {
|
||||||
this.modLoader = modLoader;
|
this.modLoader = modLoader;
|
||||||
|
|
||||||
/** @type {Map<string, AtlasSprite>} */
|
|
||||||
this.lazySprites = new Map();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerCss(cssString) {
|
registerCss(cssString) {
|
||||||
@ -249,6 +245,66 @@ export class ModInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Object} param0
|
||||||
|
* @param {string} param0.id
|
||||||
|
* @param {number} param0.keyCode
|
||||||
|
* @param {string} param0.translation
|
||||||
|
* @param {boolean=} param0.repeated
|
||||||
|
* @param {((GameRoot) => void)=} param0.handler
|
||||||
|
* @param {{shift?: boolean; alt?: boolean; ctrl?: boolean}=} param0.modifiers
|
||||||
|
* @param {boolean=} param0.builtin
|
||||||
|
*/
|
||||||
|
registerIngameKeybinding({
|
||||||
|
id,
|
||||||
|
keyCode,
|
||||||
|
translation,
|
||||||
|
modifiers = {},
|
||||||
|
repeated = false,
|
||||||
|
builtin = false,
|
||||||
|
handler = null,
|
||||||
|
}) {
|
||||||
|
if (!KEYMAPPINGS.mods) {
|
||||||
|
KEYMAPPINGS.mods = {};
|
||||||
|
}
|
||||||
|
const binding = (KEYMAPPINGS.mods[id] = {
|
||||||
|
keyCode,
|
||||||
|
id,
|
||||||
|
repeated,
|
||||||
|
modifiers,
|
||||||
|
builtin,
|
||||||
|
});
|
||||||
|
this.registerTranslations("en", {
|
||||||
|
keybindings: {
|
||||||
|
mappings: {
|
||||||
|
[id]: translation,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (handler) {
|
||||||
|
this.modLoader.signals.gameStarted.add(root => {
|
||||||
|
root.keyMapper.getBindingById(id).addToTop(handler.bind(null, root));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {HUDModalDialogs}
|
||||||
|
*/
|
||||||
|
get dialogs() {
|
||||||
|
const state = this.modLoader.app.stateMgr.currentState;
|
||||||
|
// @ts-ignore
|
||||||
|
if (state.dialogs) {
|
||||||
|
// @ts-ignore
|
||||||
|
return state.dialogs;
|
||||||
|
}
|
||||||
|
throw new Error("Tried to access dialogs but current state doesn't support it");
|
||||||
|
}
|
||||||
|
|
||||||
setBuildingToolbarIcon(buildingId, iconBase64) {
|
setBuildingToolbarIcon(buildingId, iconBase64) {
|
||||||
this.registerCss(`
|
this.registerCss(`
|
||||||
[data-icon="building_icons/${buildingId}.png"] .icon {
|
[data-icon="building_icons/${buildingId}.png"] .icon {
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { Signal } from "../core/signal";
|
|
||||||
/* typehints:start */
|
/* typehints:start */
|
||||||
import { BaseHUDPart } from "../game/hud/base_hud_part";
|
import { BaseHUDPart } from "../game/hud/base_hud_part";
|
||||||
|
import { GameRoot } from "../game/root";
|
||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
|
import { Signal } from "../core/signal";
|
||||||
|
|
||||||
// Single file to avoid circular deps
|
// Single file to avoid circular deps
|
||||||
|
|
||||||
export const MOD_SIGNALS = {
|
export const MOD_SIGNALS = {
|
||||||
@ -15,4 +17,6 @@ export const MOD_SIGNALS = {
|
|||||||
|
|
||||||
hudElementInitialized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
|
hudElementInitialized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
|
||||||
hudElementFinalized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
|
hudElementFinalized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
|
||||||
|
|
||||||
|
gameStarted: /** @type {TypedSignal<[GameRoot]>} */ (new Signal()),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
/* typehints:start */
|
||||||
|
import { Application } from "../application";
|
||||||
|
/* typehints:end */
|
||||||
|
|
||||||
import { globalConfig } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { getIPCRenderer } from "../core/utils";
|
import { getIPCRenderer } from "../core/utils";
|
||||||
@ -11,6 +15,11 @@ export class ModLoader {
|
|||||||
constructor() {
|
constructor() {
|
||||||
LOG.log("modloader created");
|
LOG.log("modloader created");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Application}
|
||||||
|
*/
|
||||||
|
this.app = undefined;
|
||||||
|
|
||||||
/** @type {Mod[]} */
|
/** @type {Mod[]} */
|
||||||
this.mods = [];
|
this.mods = [];
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { Savegame } from "../savegame/savegame";
|
|||||||
import { GameCore } from "../game/core";
|
import { GameCore } from "../game/core";
|
||||||
import { MUSIC } from "../platform/sound";
|
import { MUSIC } from "../platform/sound";
|
||||||
import { enumGameModeIds } from "../game/game_mode";
|
import { enumGameModeIds } from "../game/game_mode";
|
||||||
|
import { MOD_SIGNALS } from "../mods/mod_signals";
|
||||||
|
|
||||||
const logger = createLogger("state/ingame");
|
const logger = createLogger("state/ingame");
|
||||||
|
|
||||||
@ -82,6 +83,10 @@ export class InGameState extends GameState {
|
|||||||
this.currentSavePromise = null;
|
this.currentSavePromise = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get dialogs() {
|
||||||
|
return this.core.root.hud.parts.dialogs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switches the game into another sub-state
|
* Switches the game into another sub-state
|
||||||
* @param {string} stage
|
* @param {string} stage
|
||||||
@ -318,6 +323,8 @@ export class InGameState extends GameState {
|
|||||||
|
|
||||||
// Initial resize, might have changed during loading (this is possible)
|
// Initial resize, might have changed during loading (this is possible)
|
||||||
this.core.resize(this.app.screenWidth, this.app.screenHeight);
|
this.core.resize(this.app.screenWidth, this.app.screenHeight);
|
||||||
|
|
||||||
|
MOD_SIGNALS.gameStarted.dispatch(this.core.root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export class KeybindingsState extends TextualGameState {
|
|||||||
<div class="topEntries">
|
<div class="topEntries">
|
||||||
<span class="hint">${T.keybindings.hint}</span>
|
<span class="hint">${T.keybindings.hint}</span>
|
||||||
<button class="styledButton resetBindings">${T.keybindings.resetKeybindings}</button>
|
<button class="styledButton resetBindings">${T.keybindings.resetKeybindings}</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="keybindings">
|
<div class="keybindings">
|
||||||
@ -34,6 +34,10 @@ export class KeybindingsState extends TextualGameState {
|
|||||||
this.trackClicks(this.htmlElement.querySelector(".resetBindings"), this.resetBindings);
|
this.trackClicks(this.htmlElement.querySelector(".resetBindings"), this.resetBindings);
|
||||||
|
|
||||||
for (const category in KEYMAPPINGS) {
|
for (const category in KEYMAPPINGS) {
|
||||||
|
if (Object.keys(KEYMAPPINGS[category]).length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const categoryDiv = document.createElement("div");
|
const categoryDiv = document.createElement("div");
|
||||||
categoryDiv.classList.add("category");
|
categoryDiv.classList.add("category");
|
||||||
keybindingsElem.appendChild(categoryDiv);
|
keybindingsElem.appendChild(categoryDiv);
|
||||||
@ -138,7 +142,19 @@ export class KeybindingsState extends TextualGameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mappingDiv = container.querySelector(".mapping");
|
const mappingDiv = container.querySelector(".mapping");
|
||||||
mappingDiv.innerHTML = getStringForKeyCode(keyCode);
|
let modifiers = "";
|
||||||
|
|
||||||
|
if (mapped.modifiers && mapped.modifiers.shift) {
|
||||||
|
modifiers += "⇪ ";
|
||||||
|
}
|
||||||
|
if (mapped.modifiers && mapped.modifiers.alt) {
|
||||||
|
modifiers += T.global.keys.alt + " ";
|
||||||
|
}
|
||||||
|
if (mapped.modifiers && mapped.modifiers.ctrl) {
|
||||||
|
modifiers += T.global.keys.control + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
mappingDiv.innerHTML = modifiers + getStringForKeyCode(keyCode);
|
||||||
mappingDiv.classList.toggle("changed", !!overrides[keybindingId]);
|
mappingDiv.classList.toggle("changed", !!overrides[keybindingId]);
|
||||||
|
|
||||||
const resetBtn = container.querySelector("button.resetKeybinding");
|
const resetBtn = container.querySelector("button.resetKeybinding");
|
||||||
|
|||||||
@ -1328,6 +1328,7 @@ keybindings:
|
|||||||
massSelect: Mass Select
|
massSelect: Mass Select
|
||||||
buildings: Building Shortcuts
|
buildings: Building Shortcuts
|
||||||
placementModifiers: Placement Modifiers
|
placementModifiers: Placement Modifiers
|
||||||
|
mods: Provided by Mods
|
||||||
|
|
||||||
mappings:
|
mappings:
|
||||||
confirm: Confirm
|
confirm: Confirm
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user