mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Add customizable keybindings & watermark
This commit is contained in:
parent
2968fe3788
commit
3714a59fca
BIN
res/ui/icons/edit_key.png
Normal file
BIN
res/ui/icons/edit_key.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 634 B |
BIN
res/ui/icons/main_menu_settings.png
Normal file
BIN
res/ui/icons/main_menu_settings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
res/ui/icons/reset_key.png
Normal file
BIN
res/ui/icons/reset_key.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
@ -523,7 +523,7 @@ canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.checkbox {
|
.checkbox {
|
||||||
$bgColor: darken($mainBgColor, 0);
|
$bgColor: darken($mainBgColor, 3);
|
||||||
background-color: $bgColor;
|
background-color: $bgColor;
|
||||||
@include S(width, 35px);
|
@include S(width, 35px);
|
||||||
@include S(height, 17px);
|
@include S(height, 17px);
|
||||||
|
@ -23,7 +23,9 @@
|
|||||||
@import "states/preload";
|
@import "states/preload";
|
||||||
@import "states/main_menu";
|
@import "states/main_menu";
|
||||||
@import "states/ingame";
|
@import "states/ingame";
|
||||||
|
@import "states/keybindings";
|
||||||
@import "states/settings";
|
@import "states/settings";
|
||||||
|
@import "states/about";
|
||||||
|
|
||||||
@import "ingame_hud/buildings_toolbar";
|
@import "ingame_hud/buildings_toolbar";
|
||||||
@import "ingame_hud/building_placer";
|
@import "ingame_hud/building_placer";
|
||||||
|
5
src/css/states/about.scss
Normal file
5
src/css/states/about.scss
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#state_AboutState {
|
||||||
|
.content {
|
||||||
|
@include PlainText;
|
||||||
|
}
|
||||||
|
}
|
54
src/css/states/keybindings.scss
Normal file
54
src/css/states/keybindings.scss
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#state_KeybindingsState {
|
||||||
|
.content {
|
||||||
|
.topEntries {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
@include S(grid-gap, 5px);
|
||||||
|
@include S(margin-bottom, 10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
display: block;
|
||||||
|
background: #eee;
|
||||||
|
@include S(padding, 4px);
|
||||||
|
@include PlainText;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category {
|
||||||
|
.entry {
|
||||||
|
display: grid;
|
||||||
|
@include S(margin-top, 2px);
|
||||||
|
@include S(padding-top, 2px);
|
||||||
|
@include S(grid-gap, 4px);
|
||||||
|
grid-template-columns: 1fr #{D(100px)} auto auto;
|
||||||
|
border-bottom: #{D(1px)} dotted #eee;
|
||||||
|
color: #888c8f;
|
||||||
|
.mapping {
|
||||||
|
color: $colorBlueBright;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include S(height, 15px);
|
||||||
|
@include S(width, 15px);
|
||||||
|
@include IncreasedClickArea(0px);
|
||||||
|
background: transparent center center / 40% no-repeat;
|
||||||
|
opacity: 0.9;
|
||||||
|
&.editKeybinding {
|
||||||
|
background-image: uiResource("icons/edit_key.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.resetKeybinding {
|
||||||
|
background-image: uiResource("icons/reset_key.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.1 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,13 +9,13 @@
|
|||||||
|
|
||||||
.settingsButton {
|
.settingsButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@include S(bottom, 30px);
|
@include S(top, 30px);
|
||||||
@include S(right, 30px);
|
@include S(right, 30px);
|
||||||
@include S(width, 35px);
|
@include S(width, 35px);
|
||||||
@include S(height, 35px);
|
@include S(height, 35px);
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: uiResource("icons/settings.png") center center / contain no-repeat;
|
background: uiResource("icons/main_menu_settings.png") center center / contain no-repeat;
|
||||||
transition: opacity 0.12s ease-in-out;
|
transition: opacity 0.12s ease-in-out;
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
|
@ -1,13 +1,5 @@
|
|||||||
#state_SettingsState {
|
#state_SettingsState {
|
||||||
.content {
|
.content {
|
||||||
.categoryLabel {
|
|
||||||
display: block;
|
|
||||||
text-transform: uppercase;
|
|
||||||
@include S(margin-top, 15px);
|
|
||||||
@include S(margin-bottom, 15px);
|
|
||||||
@include Heading;
|
|
||||||
}
|
|
||||||
|
|
||||||
.versionbar {
|
.versionbar {
|
||||||
@include S(margin-top, 20px);
|
@include S(margin-top, 20px);
|
||||||
@include SuperSmallText;
|
@include SuperSmallText;
|
||||||
@ -21,9 +13,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.about {
|
||||||
|
background-color: $colorGreenBright;
|
||||||
|
}
|
||||||
|
|
||||||
.setting {
|
.setting {
|
||||||
@include S(padding, 10px);
|
@include S(padding, 10px);
|
||||||
background: #eee;
|
background: #eeeff5;
|
||||||
@include S(border-radius, $globalBorderRadius);
|
@include S(border-radius, $globalBorderRadius);
|
||||||
@include S(margin-bottom, 5px);
|
@include S(margin-bottom, 5px);
|
||||||
|
|
||||||
|
@ -38,13 +38,27 @@
|
|||||||
@include S(margin-bottom, 20px);
|
@include S(margin-bottom, 20px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
> .container {
|
||||||
background: #fff;
|
> .content {
|
||||||
@include S(border-radius, $globalBorderRadius);
|
background: #fff;
|
||||||
@include S(padding, 10px);
|
@include S(border-radius, $globalBorderRadius);
|
||||||
max-height: calc(80vh - #{D(60px)});
|
@include S(padding, 10px);
|
||||||
overflow-y: auto;
|
height: calc(80vh - #{D(60px)});
|
||||||
box-sizing: border-box;
|
overflow-y: auto;
|
||||||
pointer-events: all;
|
box-sizing: border-box;
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $colorBlueBright;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categoryLabel {
|
||||||
|
display: block;
|
||||||
|
text-transform: uppercase;
|
||||||
|
@include S(margin-top, 15px);
|
||||||
|
@include S(margin-bottom, 15px);
|
||||||
|
@include Heading;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,8 @@ import { queryParamOptions } from "./core/query_parameters";
|
|||||||
import { NoGameAnalytics } from "./platform/browser/no_game_analytics";
|
import { NoGameAnalytics } from "./platform/browser/no_game_analytics";
|
||||||
import { StorageImplBrowserIndexedDB } from "./platform/browser/storage_indexed_db";
|
import { StorageImplBrowserIndexedDB } from "./platform/browser/storage_indexed_db";
|
||||||
import { SettingsState } from "./states/settings";
|
import { SettingsState } from "./states/settings";
|
||||||
|
import { KeybindingsState } from "./states/keybindings";
|
||||||
|
import { AboutState } from "./states/about";
|
||||||
|
|
||||||
const logger = createLogger("application");
|
const logger = createLogger("application");
|
||||||
|
|
||||||
@ -143,7 +145,14 @@ export class Application {
|
|||||||
*/
|
*/
|
||||||
registerStates() {
|
registerStates() {
|
||||||
/** @type {Array<typeof GameState>} */
|
/** @type {Array<typeof GameState>} */
|
||||||
const states = [PreloadState, MainMenuState, InGameState, SettingsState];
|
const states = [
|
||||||
|
PreloadState,
|
||||||
|
MainMenuState,
|
||||||
|
InGameState,
|
||||||
|
SettingsState,
|
||||||
|
KeybindingsState,
|
||||||
|
AboutState,
|
||||||
|
];
|
||||||
|
|
||||||
for (let i = 0; i < states.length; ++i) {
|
for (let i = 0; i < states.length; ++i) {
|
||||||
this.stateMgr.register(states[i]);
|
this.stateMgr.register(states[i]);
|
||||||
|
@ -71,7 +71,7 @@ export const globalConfig = {
|
|||||||
|
|
||||||
debug: {
|
debug: {
|
||||||
/* dev:start */
|
/* dev:start */
|
||||||
// fastGameEnter: true,
|
fastGameEnter: true,
|
||||||
noArtificialDelays: true,
|
noArtificialDelays: true,
|
||||||
// disableSavegameWrite: true,
|
// disableSavegameWrite: true,
|
||||||
// showEntityBounds: true,
|
// showEntityBounds: true,
|
||||||
|
@ -17,6 +17,7 @@ import { clamp } from "../core/utils";
|
|||||||
import { mixVector, Vector } from "../core/vector";
|
import { mixVector, Vector } from "../core/vector";
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
|
import { KEYMAPPINGS } from "./key_action_mapper";
|
||||||
|
|
||||||
const logger = createLogger("camera");
|
const logger = createLogger("camera");
|
||||||
|
|
||||||
@ -330,12 +331,12 @@ export class Camera extends BasicSerializableObject {
|
|||||||
*/
|
*/
|
||||||
bindKeys() {
|
bindKeys() {
|
||||||
const mapper = this.root.gameState.keyActionMapper;
|
const mapper = this.root.gameState.keyActionMapper;
|
||||||
mapper.getBinding("map_move_up").add(() => (this.keyboardForce.y = -1));
|
mapper.getBinding(KEYMAPPINGS.ingame.mapMoveUp).add(() => (this.keyboardForce.y = -1));
|
||||||
mapper.getBinding("map_move_down").add(() => (this.keyboardForce.y = 1));
|
mapper.getBinding(KEYMAPPINGS.ingame.mapMoveDown).add(() => (this.keyboardForce.y = 1));
|
||||||
mapper.getBinding("map_move_right").add(() => (this.keyboardForce.x = 1));
|
mapper.getBinding(KEYMAPPINGS.ingame.mapMoveRight).add(() => (this.keyboardForce.x = 1));
|
||||||
mapper.getBinding("map_move_left").add(() => (this.keyboardForce.x = -1));
|
mapper.getBinding(KEYMAPPINGS.ingame.mapMoveLeft).add(() => (this.keyboardForce.x = -1));
|
||||||
|
|
||||||
mapper.getBinding("center_map").add(() => this.centerOnMap());
|
mapper.getBinding(KEYMAPPINGS.ingame.centerMap).add(() => this.centerOnMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
centerOnMap() {
|
centerOnMap() {
|
||||||
@ -867,19 +868,19 @@ export class Camera extends BasicSerializableObject {
|
|||||||
let forceY = 0;
|
let forceY = 0;
|
||||||
|
|
||||||
const actionMapper = this.root.gameState.keyActionMapper;
|
const actionMapper = this.root.gameState.keyActionMapper;
|
||||||
if (actionMapper.getBinding("map_move_up").currentlyDown) {
|
if (actionMapper.getBinding(KEYMAPPINGS.ingame.mapMoveUp).currentlyDown) {
|
||||||
forceY -= 1;
|
forceY -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actionMapper.getBinding("map_move_down").currentlyDown) {
|
if (actionMapper.getBinding(KEYMAPPINGS.ingame.mapMoveDown).currentlyDown) {
|
||||||
forceY += 1;
|
forceY += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actionMapper.getBinding("map_move_left").currentlyDown) {
|
if (actionMapper.getBinding(KEYMAPPINGS.ingame.mapMoveLeft).currentlyDown) {
|
||||||
forceX -= 1;
|
forceX -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actionMapper.getBinding("map_move_right").currentlyDown) {
|
if (actionMapper.getBinding(KEYMAPPINGS.ingame.mapMoveRight).currentlyDown) {
|
||||||
forceX += 1;
|
forceX += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,10 +154,10 @@ export class BaseHUDPart {
|
|||||||
*/
|
*/
|
||||||
forwardMapMovementKeybindings(sourceMapper) {
|
forwardMapMovementKeybindings(sourceMapper) {
|
||||||
sourceMapper.forward(this.root.gameState.keyActionMapper, [
|
sourceMapper.forward(this.root.gameState.keyActionMapper, [
|
||||||
"map_move_up",
|
"mapMoveUp",
|
||||||
"map_move_right",
|
"mapMoveRight",
|
||||||
"map_move_down",
|
"mapMoveDown",
|
||||||
"map_move_left",
|
"mapMoveLeft",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ import { HUDNotifications, enumNotificationType } from "./parts/notifications";
|
|||||||
import { HUDSettingsMenu } from "./parts/settings_menu";
|
import { HUDSettingsMenu } from "./parts/settings_menu";
|
||||||
import { HUDDebugInfo } from "./parts/debug_info";
|
import { HUDDebugInfo } from "./parts/debug_info";
|
||||||
import { HUDEntityDebugger } from "./parts/entity_debugger";
|
import { HUDEntityDebugger } from "./parts/entity_debugger";
|
||||||
|
import { KEYMAPPINGS } from "../key_action_mapper";
|
||||||
|
import { HUDWatermark } from "./parts/watermark";
|
||||||
|
|
||||||
export class GameHUD {
|
export class GameHUD {
|
||||||
/**
|
/**
|
||||||
@ -76,6 +78,10 @@ export class GameHUD {
|
|||||||
this.parts.entityDebugger = new HUDEntityDebugger(this.root);
|
this.parts.entityDebugger = new HUDEntityDebugger(this.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!G_IS_STANDALONE && G_IS_RELEASE) {
|
||||||
|
this.parts.watermark = new HUDWatermark(this.root);
|
||||||
|
}
|
||||||
|
|
||||||
const frag = document.createDocumentFragment();
|
const frag = document.createDocumentFragment();
|
||||||
for (const key in this.parts) {
|
for (const key in this.parts) {
|
||||||
this.parts[key].createElements(frag);
|
this.parts[key].createElements(frag);
|
||||||
@ -88,7 +94,7 @@ export class GameHUD {
|
|||||||
}
|
}
|
||||||
this.internalInitSignalConnections();
|
this.internalInitSignalConnections();
|
||||||
|
|
||||||
this.root.gameState.keyActionMapper.getBinding("toggle_hud").add(this.toggleUi, this);
|
this.root.gameState.keyActionMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,7 +192,7 @@ export class GameHUD {
|
|||||||
* @param {DrawParameters} parameters
|
* @param {DrawParameters} parameters
|
||||||
*/
|
*/
|
||||||
drawOverlays(parameters) {
|
drawOverlays(parameters) {
|
||||||
const partsOrder = [];
|
const partsOrder = ["watermark"];
|
||||||
|
|
||||||
for (let i = 0; i < partsOrder.length; ++i) {
|
for (let i = 0; i < partsOrder.length; ++i) {
|
||||||
if (this.parts[partsOrder[i]]) {
|
if (this.parts[partsOrder[i]]) {
|
||||||
|
@ -19,6 +19,7 @@ import { defaultBuildingVariant, MetaBuilding } from "../../meta_building";
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
|
|
||||||
export class HUDBuildingPlacer extends BaseHUDPart {
|
export class HUDBuildingPlacer extends BaseHUDPart {
|
||||||
initialize() {
|
initialize() {
|
||||||
@ -30,11 +31,13 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
|||||||
this.fakeEntity = null;
|
this.fakeEntity = null;
|
||||||
|
|
||||||
const keyActionMapper = this.root.gameState.keyActionMapper;
|
const keyActionMapper = this.root.gameState.keyActionMapper;
|
||||||
keyActionMapper.getBinding("building_abort_placement").add(this.abortPlacement, this);
|
keyActionMapper
|
||||||
keyActionMapper.getBinding("back").add(this.abortPlacement, this);
|
.getBinding(KEYMAPPINGS.placement.abortBuildingPlacement)
|
||||||
|
.add(this.abortPlacement, this);
|
||||||
|
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
|
||||||
|
|
||||||
keyActionMapper.getBinding("rotate_while_placing").add(this.tryRotate, this);
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.tryRotate, this);
|
||||||
keyActionMapper.getBinding("cycle_variants").add(this.cycleVariants, this);
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildingVariants).add(this.cycleVariants, this);
|
||||||
|
|
||||||
this.domAttach = new DynamicDomAttach(this.root, this.element, {});
|
this.domAttach = new DynamicDomAttach(this.root, this.element, {});
|
||||||
|
|
||||||
@ -281,7 +284,9 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
|||||||
this.buildingInfoElements.label.innerHTML = T.buildings[metaBuilding.id].name;
|
this.buildingInfoElements.label.innerHTML = T.buildings[metaBuilding.id].name;
|
||||||
this.buildingInfoElements.descText.innerHTML = T.buildings[metaBuilding.id].description;
|
this.buildingInfoElements.descText.innerHTML = T.buildings[metaBuilding.id].description;
|
||||||
|
|
||||||
const binding = this.root.gameState.keyActionMapper.getBinding("building_" + metaBuilding.getId());
|
const binding = this.root.gameState.keyActionMapper.getBinding(
|
||||||
|
KEYMAPPINGS.buildings[metaBuilding.getId()]
|
||||||
|
);
|
||||||
this.buildingInfoElements.hotkey.innerHTML = T.ingame.buildingPlacement.hotkeyLabel.replace(
|
this.buildingInfoElements.hotkey.innerHTML = T.ingame.buildingPlacement.hotkeyLabel.replace(
|
||||||
"<key>",
|
"<key>",
|
||||||
"<code class='keybinding'>" + binding.getKeyCodeString() + "</code>"
|
"<code class='keybinding'>" + binding.getKeyCodeString() + "</code>"
|
||||||
@ -322,7 +327,9 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
|||||||
T.ingame.buildingPlacement.cycleBuildingVariants.replace(
|
T.ingame.buildingPlacement.cycleBuildingVariants.replace(
|
||||||
"<key>",
|
"<key>",
|
||||||
"<code class='keybinding'>" +
|
"<code class='keybinding'>" +
|
||||||
this.root.gameState.keyActionMapper.getBinding("cycle_variants").getKeyCodeString() +
|
this.root.gameState.keyActionMapper
|
||||||
|
.getBinding(KEYMAPPINGS.placement.cycleBuildingVariants)
|
||||||
|
.getKeyCodeString() +
|
||||||
"</code>"
|
"</code>"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -452,7 +459,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
|||||||
) {
|
) {
|
||||||
// Succesfully placed
|
// Succesfully placed
|
||||||
|
|
||||||
if (metaBuilding.getFlipOrientationAfterPlacement()) {
|
if (metaBuilding.getFlipOrientationAfterPlacement() && !this.root.app.inputMgr.ctrlIsDown) {
|
||||||
this.currentBaseRotation = (180 + this.currentBaseRotation) % 360;
|
this.currentBaseRotation = (180 + this.currentBaseRotation) % 360;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import { MetaTrashBuilding } from "../../buildings/trash";
|
|||||||
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
|
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
|
||||||
import { MetaBuilding } from "../../meta_building";
|
import { MetaBuilding } from "../../meta_building";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
|
|
||||||
const toolbarBuildings = [
|
const toolbarBuildings = [
|
||||||
MetaBeltBaseBuilding,
|
MetaBeltBaseBuilding,
|
||||||
@ -65,7 +66,7 @@ export class HUDBuildingsToolbar extends BaseHUDPart {
|
|||||||
|
|
||||||
for (let i = 0; i < toolbarBuildings.length; ++i) {
|
for (let i = 0; i < toolbarBuildings.length; ++i) {
|
||||||
const metaBuilding = gMetaBuildingRegistry.findByClass(toolbarBuildings[i]);
|
const metaBuilding = gMetaBuildingRegistry.findByClass(toolbarBuildings[i]);
|
||||||
const binding = actionMapper.getBinding("building_" + metaBuilding.getId());
|
const binding = actionMapper.getBinding(KEYMAPPINGS.buildings[metaBuilding.getId()]);
|
||||||
|
|
||||||
const itemContainer = makeDiv(items, null, ["building"]);
|
const itemContainer = makeDiv(items, null, ["building"]);
|
||||||
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
|
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
|
||||||
@ -91,7 +92,7 @@ export class HUDBuildingsToolbar extends BaseHUDPart {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.lastSelectedIndex = 0;
|
this.lastSelectedIndex = 0;
|
||||||
actionMapper.getBinding("cycle_buildings").add(this.cycleBuildings, this);
|
actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
|
@ -3,6 +3,7 @@ import { makeDiv, randomInt } from "../../../core/utils";
|
|||||||
import { SOUNDS } from "../../../platform/sound";
|
import { SOUNDS } from "../../../platform/sound";
|
||||||
import { enumNotificationType } from "./notifications";
|
import { enumNotificationType } from "./notifications";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
|
|
||||||
export class HUDGameMenu extends BaseHUDPart {
|
export class HUDGameMenu extends BaseHUDPart {
|
||||||
initialize() {}
|
initialize() {}
|
||||||
@ -14,7 +15,7 @@ export class HUDGameMenu extends BaseHUDPart {
|
|||||||
id: "shop",
|
id: "shop",
|
||||||
label: "Upgrades",
|
label: "Upgrades",
|
||||||
handler: () => this.root.hud.parts.shop.show(),
|
handler: () => this.root.hud.parts.shop.show(),
|
||||||
keybinding: "menu_open_shop",
|
keybinding: KEYMAPPINGS.ingame.menuOpenShop,
|
||||||
badge: () => this.root.hubGoals.getAvailableUpgradeCount(),
|
badge: () => this.root.hubGoals.getAvailableUpgradeCount(),
|
||||||
notification: /** @type {[string, enumNotificationType]} */ ([
|
notification: /** @type {[string, enumNotificationType]} */ ([
|
||||||
T.ingame.notifications.newUpgrade,
|
T.ingame.notifications.newUpgrade,
|
||||||
@ -25,7 +26,7 @@ export class HUDGameMenu extends BaseHUDPart {
|
|||||||
id: "stats",
|
id: "stats",
|
||||||
label: "Stats",
|
label: "Stats",
|
||||||
handler: () => this.root.hud.parts.statistics.show(),
|
handler: () => this.root.hud.parts.statistics.show(),
|
||||||
keybinding: "menu_open_stats",
|
keybinding: KEYMAPPINGS.ingame.menuOpenStats,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { makeDiv } from "../../../core/utils";
|
import { makeDiv } from "../../../core/utils";
|
||||||
import { getStringForKeyCode } from "../../key_action_mapper";
|
import { getStringForKeyCode, KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { TrackedState } from "../../../core/tracked_state";
|
import { TrackedState } from "../../../core/tracked_state";
|
||||||
import { queryParamOptions } from "../../../core/query_parameters";
|
import { queryParamOptions } from "../../../core/query_parameters";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
@ -32,16 +32,16 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
|
|||||||
[],
|
[],
|
||||||
`
|
`
|
||||||
<div class="binding">
|
<div class="binding">
|
||||||
<code class="keybinding">${getKeycode("center_map")}</code>
|
<code class="keybinding">${getKeycode(KEYMAPPINGS.ingame.centerMap)}</code>
|
||||||
<label>${T.ingame.keybindingsOverlay.centerMap}</label>
|
<label>${T.ingame.keybindingsOverlay.centerMap}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="binding">
|
<div class="binding">
|
||||||
<code class="keybinding leftMouse"></code><i></i>
|
<code class="keybinding leftMouse"></code><i></i>
|
||||||
<code class="keybinding">${getKeycode("map_move_up")}</code>
|
<code class="keybinding">${getKeycode(KEYMAPPINGS.ingame.mapMoveUp)}</code>
|
||||||
<code class="keybinding">${getKeycode("map_move_left")}</code>
|
<code class="keybinding">${getKeycode(KEYMAPPINGS.ingame.mapMoveLeft)}</code>
|
||||||
<code class="keybinding">${getKeycode("map_move_down")}</code>
|
<code class="keybinding">${getKeycode(KEYMAPPINGS.ingame.mapMoveDown)}</code>
|
||||||
<code class="keybinding">${getKeycode("map_move_right")}</code>
|
<code class="keybinding">${getKeycode(KEYMAPPINGS.ingame.mapMoveRight)}</code>
|
||||||
<label>${T.ingame.keybindingsOverlay.moveMap}</label>
|
<label>${T.ingame.keybindingsOverlay.moveMap}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -55,12 +55,12 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
|
|||||||
|
|
||||||
<div class="binding placementOnly">
|
<div class="binding placementOnly">
|
||||||
<code class="keybinding rightMouse"></code><i></i>
|
<code class="keybinding rightMouse"></code><i></i>
|
||||||
<code class="keybinding">${getKeycode("building_abort_placement")}</code>
|
<code class="keybinding">${getKeycode(KEYMAPPINGS.placement.abortBuildingPlacement)}</code>
|
||||||
<label>${T.ingame.keybindingsOverlay.stopPlacement}</label>
|
<label>${T.ingame.keybindingsOverlay.stopPlacement}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="binding placementOnly">
|
<div class="binding placementOnly">
|
||||||
<code class="keybinding">${getKeycode("rotate_while_placing")}</code>
|
<code class="keybinding">${getKeycode(KEYMAPPINGS.placement.rotateWhilePlacing)}</code>
|
||||||
<label>${T.ingame.keybindingsOverlay.rotateBuilding}</label>
|
<label>${T.ingame.keybindingsOverlay.rotateBuilding}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -10,15 +10,18 @@ import { DynamicDomAttach } from "../dynamic_dom_attach";
|
|||||||
import { createLogger } from "../../../core/logging";
|
import { createLogger } from "../../../core/logging";
|
||||||
import { enumMouseButton } from "../../camera";
|
import { enumMouseButton } from "../../camera";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
|
|
||||||
const logger = createLogger("hud/mass_selector");
|
const logger = createLogger("hud/mass_selector");
|
||||||
|
|
||||||
export class HUDMassSelector extends BaseHUDPart {
|
export class HUDMassSelector extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
const removalKeybinding = this.root.gameState.keyActionMapper
|
const removalKeybinding = this.root.gameState.keyActionMapper
|
||||||
.getBinding("confirm_mass_delete")
|
.getBinding(KEYMAPPINGS.massSelect.confirmMassDelete)
|
||||||
|
.getKeyCodeString();
|
||||||
|
const abortKeybinding = this.root.gameState.keyActionMapper
|
||||||
|
.getBinding(KEYMAPPINGS.general.back)
|
||||||
.getKeyCodeString();
|
.getKeyCodeString();
|
||||||
const abortKeybinding = this.root.gameState.keyActionMapper.getBinding("back").getKeyCodeString();
|
|
||||||
|
|
||||||
this.element = makeDiv(
|
this.element = makeDiv(
|
||||||
parent,
|
parent,
|
||||||
@ -43,8 +46,10 @@ export class HUDMassSelector extends BaseHUDPart {
|
|||||||
this.root.camera.movePreHandler.add(this.onMouseMove, this);
|
this.root.camera.movePreHandler.add(this.onMouseMove, this);
|
||||||
this.root.camera.upPostHandler.add(this.onMouseUp, this);
|
this.root.camera.upPostHandler.add(this.onMouseUp, this);
|
||||||
|
|
||||||
this.root.gameState.keyActionMapper.getBinding("back").add(this.onBack, this);
|
this.root.gameState.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.onBack, this);
|
||||||
this.root.gameState.keyActionMapper.getBinding("confirm_mass_delete").add(this.confirmDelete, this);
|
this.root.gameState.keyActionMapper
|
||||||
|
.getBinding(KEYMAPPINGS.massSelect.confirmMassDelete)
|
||||||
|
.add(this.confirmDelete, this);
|
||||||
|
|
||||||
this.domAttach = new DynamicDomAttach(this.root, this.element);
|
this.domAttach = new DynamicDomAttach(this.root, this.element);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { BaseHUDPart } from "../base_hud_part";
|
|||||||
import { makeDiv, formatSeconds, formatBigNumberFull } from "../../../core/utils";
|
import { makeDiv, formatSeconds, formatBigNumberFull } from "../../../core/utils";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
import { InputReceiver } from "../../../core/input_receiver";
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
import { KeyActionMapper } from "../../key_action_mapper";
|
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||||
import { ItemProcessorComponent } from "../../components/item_processor";
|
import { ItemProcessorComponent } from "../../components/item_processor";
|
||||||
@ -72,7 +72,7 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
this.root.gameState.keyActionMapper.getBinding("back").add(this.show, this);
|
this.root.gameState.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.show, this);
|
||||||
|
|
||||||
this.domAttach = new DynamicDomAttach(this.root, this.background, {
|
this.domAttach = new DynamicDomAttach(this.root, this.background, {
|
||||||
attachClass: "visible",
|
attachClass: "visible",
|
||||||
@ -80,8 +80,7 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
|||||||
|
|
||||||
this.inputReciever = new InputReceiver("settingsmenu");
|
this.inputReciever = new InputReceiver("settingsmenu");
|
||||||
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
|
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
|
||||||
|
this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this);
|
||||||
this.keyActionMapper.getBinding("back").add(this.close, this);
|
|
||||||
|
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { ClickDetector } from "../../../core/click_detector";
|
|||||||
import { InputReceiver } from "../../../core/input_receiver";
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
import { formatBigNumber, makeDiv } from "../../../core/utils";
|
import { formatBigNumber, makeDiv } from "../../../core/utils";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
import { KeyActionMapper } from "../../key_action_mapper";
|
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { UPGRADES } from "../../upgrades";
|
import { UPGRADES } from "../../upgrades";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
@ -168,8 +168,8 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
this.inputReciever = new InputReceiver("shop");
|
this.inputReciever = new InputReceiver("shop");
|
||||||
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
|
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
|
||||||
|
|
||||||
this.keyActionMapper.getBinding("back").add(this.close, this);
|
this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this);
|
||||||
this.keyActionMapper.getBinding("menu_open_shop").add(this.close, this);
|
this.keyActionMapper.getBinding(KEYMAPPINGS.ingame.menuOpenShop).add(this.close, this);
|
||||||
|
|
||||||
this.close();
|
this.close();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Math_min } from "../../../core/builtins";
|
import { Math_min } from "../../../core/builtins";
|
||||||
import { InputReceiver } from "../../../core/input_receiver";
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
import { makeButton, makeDiv, removeAllChildren, capitalizeFirstLetter } from "../../../core/utils";
|
import { makeButton, makeDiv, removeAllChildren, capitalizeFirstLetter } from "../../../core/utils";
|
||||||
import { KeyActionMapper } from "../../key_action_mapper";
|
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { enumAnalyticsDataSource } from "../../production_analytics";
|
import { enumAnalyticsDataSource } from "../../production_analytics";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
@ -81,8 +81,8 @@ export class HUDStatistics extends BaseHUDPart {
|
|||||||
this.inputReciever = new InputReceiver("statistics");
|
this.inputReciever = new InputReceiver("statistics");
|
||||||
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
|
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
|
||||||
|
|
||||||
this.keyActionMapper.getBinding("back").add(this.close, this);
|
this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this);
|
||||||
this.keyActionMapper.getBinding("menu_open_stats").add(this.close, this);
|
this.keyActionMapper.getBinding(KEYMAPPINGS.ingame.menuOpenStats).add(this.close, this);
|
||||||
|
|
||||||
/** @type {Object.<string, HUDShapeStatisticsHandle>} */
|
/** @type {Object.<string, HUDShapeStatisticsHandle>} */
|
||||||
this.activeHandles = {};
|
this.activeHandles = {};
|
||||||
|
27
src/js/game/hud/parts/watermark.js
Normal file
27
src/js/game/hud/parts/watermark.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
import { DrawParameters } from "../../../core/draw_parameters";
|
||||||
|
|
||||||
|
export class HUDWatermark extends BaseHUDPart {
|
||||||
|
createElements() {}
|
||||||
|
|
||||||
|
initialize() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {DrawParameters} parameters
|
||||||
|
*/
|
||||||
|
drawOverlays(parameters) {
|
||||||
|
const w = this.root.gameWidth;
|
||||||
|
|
||||||
|
parameters.context.fillStyle = "#f77";
|
||||||
|
parameters.context.font = "50px GameFont";
|
||||||
|
parameters.context.textAlign = "center";
|
||||||
|
parameters.context.fillText("DEMO VERSION", w / 2, 100);
|
||||||
|
|
||||||
|
parameters.context.fillStyle = "#aaaca9";
|
||||||
|
parameters.context.font = "20px GameFont";
|
||||||
|
parameters.context.fillText("Get shapez.io on steam for the full experience!", w / 2, 140);
|
||||||
|
|
||||||
|
parameters.context.textAlign = "left";
|
||||||
|
}
|
||||||
|
}
|
@ -7,55 +7,72 @@ 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";
|
||||||
|
import { JSON_stringify } from "../core/builtins";
|
||||||
|
|
||||||
function key(str) {
|
function key(str) {
|
||||||
return str.toUpperCase().charCodeAt(0);
|
return str.toUpperCase().charCodeAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Configurable
|
export const KEYMAPPINGS = {
|
||||||
export const defaultKeybindings = {
|
|
||||||
general: {
|
general: {
|
||||||
confirm: { keyCode: 13 }, // enter
|
confirm: { keyCode: 13 }, // enter
|
||||||
back: { keyCode: 27, builtin: true }, // escape
|
back: { keyCode: 27, builtin: true }, // escape
|
||||||
},
|
},
|
||||||
|
|
||||||
ingame: {
|
ingame: {
|
||||||
map_move_up: { keyCode: key("W") },
|
mapMoveUp: { keyCode: key("W") },
|
||||||
map_move_right: { keyCode: key("D") },
|
mapMoveRight: { keyCode: key("D") },
|
||||||
map_move_down: { keyCode: key("S") },
|
mapMoveDown: { keyCode: key("S") },
|
||||||
map_move_left: { keyCode: key("A") },
|
mapMoveLeft: { keyCode: key("A") },
|
||||||
|
|
||||||
center_map: { keyCode: 32 },
|
centerMap: { keyCode: 32 },
|
||||||
|
|
||||||
menu_open_shop: { keyCode: key("F") },
|
menuOpenShop: { keyCode: key("F") },
|
||||||
menu_open_stats: { keyCode: key("G") },
|
menuOpenStats: { keyCode: key("G") },
|
||||||
|
|
||||||
confirm_mass_delete: { keyCode: key("X") }, // DEL
|
toggleHud: { keyCode: 113 }, // F2
|
||||||
toggle_hud: { keyCode: 113 }, // F2
|
|
||||||
},
|
},
|
||||||
|
|
||||||
toolbar: {
|
buildings: {
|
||||||
building_belt: { keyCode: key("1") },
|
belt: { keyCode: key("1") },
|
||||||
building_splitter: { keyCode: key("2") },
|
splitter: { keyCode: key("2") },
|
||||||
building_underground_belt: { keyCode: key("3") },
|
underground_belt: { keyCode: key("3") },
|
||||||
building_miner: { keyCode: key("4") },
|
miner: { keyCode: key("4") },
|
||||||
building_cutter: { keyCode: key("5") },
|
cutter: { keyCode: key("5") },
|
||||||
building_rotater: { keyCode: key("6") },
|
rotater: { keyCode: key("6") },
|
||||||
building_stacker: { keyCode: key("7") },
|
stacker: { keyCode: key("7") },
|
||||||
building_mixer: { keyCode: key("8") },
|
mixer: { keyCode: key("8") },
|
||||||
building_painter: { keyCode: key("9") },
|
painter: { keyCode: key("9") },
|
||||||
building_trash: { keyCode: key("0") },
|
trash: { keyCode: key("0") },
|
||||||
|
},
|
||||||
|
|
||||||
building_abort_placement: { keyCode: key("Q") },
|
placement: {
|
||||||
|
abortBuildingPlacement: { keyCode: key("Q") },
|
||||||
|
rotateWhilePlacing: { keyCode: key("R") },
|
||||||
|
cycleBuildingVariants: { keyCode: key("T") },
|
||||||
|
cycleBuildings: { keyCode: 9 }, // TAB
|
||||||
|
},
|
||||||
|
|
||||||
rotate_while_placing: { keyCode: key("R") },
|
massSelect: {
|
||||||
|
massSelectStart: { keyCode: 17, builtin: true }, // CTRL
|
||||||
|
massSelectSelectMultiple: { keyCode: 16, builtin: true }, // SHIFT
|
||||||
|
confirmMassDelete: { keyCode: key("X") },
|
||||||
|
},
|
||||||
|
|
||||||
cycle_variants: { keyCode: key("T") },
|
placementModifiers: {
|
||||||
|
placementDisableAutoOrientation: { keyCode: 17, builtin: true }, // CTRL
|
||||||
cycle_buildings: { keyCode: 9 },
|
placeMultiple: { keyCode: 16, builtin: true }, // SHIFT
|
||||||
|
placeInverse: { keyCode: 18, builtin: true }, // ALT
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Assign ids
|
||||||
|
for (const categoryId in KEYMAPPINGS) {
|
||||||
|
for (const mappingId in KEYMAPPINGS[categoryId]) {
|
||||||
|
KEYMAPPINGS[categoryId][mappingId].id = mappingId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a keycode -> string
|
* Returns a keycode -> string
|
||||||
* @param {number} code
|
* @param {number} code
|
||||||
@ -271,14 +288,14 @@ export class KeyActionMapper {
|
|||||||
/** @type {Object.<string, Keybinding>} */
|
/** @type {Object.<string, Keybinding>} */
|
||||||
this.keybindings = {};
|
this.keybindings = {};
|
||||||
|
|
||||||
// const overrides = root.app.settings.getKeybindingOverrides();
|
const overrides = root.app.settings.getKeybindingOverrides();
|
||||||
|
|
||||||
for (const category in defaultKeybindings) {
|
for (const category in KEYMAPPINGS) {
|
||||||
for (const key in defaultKeybindings[category]) {
|
for (const key in KEYMAPPINGS[category]) {
|
||||||
let payload = Object.assign({}, defaultKeybindings[category][key]);
|
let payload = Object.assign({}, KEYMAPPINGS[category][key]);
|
||||||
// if (overrides[key]) {
|
if (overrides[key]) {
|
||||||
// payload.keyCode = overrides[key];
|
payload.keyCode = overrides[key];
|
||||||
// }
|
}
|
||||||
|
|
||||||
this.keybindings[key] = new Keybinding(this.root.app, payload);
|
this.keybindings[key] = new Keybinding(this.root.app, payload);
|
||||||
}
|
}
|
||||||
@ -380,10 +397,13 @@ export class KeyActionMapper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a given keybinding
|
* Returns a given keybinding
|
||||||
* @param {string} id
|
* @param {{ keyCode: number }} binding
|
||||||
* @returns {Keybinding}
|
* @returns {Keybinding}
|
||||||
*/
|
*/
|
||||||
getBinding(id) {
|
getBinding(binding) {
|
||||||
|
// @ts-ignore
|
||||||
|
const id = binding.id;
|
||||||
|
assert(id, "Not a valid keybinding: " + JSON_stringify(binding));
|
||||||
assert(this.keybindings[id], "Keybinding " + id + " not known!");
|
assert(this.keybindings[id], "Keybinding " + id + " not known!");
|
||||||
return this.keybindings[id];
|
return this.keybindings[id];
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,11 @@ class SettingsStorage {
|
|||||||
this.musicMuted = false;
|
this.musicMuted = false;
|
||||||
this.theme = "light";
|
this.theme = "light";
|
||||||
this.refreshRate = "60";
|
this.refreshRate = "60";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object.<string, number>}
|
||||||
|
*/
|
||||||
|
this.keybindingOverrides = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +206,10 @@ export class ApplicationSettings extends ReadWriteProxy {
|
|||||||
return this.getAllSettings().fullscreen;
|
return this.getAllSettings().fullscreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getKeybindingOverrides() {
|
||||||
|
return this.getAllSettings().keybindingOverrides;
|
||||||
|
}
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,6 +233,33 @@ export class ApplicationSettings extends ReadWriteProxy {
|
|||||||
assertAlways(false, "Unknown setting: " + key);
|
assertAlways(false, "Unknown setting: " + key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a new keybinding override
|
||||||
|
* @param {string} keybindingId
|
||||||
|
* @param {number} keyCode
|
||||||
|
*/
|
||||||
|
updateKeybindingOverride(keybindingId, keyCode) {
|
||||||
|
assert(Number.isInteger(keyCode), "Not a valid key code: " + keyCode);
|
||||||
|
this.getAllSettings().keybindingOverrides[keybindingId] = keyCode;
|
||||||
|
return this.writeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets a given keybinding override
|
||||||
|
* @param {string} id
|
||||||
|
*/
|
||||||
|
resetKeybindingOverride(id) {
|
||||||
|
delete this.getAllSettings().keybindingOverrides[id];
|
||||||
|
return this.writeAsync();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Resets all keybinding overrides
|
||||||
|
*/
|
||||||
|
resetKeybindingOverrides() {
|
||||||
|
this.getAllSettings().keybindingOverrides = {};
|
||||||
|
return this.writeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
// RW Proxy impl
|
// RW Proxy impl
|
||||||
verify(data) {
|
verify(data) {
|
||||||
if (!data.settings) {
|
if (!data.settings) {
|
||||||
@ -252,7 +288,7 @@ export class ApplicationSettings extends ReadWriteProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCurrentVersion() {
|
getCurrentVersion() {
|
||||||
return 4;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
migrate(data) {
|
migrate(data) {
|
||||||
|
35
src/js/states/about.js
Normal file
35
src/js/states/about.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { TextualGameState } from "../core/textual_game_state";
|
||||||
|
import { SOUNDS } from "../platform/sound";
|
||||||
|
import { T } from "../translations";
|
||||||
|
import { KEYMAPPINGS, getStringForKeyCode } from "../game/key_action_mapper";
|
||||||
|
import { Dialog } from "../core/modal_dialog_elements";
|
||||||
|
|
||||||
|
export class AboutState extends TextualGameState {
|
||||||
|
constructor() {
|
||||||
|
super("AboutState");
|
||||||
|
}
|
||||||
|
|
||||||
|
getStateHeaderTitle() {
|
||||||
|
return T.about.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMainContentHTML() {
|
||||||
|
return `
|
||||||
|
This game is open source and developed by <a href="https://github.com/tobspr" target="_blank">Tobias Springer</a> (this is me).
|
||||||
|
<br><br>
|
||||||
|
If you want to contribute, check out <a href="https://github.com/tobspr/shapez.io" target="_blank">shapez.io on github</a>.
|
||||||
|
<br><br>
|
||||||
|
This game wouldn't have been possible without the great discord community arround my games - You should really join the <a href="https://discord.gg/HN7EVzV" target="_blank">discord server</a>!
|
||||||
|
<br><br>
|
||||||
|
The soundtrack was made by <a href="https://soundcloud.com/pettersumelius" target="_blank">Peppsen</a> - He's awesome.
|
||||||
|
<br><br>
|
||||||
|
Finally, huge thanks to my best friend <a href="https://github.com/niklas-dahl" target="_blank">Niklas</a> - Without our factorio sessions this game would never have existed.
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnter() {}
|
||||||
|
|
||||||
|
getDefaultPreviousState() {
|
||||||
|
return "SettingsState";
|
||||||
|
}
|
||||||
|
}
|
171
src/js/states/keybindings.js
Normal file
171
src/js/states/keybindings.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import { TextualGameState } from "../core/textual_game_state";
|
||||||
|
import { SOUNDS } from "../platform/sound";
|
||||||
|
import { T } from "../translations";
|
||||||
|
import { KEYMAPPINGS, getStringForKeyCode } from "../game/key_action_mapper";
|
||||||
|
import { Dialog } from "../core/modal_dialog_elements";
|
||||||
|
|
||||||
|
export class KeybindingsState extends TextualGameState {
|
||||||
|
constructor() {
|
||||||
|
super("KeybindingsState");
|
||||||
|
}
|
||||||
|
|
||||||
|
getStateHeaderTitle() {
|
||||||
|
return T.keybindings.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMainContentHTML() {
|
||||||
|
return `
|
||||||
|
|
||||||
|
<div class="topEntries">
|
||||||
|
<span class="hint">${T.keybindings.hint}</span>
|
||||||
|
<button class="styledButton resetBindings">${T.keybindings.resetKeybindings}</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="keybindings">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnter() {
|
||||||
|
const keybindingsElem = this.htmlElement.querySelector(".keybindings");
|
||||||
|
|
||||||
|
this.trackClicks(this.htmlElement.querySelector(".resetBindings"), this.resetBindings);
|
||||||
|
|
||||||
|
for (const category in KEYMAPPINGS) {
|
||||||
|
const categoryDiv = document.createElement("div");
|
||||||
|
categoryDiv.classList.add("category");
|
||||||
|
keybindingsElem.appendChild(categoryDiv);
|
||||||
|
|
||||||
|
const labelDiv = document.createElement("strong");
|
||||||
|
labelDiv.innerText = T.keybindings.categoryLabels[category];
|
||||||
|
labelDiv.classList.add("categoryLabel");
|
||||||
|
categoryDiv.appendChild(labelDiv);
|
||||||
|
|
||||||
|
for (const keybindingId in KEYMAPPINGS[category]) {
|
||||||
|
const mapped = KEYMAPPINGS[category][keybindingId];
|
||||||
|
|
||||||
|
const elem = document.createElement("div");
|
||||||
|
elem.classList.add("entry");
|
||||||
|
elem.setAttribute("data-keybinding", keybindingId);
|
||||||
|
categoryDiv.appendChild(elem);
|
||||||
|
|
||||||
|
const title = document.createElement("span");
|
||||||
|
title.classList.add("title");
|
||||||
|
title.innerText = T.keybindings.mappings[keybindingId];
|
||||||
|
elem.appendChild(title);
|
||||||
|
|
||||||
|
const mappingDiv = document.createElement("span");
|
||||||
|
mappingDiv.classList.add("mapping");
|
||||||
|
elem.appendChild(mappingDiv);
|
||||||
|
|
||||||
|
const editBtn = document.createElement("button");
|
||||||
|
editBtn.classList.add("styledButton", "editKeybinding");
|
||||||
|
|
||||||
|
const resetBtn = document.createElement("button");
|
||||||
|
resetBtn.classList.add("styledButton", "resetKeybinding");
|
||||||
|
|
||||||
|
if (mapped.builtin) {
|
||||||
|
editBtn.classList.add("disabled");
|
||||||
|
resetBtn.classList.add("disabled");
|
||||||
|
} else {
|
||||||
|
this.trackClicks(editBtn, () => this.editKeybinding(keybindingId));
|
||||||
|
this.trackClicks(resetBtn, () => this.resetKeybinding(keybindingId));
|
||||||
|
}
|
||||||
|
elem.appendChild(editBtn);
|
||||||
|
elem.appendChild(resetBtn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.updateKeybindings();
|
||||||
|
}
|
||||||
|
|
||||||
|
editKeybinding(id) {
|
||||||
|
const dialog = new Dialog({
|
||||||
|
app: this.app,
|
||||||
|
title: T.dialogs.editKeybinding.title,
|
||||||
|
contentHTML: T.dialogs.editKeybinding.desc,
|
||||||
|
buttons: ["cancel:good"],
|
||||||
|
type: "info",
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.inputReciever.keydown.add(({ keyCode, shift, alt, event }) => {
|
||||||
|
if (keyCode === 27) {
|
||||||
|
this.dialogs.closeDialog(dialog);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
// Enter
|
||||||
|
keyCode === 13 ||
|
||||||
|
// TAB
|
||||||
|
keyCode === 9
|
||||||
|
) {
|
||||||
|
// Ignore builtins
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.app.settings.updateKeybindingOverride(id, keyCode);
|
||||||
|
|
||||||
|
this.dialogs.closeDialog(dialog);
|
||||||
|
this.updateKeybindings();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.inputReciever.backButton.add(() => {});
|
||||||
|
|
||||||
|
this.dialogs.internalShowDialog(dialog);
|
||||||
|
this.app.sound.playUiSound(SOUNDS.dialogOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateKeybindings() {
|
||||||
|
const overrides = this.app.settings.getKeybindingOverrides();
|
||||||
|
for (const category in KEYMAPPINGS) {
|
||||||
|
for (const keybindingId in KEYMAPPINGS[category]) {
|
||||||
|
const mapped = KEYMAPPINGS[category][keybindingId];
|
||||||
|
|
||||||
|
const container = this.htmlElement.querySelector("[data-keybinding='" + keybindingId + "']");
|
||||||
|
assert(container, "Container for keybinding not found: " + keybindingId);
|
||||||
|
|
||||||
|
let keyCode = mapped.keyCode;
|
||||||
|
if (overrides[keybindingId]) {
|
||||||
|
keyCode = overrides[keybindingId];
|
||||||
|
}
|
||||||
|
|
||||||
|
const mappingDiv = container.querySelector(".mapping");
|
||||||
|
mappingDiv.innerHTML = getStringForKeyCode(keyCode);
|
||||||
|
mappingDiv.classList.toggle("changed", !!overrides[keybindingId]);
|
||||||
|
|
||||||
|
const resetBtn = container.querySelector("button.resetKeybinding");
|
||||||
|
resetBtn.classList.toggle("disabled", mapped.builtin || !overrides[keybindingId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resetKeybinding(id) {
|
||||||
|
this.app.settings.resetKeybindingOverride(id);
|
||||||
|
this.updateKeybindings();
|
||||||
|
}
|
||||||
|
|
||||||
|
resetBindings() {
|
||||||
|
const { reset } = this.dialogs.showWarning(
|
||||||
|
T.dialogs.resetKeybindingsConfirmation.title,
|
||||||
|
T.dialogs.resetKeybindingsConfirmation.desc,
|
||||||
|
["cancel:good", "reset:bad"]
|
||||||
|
);
|
||||||
|
|
||||||
|
reset.add(() => {
|
||||||
|
this.app.settings.resetKeybindingOverrides();
|
||||||
|
this.updateKeybindings();
|
||||||
|
|
||||||
|
this.dialogs.showInfo(T.dialogs.keybindingsResetOk.title, T.dialogs.keybindingsResetOk.desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultPreviousState() {
|
||||||
|
return "SettingsState";
|
||||||
|
}
|
||||||
|
}
|
@ -23,9 +23,7 @@ export class SettingsState extends TextualGameState {
|
|||||||
`
|
`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
|
<button class="styledButton about">${T.about.title}</button>
|
||||||
<button class="styledButton changelog">Changelog</button>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -33,7 +31,6 @@ export class SettingsState extends TextualGameState {
|
|||||||
${this.getSettingsHtml()}
|
${this.getSettingsHtml()}
|
||||||
<div class="versionbar">
|
<div class="versionbar">
|
||||||
<div class="buildVersion">${T.global.loading} ...</div>
|
<div class="buildVersion">${T.global.loading} ...</div>
|
||||||
<button class="styledButton copyright">Copyright & Licenses</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -82,10 +79,7 @@ export class SettingsState extends TextualGameState {
|
|||||||
|
|
||||||
onEnter(payload) {
|
onEnter(payload) {
|
||||||
this.renderBuildText();
|
this.renderBuildText();
|
||||||
this.trackClicks(this.htmlElement.querySelector(".copyright"), this.onCopyrightClicked, {
|
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
|
||||||
preventDefault: false,
|
|
||||||
});
|
|
||||||
this.trackClicks(this.htmlElement.querySelector(".changelog"), this.onChangelogClicked, {
|
|
||||||
preventDefault: false,
|
preventDefault: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -113,8 +107,8 @@ export class SettingsState extends TextualGameState {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCopyrightClicked() {
|
onAboutClicked() {
|
||||||
// this.moveToStateAddGoBack("CopyrightState");
|
this.moveToStateAddGoBack("AboutState");
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangelogClicked() {
|
onChangelogClicked() {
|
||||||
@ -122,6 +116,6 @@ export class SettingsState extends TextualGameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onKeybindingsClicked() {
|
onKeybindingsClicked() {
|
||||||
// this.moveToStateAddGoBack("KeybindingsState");
|
this.moveToStateAddGoBack("KeybindingsState");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,7 @@ dialogs:
|
|||||||
cancel: Cancel
|
cancel: Cancel
|
||||||
later: Later
|
later: Later
|
||||||
restart: Restart
|
restart: Restart
|
||||||
|
reset: Reset
|
||||||
|
|
||||||
importSavegameError:
|
importSavegameError:
|
||||||
title: Import Error
|
title: Import Error
|
||||||
@ -113,6 +114,18 @@ dialogs:
|
|||||||
text: >-
|
text: >-
|
||||||
You need to restart the game to apply the settings.
|
You need to restart the game to apply the settings.
|
||||||
|
|
||||||
|
editKeybinding:
|
||||||
|
title: Change Keybinding
|
||||||
|
desc: Press the key you want to assign, or escape to cancel.
|
||||||
|
|
||||||
|
resetKeybindingsConfirmation:
|
||||||
|
title: Reset keybindings
|
||||||
|
desc: This will reset all keybindings to their default values. Please confirm.
|
||||||
|
|
||||||
|
keybindingsResetOk:
|
||||||
|
title: Keybindings reset
|
||||||
|
desc: The keybindings have been reset to their respective defaults!
|
||||||
|
|
||||||
ingame:
|
ingame:
|
||||||
# This is shown in the top left corner and displays useful keybindings in
|
# This is shown in the top left corner and displays useful keybindings in
|
||||||
# every situation
|
# every situation
|
||||||
@ -226,43 +239,43 @@ shopUpgrades:
|
|||||||
# Buildings and their name / description
|
# Buildings and their name / description
|
||||||
buildings:
|
buildings:
|
||||||
belt:
|
belt:
|
||||||
name: Belt
|
name: &belt Belt
|
||||||
description: Transports items, hold and drag to place multiple.
|
description: Transports items, hold and drag to place multiple.
|
||||||
|
|
||||||
miner: # Internal name for the Extractor
|
miner: # Internal name for the Extractor
|
||||||
name: Extractor
|
name: &miner Extractor
|
||||||
description: Place over a shape or color to extract it.
|
description: Place over a shape or color to extract it.
|
||||||
|
|
||||||
underground_belt: # Internal name for the Tunnel
|
underground_belt: # Internal name for the Tunnel
|
||||||
name: Tunnel
|
name: &underground_belt Tunnel
|
||||||
description: Allows to tunnel resources under buildings and belts.
|
description: Allows to tunnel resources under buildings and belts.
|
||||||
|
|
||||||
splitter: # Internal name for the Balancer
|
splitter: # Internal name for the Balancer
|
||||||
name: Balancer
|
name: &splitter Balancer
|
||||||
description: Multifunctional - Evenly distributes all inputs onto all outputs.
|
description: Multifunctional - Evenly distributes all inputs onto all outputs.
|
||||||
|
|
||||||
cutter:
|
cutter:
|
||||||
name: Cut Half
|
name: &cutter Cut Half
|
||||||
description: Cuts shapes from top to bottom and outputs both halfs. <strong>If you use only one part, be sure to destroy the other part or it will stall!</strong>
|
description: Cuts shapes from top to bottom and outputs both halfs. <strong>If you use only one part, be sure to destroy the other part or it will stall!</strong>
|
||||||
|
|
||||||
rotater:
|
rotater:
|
||||||
name: Rotate
|
name: &rotater Rotate
|
||||||
description: Rotates shapes clockwise by 90 degrees.
|
description: Rotates shapes clockwise by 90 degrees.
|
||||||
|
|
||||||
stacker: # Internal name for the Combiner
|
stacker: # Internal name for the Combiner
|
||||||
name: Combine
|
name: &stacker Combine
|
||||||
description: Combines both items. If they can not be merged, the right item is placed above the left item.
|
description: Combines both items. If they can not be merged, the right item is placed above the left item.
|
||||||
|
|
||||||
mixer:
|
mixer:
|
||||||
name: Mix Colors
|
name: &mixer Mix Colors
|
||||||
description: Mixes two colors using additive blending.
|
description: Mixes two colors using additive blending.
|
||||||
|
|
||||||
painter:
|
painter:
|
||||||
name: Dye
|
name: &painter Dye
|
||||||
description: Colors the whole shape on the left input with the color from the right input.
|
description: Colors the whole shape on the left input with the color from the right input.
|
||||||
|
|
||||||
trash: # Internal name for the destroyer
|
trash: # Internal name for the destroyer
|
||||||
name: Destroyed
|
name: &trash Destroyed
|
||||||
description: Accepts inputs from all sides and destroys them. Forever.
|
description: Accepts inputs from all sides and destroys them. Forever.
|
||||||
|
|
||||||
storyRewards:
|
storyRewards:
|
||||||
@ -329,4 +342,60 @@ settings:
|
|||||||
refreshRate:
|
refreshRate:
|
||||||
title: Simulation Target
|
title: Simulation Target
|
||||||
description: >-
|
description: >-
|
||||||
If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates.
|
If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates. This might actually decrease the FPS if your computer is too slow.
|
||||||
|
|
||||||
|
keybindings:
|
||||||
|
title: Keybindings
|
||||||
|
hint: >-
|
||||||
|
Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different placement options.
|
||||||
|
|
||||||
|
resetKeybindings: Reset Keyinbindings
|
||||||
|
|
||||||
|
categoryLabels:
|
||||||
|
general: Appplication
|
||||||
|
ingame: Game
|
||||||
|
placement: Placement
|
||||||
|
massSelect: Mass Delete
|
||||||
|
buildings: Building Shortcuts
|
||||||
|
placementModifiers: Placement Modifiers
|
||||||
|
|
||||||
|
mappings:
|
||||||
|
confirm: Confirm
|
||||||
|
back: Back
|
||||||
|
mapMoveUp: Move Up
|
||||||
|
mapMoveRight: Move Right
|
||||||
|
mapMoveDown: Move Down
|
||||||
|
mapMoveLeft: Move Left
|
||||||
|
|
||||||
|
centerMap: Center Map
|
||||||
|
|
||||||
|
menuOpenShop: Upgrades
|
||||||
|
menuOpenStats: Statistics
|
||||||
|
|
||||||
|
toggleHud: Toggle HUD
|
||||||
|
belt: *belt
|
||||||
|
splitter: *splitter
|
||||||
|
underground_belt: *underground_belt
|
||||||
|
miner: *miner
|
||||||
|
cutter: *cutter
|
||||||
|
rotater: *rotater
|
||||||
|
stacker: *stacker
|
||||||
|
mixer: *mixer
|
||||||
|
painter: *painter
|
||||||
|
trash: *trash
|
||||||
|
|
||||||
|
abortBuildingPlacement: Abort Placement
|
||||||
|
rotateWhilePlacing: Rotate
|
||||||
|
cycleBuildingVariants: Cycle Variants
|
||||||
|
confirmMassDelete: Confirm Mass Delete
|
||||||
|
cycleBuildings: Cycle Buildings
|
||||||
|
|
||||||
|
massSelectStart: Hold and drag to start
|
||||||
|
massSelectSelectMultiple: Select multiple areas
|
||||||
|
|
||||||
|
placementDisableAutoOrientation: Disable automatic orientation
|
||||||
|
placeMultiple: Stay in placement mode
|
||||||
|
placeInverse: Invert automatic orientation
|
||||||
|
|
||||||
|
about:
|
||||||
|
title: About this Game
|
||||||
|
Loading…
Reference in New Issue
Block a user