1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Integrate with addition of new setting in master.

This commit is contained in:
hexagonhexagon 2020-06-01 14:01:32 -04:00
commit 6f7d0a4444
29 changed files with 301 additions and 104 deletions

View File

@ -1,15 +1,15 @@
# shapez.io
<img src="https://i.imgur.com/Y5Z2iqQ.png" alt="shapez.io Logo">
<img src="https://i.imgur.com/W25Fkl0.png" alt="shapez.io Screenshot">
This is the source code for shapez.io, an open source base building game inspired by Factorio.
Your goal is to produce shapes by cutting, rotating, merging and painting parts of shapes.
## Playing
You can already play it [here](https://shapez.io).
- [Trello Board & Roadmap](https://trello.com/b/ISQncpJP/shapezio)
- [Free web version](https://shapez.io)
- [itch.io Page](https://tobspr.itch.io/shapezio)
- [Steam Page](https://steam.shapez.io)
- [Official Discord](https://discord.com/invite/HN7EVzV) <- _Highly recommended to join!_
## Building
@ -46,3 +46,5 @@ This project is based on ES5. Some ES2015 features are used but most of them are
For most assets I use Adobe Photoshop, you can find them in `assets/`.
You will need a <a href="https://www.codeandweb.com/texturepacker" target="_blank">Texture Packer</a> license in order to regenerate the atlas. If you don't have one but want to contribute assets, let me know and I might compile it for you. I'm currently switching to an open source solution but I can't give an estimate when thats done.
<img src="https://i.imgur.com/W25Fkl0.png" alt="shapez.io Screenshot">

9
gulp/.itch.toml Normal file
View File

@ -0,0 +1,9 @@
[[actions]]
name = "play"
path = "shapezio.exe"
platform = "windows"
[[actions]]
name = "play"
path = "play.sh"
platform = "linux"

View File

@ -121,6 +121,8 @@ function gulptasksStandalone($, gulp, buildFolder) {
* @param {boolean=} isRelease
*/
function packageStandalone(platform, arch, cb, isRelease = false) {
const tomlFile = fs.readFileSync(path.join(__dirname, ".itch.toml"));
packager({
dir: tempDestBuildDir,
appCopyright: "Tobias Springer",
@ -150,17 +152,25 @@ function gulptasksStandalone($, gulp, buildFolder) {
fs.readFileSync(path.join(__dirname, "..", "LICENSE"))
);
const playablePath = appPath + "_playable";
fse.copySync(appPath, playablePath);
fs.writeFileSync(path.join(playablePath, "steam_appid.txt"), "1134480");
fs.writeFileSync(
path.join(playablePath, "play.bat"),
"start shapezio --dev --disable-direct-composition --in-process-gpu\r\n"
);
fs.writeFileSync(
path.join(playablePath, "play_local.bat"),
"start shapezio --local --dev --disable-direct-composition --in-process-gpu\r\n"
);
fs.writeFileSync(path.join(appPath, ".itch.toml"), tomlFile);
if (platform === "linux" || platform === "darwin") {
fs.writeFileSync(path.join(appPath, "play.sh"), "#!/usr/bin/env bash\n./shapezio\n");
fs.chmodSync(path.join(appPath, "play.sh"), 0o775);
} else if (platform === "win32") {
// Optional: Create a playable copy. Shouldn't be required
// const playablePath = appPath + "_playable";
// fse.copySync(appPath, playablePath);
// fs.writeFileSync(path.join(playablePath, "steam_appid.txt"), "1134480");
// fs.writeFileSync(
// path.join(playablePath, "play.bat"),
// "start shapezio --dev --disable-direct-composition --in-process-gpu\r\n"
// );
// fs.writeFileSync(
// path.join(playablePath, "play_local.bat"),
// "start shapezio --local --dev --disable-direct-composition --in-process-gpu\r\n"
// );
}
});
cb();
@ -182,10 +192,10 @@ function gulptasksStandalone($, gulp, buildFolder) {
"standalone.package.prod",
$.sequence("standalone.prepare", [
"standalone.package.prod.win64",
// "standalone.package.prod.linux64",
"standalone.package.prod.linux64",
"standalone.package.prod.darwin64",
// "standalone.package.prod.win32",
// "standalone.package.prod.linux32",
// "standalone.package.prod.darwin64"
])
);
}

View File

@ -11,7 +11,8 @@
"tslint": "cd src/js && tsc",
"lint": "npx eslint src/js",
"prettier-all": "prettier --write src/**/*.* && prettier --write gulp/**/*.*",
"publishOnItch": "butler push tmp_standalone_files/shapez.io-standalone-win32-x64 tobspr/shapezio:windows --userversion-file version",
"publishOnItchWindows": "butler push tmp_standalone_files/shapez.io-standalone-win32-x64 tobspr/shapezio:windows --userversion-file version",
"publishOnItchLinux": "butler push tmp_standalone_files/shapez.io-standalone-linux-x64 tobspr/shapezio:linux-experimental --userversion-file version",
"publishOnSteam": "cd gulp/steampipe && ./upload.bat",
"publishStandalone": "yarn publishOnItch && yarn publishOnSteam",
"publishWeb": "cd gulp && yarn main.deploy.prod",

View File

@ -11,7 +11,11 @@
border-bottom-width: 0;
transition: transform 0.12s ease-in-out;
background: rgba(mix(#ddd, $colorBlueBright, 80%), 0.69);
background: rgba(mix(#ddd, $colorBlueBright, 90%), 0.75);
@include DarkThemeOverride {
background: #222428;
}
&:not(.visible) {
transform: translateX(-50%) translateY(#{D(100px)});

View File

@ -6,8 +6,12 @@
display: flex;
flex-direction: column;
align-items: flex-start;
color: #fff;
text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.1);
color: #333438;
// text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.1);
@include DarkThemeOverride {
color: #fff;
}
> .binding {
display: inline-grid;
@ -42,10 +46,13 @@
}
label {
color: $accentColorDark;
color: #333438;
@include SuperSmallText;
text-transform: uppercase;
color: #fff;
// color: #fff;
@include DarkThemeOverride {
color: #fff;
}
@include S(margin-left, 5px);
}

View File

@ -16,8 +16,8 @@
grid-template-columns: auto 1fr;
grid-template-rows: 1fr 1fr;
@include S(margin-bottom, 4px);
color: #fff;
text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.2);
color: #333438;
// text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.2);
&.unpinable {
> canvas {
@ -59,7 +59,7 @@
> .goalLabel {
@include S(font-size, 7px);
opacity: 0.5;
opacity: 0.9;
align-self: start;
justify-self: start;
font-weight: normal;
@ -81,7 +81,6 @@
display: inline-block;
@include S(width, 8px);
@include S(height, 8px);
opacity: 0.8;
@include S(top, 4px);
@include S(left, -7px);
background: uiResource("icons/current_goal_marker.png") center center / contain no-repeat;

View File

@ -38,13 +38,13 @@
@include SuperSmallText;
pointer-events: all;
cursor: pointer;
color: #000;
color: #333438;
@include S(padding-left, 11px);
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
background: uiResource("icons/waypoint.png") left 50% / #{D(8px)} no-repeat;
opacity: 0.5;
opacity: 0.7;
@include S(margin-bottom, 1px);
font-weight: bold;
&:hover {

View File

@ -36,6 +36,9 @@
@include S(padding, 1px, 2px);
@include S(margin-right, 3px);
}
a {
color: $colorBlueBright;
}
}
}

View File

@ -40,6 +40,9 @@
<meta http-equiv="Expires" content="0" />
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<link rel="canonical" href="https://shapez.io" />
<!-- a/b testing -->
<script src="https://www.googleoptimize.com/optimize.js?id=OPT-M5NHCV7"></script>
</head>
<body oncontextmenu="return false" style="background: #393747;"></body>

View File

@ -1,11 +1,25 @@
export const CHANGELOG = [
{
version: "1.1.2",
date: "unreleased",
version: "1.1.3",
date: "01.06.2020",
entries: [
"Added setting to configure zoom / mouse wheel / touchpad sensitivity",
"Fix belts being too slow when copied via blueprint (by Dimava)",
"Allow binding mouse buttons to actions (by Dimava)",
"Increase readability of certain HUD elements",
],
},
{
version: "1.1.2",
date: "30.05.2020",
entries: [
"The official trailer is now ready! Check it out <a href='https://www.youtube.com/watch?v=KyorY1uIqiQ' target='_blank'>here</a>!",
"The <a href='https://steam.shapez.io' target='_blank'>steam page</a> is now live!",
"Experimental linux builds are now available! Please give me feedback on them in the discord",
"Allow hovering pinned shapes to enlarge them",
"Allow deselecting blueprints with right click and 'Q'",
"Move default key for deleting from 'X' to 'DEL'",
"Show confirmation when deleting > 100 buildings",
"Show confirmation when deleting more than 100 buildings",
"Reintroduce 'SPACE' keybinding to center on map",
"Improved keybinding hints",
"Fixed some keybindings showing as 'undefined'",

View File

@ -311,7 +311,7 @@ export class ClickDetector {
const position = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event);
if (event instanceof MouseEvent) {
const isRightClick = event.which == 3;
const isRightClick = event.button === 2;
if (isRightClick) {
// Ignore right clicks
this.rightClick.dispatch(position, event);
@ -384,7 +384,7 @@ export class ClickDetector {
}
if (event instanceof MouseEvent) {
const isRightClick = event.which == 3;
const isRightClick = event.button === 2;
if (isRightClick) {
return;
}

View File

@ -83,7 +83,7 @@ export const globalConfig = {
debug: {
/* dev:start */
fastGameEnter: true,
// fastGameEnter: true,
// noArtificialDelays: true,
// disableSavegameWrite: true,
// showEntityBounds: true,

View File

@ -141,8 +141,13 @@ export class InputDistributor {
bindToEvents() {
window.addEventListener("popstate", this.handleBackButton.bind(this), false);
document.addEventListener("backbutton", this.handleBackButton.bind(this), false);
window.addEventListener("keydown", this.handleKeydown.bind(this));
window.addEventListener("keyup", this.handleKeyup.bind(this));
window.addEventListener("keydown", this.handleKeyMouseDown.bind(this));
window.addEventListener("keyup", this.handleKeyMouseUp.bind(this));
window.addEventListener("mousedown", this.handleKeyMouseDown.bind(this));
window.addEventListener("mouseup", this.handleKeyMouseUp.bind(this));
window.addEventListener("blur", this.handleBlur.bind(this));
}
@ -182,25 +187,28 @@ export class InputDistributor {
}
/**
* @param {KeyboardEvent} event
* @param {KeyboardEvent | MouseEvent} event
*/
handleKeydown(event) {
handleKeyMouseDown(event) {
const keyCode = event instanceof MouseEvent ? event.button + 1 : event.keyCode;
if (
event.keyCode === 9 || // TAB
event.keyCode === 16 || // SHIFT
event.keyCode === 17 || // CTRL
event.keyCode === 18 || // ALT
(event.keyCode >= 112 && event.keyCode < 122) // F1 - F10
keyCode === 4 || // MB4
keyCode === 5 || // MB5
keyCode === 9 || // TAB
keyCode === 16 || // SHIFT
keyCode === 17 || // CTRL
keyCode === 18 || // ALT
(keyCode >= 112 && keyCode < 122) // F1 - F10
) {
event.preventDefault();
}
const isInitial = !this.keysDown.has(event.keyCode);
this.keysDown.add(event.keyCode);
const isInitial = !this.keysDown.has(keyCode);
this.keysDown.add(keyCode);
if (
this.forwardToReceiver("keydown", {
keyCode: event.keyCode,
keyCode: keyCode,
shift: event.shiftKey,
alt: event.altKey,
initial: isInitial,
@ -210,8 +218,7 @@ export class InputDistributor {
return;
}
const code = event.keyCode;
if (code === 27) {
if (keyCode === 27) {
// Escape key
event.preventDefault();
event.stopPropagation();
@ -220,13 +227,14 @@ export class InputDistributor {
}
/**
* @param {KeyboardEvent} event
* @param {KeyboardEvent | MouseEvent} event
*/
handleKeyup(event) {
this.keysDown.delete(event.keyCode);
handleKeyMouseUp(event) {
const keyCode = event instanceof MouseEvent ? event.button + 1 : event.keyCode;
this.keysDown.delete(keyCode);
this.forwardToReceiver("keyup", {
keyCode: event.keyCode,
keyCode: keyCode,
shift: event.shiftKey,
alt: event.altKey,
});

View File

@ -24,9 +24,7 @@ export const BOTTOM = new Vector(0, 1);
export const LEFT = new Vector(-1, 0);
export const ALL_DIRECTIONS = [TOP, RIGHT, BOTTOM, LEFT];
export const thousand = 1000;
export const million = 1000 * 1000;
export const billion = 1000 * 1000 * 1000;
const bigNumberSuffixTranslationKeys = ["thousands", "millions", "billions", "trillions"];
/**
* Returns the build id
@ -435,21 +433,20 @@ export function formatBigNumber(num, divider = ".") {
if (num < 1000) {
return sign + "" + num;
} else {
let leadingDigits = num;
let suffix = "";
for (let suffixIndex = 0; suffixIndex < bigNumberSuffixTranslationKeys.length; ++suffixIndex) {
leadingDigits = leadingDigits / 1000;
suffix = T.global.suffix[bigNumberSuffixTranslationKeys[suffixIndex]];
if (leadingDigits < 1000) {
break;
}
}
const leadingDigitsRounded = round1Digit(leadingDigits);
const leadingDigitsNoTrailingDecimal = leadingDigitsRounded.toString().replace(".0", "");
return sign + leadingDigitsNoTrailingDecimal + suffix;
}
if (num > 10000) {
return Math_floor(num / 1000.0) + "k";
}
let rest = num;
let out = "";
while (rest >= 1000) {
out = (rest % 1000).toString().padStart(3, "0") + (out !== "" ? divider : "") + out;
rest = Math_floor(rest / 1000);
}
out = rest + divider + out;
return sign + out;
}
/**
@ -731,14 +728,14 @@ export function checkTimerExpired(now, lastTick, tickRate) {
Client A computes the timer and checks T > lastTick + interval. He computes
30 >= 29.90 + 0.1 <=> 30 >= 30.0000 <=> True <=> Tick performed
However, this is what it looks on client B:
33 >= 32.90 + 0.1 <=> 33 >= 32.999999999999998 <=> False <=> No tick performed!
This means that Client B will only tick at the *next* frame, which means it from now is out
of sync by one tick, which means the game will resync further or later and be not able to recover,
since it will run into the same issue over and over.
since it will run into the same issue over and over.
*/
// The next tick, in our example it would be 30.0000 / 32.99999999998. In order to fix it, we quantize

View File

@ -440,11 +440,11 @@ export class Camera extends BasicSerializableObject {
}
this.touchPostMoveVelocity = new Vector(0, 0);
if (event.which === 1) {
if (event.button === 0) {
this.combinedSingleTouchStartHandler(event.clientX, event.clientY);
} else if (event.which === 2) {
} else if (event.button === 1) {
this.downPreHandler.dispatch(new Vector(event.clientX, event.clientY), enumMouseButton.middle);
} else if (event.which === 3) {
} else if (event.button === 2) {
this.downPreHandler.dispatch(new Vector(event.clientX, event.clientY), enumMouseButton.right);
}
return false;
@ -464,7 +464,7 @@ export class Camera extends BasicSerializableObject {
return;
}
if (event.which === 1) {
if (event.button === 0) {
this.combinedSingleTouchMoveHandler(event.clientX, event.clientY);
}
@ -503,7 +503,7 @@ export class Camera extends BasicSerializableObject {
// event.stopPropagation();
}
const delta = Math.sign(event.deltaY) * -0.15;
const delta = Math.sign(event.deltaY) * -0.15 * this.root.app.settings.getScrollWheelSensitivity();
assert(Number.isFinite(delta), "Got invalid delta in mouse wheel event: " + event.deltaY);
assert(Number.isFinite(this.zoomLevel), "Got invalid zoom level *before* wheel: " + this.zoomLevel);
this.zoomLevel *= 1 + delta;

View File

@ -44,7 +44,7 @@ export class ItemEjectorComponent extends Component {
return new ItemEjectorComponent({
slots: slotsCopy,
instantEject: false,
instantEject: this.instantEject,
});
}

View File

@ -48,8 +48,8 @@ export class GameHUD {
this.parts = {
processingOverlay: new HUDProcessingOverlay(this.root),
buildingsToolbar: new HUDBuildingsToolbar(this.root),
buildingPlacer: new HUDBuildingPlacer(this.root),
blueprintPlacer: new HUDBlueprintPlacer(this.root),
buildingPlacer: new HUDBuildingPlacer(this.root),
unlockNotification: new HUDUnlockNotification(this.root),
gameMenu: new HUDGameMenu(this.root),
massSelector: new HUDMassSelector(this.root),

View File

@ -1,4 +1,4 @@
import { DrawParameters } from "../../../core/draw_parameters";
//www.youtube.com/watch?v=KyorY1uIqiQimport { DrawParameters } from "../../../core/draw_parameters";
import { STOP_PROPAGATION } from "../../../core/signal";
import { TrackedState } from "../../../core/tracked_state";
import { Vector } from "../../../core/vector";
@ -36,6 +36,9 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
.getBinding(KEYMAPPINGS.placement.abortBuildingPlacement)
.add(this.abortPlacement, this);
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
keyActionMapper
.getBinding(KEYMAPPINGS.placement.abortBuildingPlacement)
.add(this.abortPlacement, this);
this.root.camera.downPreHandler.add(this.onMouseDown, this);
this.root.camera.movePreHandler.add(this.onMouseMove, this);

View File

@ -89,6 +89,16 @@ for (const categoryId in KEYMAPPINGS) {
*/
export function getStringForKeyCode(code) {
switch (code) {
case 1:
return "LMB";
case 2:
return "MMB";
case 3:
return "RMB";
case 4:
return "MB4";
case 5:
return "MB5";
case 8:
return "⌫";
case 9:

View File

@ -66,11 +66,6 @@ export class GoogleAnalyticsImpl extends AnalyticsInterface {
}
trackUiClick(elementName) {
// Only track a fraction of clicks to not annoy google analytics
if (Math_random() < 0.9) {
return;
}
const stateKey = this.app.stateMgr.getCurrentState().key;
const fullSelector = stateKey + ">" + elementName;

View File

@ -8,6 +8,7 @@ import { createLogger } from "../core/logging";
import { ExplainedResult } from "../core/explained_result";
import { THEMES, THEME, applyGameTheme } from "../game/theme";
import { IS_DEMO } from "../core/config";
import { T } from "../translations";
const logger = createLogger("application_settings");
@ -18,27 +19,45 @@ export const uiScales = [
{
id: "super_small",
size: 0.6,
label: "Super small",
},
{
id: "small",
size: 0.8,
label: "Small",
},
{
id: "regular",
size: 1,
label: "Regular",
},
{
id: "large",
size: 1.2,
label: "Large",
},
{
id: "huge",
size: 1.4,
label: "Huge",
},
];
export const scrollWheelSensitivities = [
{
id: "super_slow",
scale: 0.25,
},
{
id: "slow",
scale: 0.5,
},
{
id: "regular",
scale: 1,
},
{
id: "fast",
scale: 2,
},
{
id: "super_fast",
scale: 4,
},
];
@ -47,7 +66,7 @@ export const allApplicationSettings = [
new EnumSetting("uiScale", {
options: uiScales.sort((a, b) => a.size - b.size),
valueGetter: scale => scale.id,
textGetter: scale => scale.label,
textGetter: scale => T.settings.labels.uiScale.scales[scale.id],
category: categoryApp,
restartRequired: false,
changeCb:
@ -56,6 +75,7 @@ export const allApplicationSettings = [
*/
(app, id) => app.updateAfterUiScaleChanged(),
}),
new BoolSetting(
"fullscreen",
categoryApp,
@ -86,6 +106,18 @@ export const allApplicationSettings = [
*/
(app, value) => app.sound.setMusicMuted(value)
),
new EnumSetting("scrollWheelSensitivity", {
options: scrollWheelSensitivities.sort((a, b) => a.scale - b.scale),
valueGetter: scale => scale.id,
textGetter: scale => T.settings.labels.scrollWheelSensitivity.sensitivity[scale.id],
category: categoryApp,
restartRequired: false,
changeCb:
/**
* @param {Application} app
*/
(app, id) => app.updateAfterUiScaleChanged(),
}),
// GAME
new EnumSetting("theme", {
@ -133,6 +165,7 @@ class SettingsStorage {
this.musicMuted = false;
this.theme = "light";
this.refreshRate = "60";
this.scrollWheelSensitivity = "regular";
this.alwaysMultiplace = false;
this.abortPlacementOnDeletion = true;
@ -209,6 +242,17 @@ export class ApplicationSettings extends ReadWriteProxy {
return 1;
}
getScrollWheelSensitivity() {
const id = this.getAllSettings().scrollWheelSensitivity;
for (let i = 0; i < scrollWheelSensitivities.length; ++i) {
if (scrollWheelSensitivities[i].id === id) {
return scrollWheelSensitivities[i].scale;
}
}
logger.error("Unknown scroll wheel sensitivity id:", id);
return 1;
}
getIsFullScreen() {
return this.getAllSettings().fullscreen;
}
@ -295,7 +339,7 @@ export class ApplicationSettings extends ReadWriteProxy {
}
getCurrentVersion() {
return 8;
return 9;
}
/** @param {{settings: SettingsStorage, version: number}} data */
@ -318,10 +362,15 @@ export class ApplicationSettings extends ReadWriteProxy {
}
if (data.version < 8) {
data.settings.abortPlacementOnDeletion = true;
data.settings.scrollWheelSensitivity = "regular";
data.version = 8;
}
if (data.version < 9) {
data.settings.abortPlacementOnDeletion = true;
data.version = 9;
}
return ExplainedResult.good();
}
}

View File

@ -10,8 +10,9 @@ import { BaseSavegameInterface } from "./savegame_interface";
import { createLogger } from "../core/logging";
import { globalConfig } from "../core/config";
import { SavegameInterface_V1000 } from "./schemas/1000";
import { getSavegameInterface } from "./savegame_interface_registry";
import { getSavegameInterface, savegameInterfaces } from "./savegame_interface_registry";
import { SavegameInterface_V1001 } from "./schemas/1001";
import { SavegameInterface_V1002 } from "./schemas/1002";
const logger = createLogger("savegame");
@ -30,6 +31,11 @@ export class Savegame extends ReadWriteProxy {
/** @type {import("./savegame_typedefs").SavegameData} */
this.currentData = this.getDefaultData();
assert(
savegameInterfaces[Savegame.getCurrentVersion()],
"Savegame interface not defined: " + Savegame.getCurrentVersion()
);
}
//////// RW Proxy Impl //////////
@ -38,14 +44,14 @@ export class Savegame extends ReadWriteProxy {
* @returns {number}
*/
static getCurrentVersion() {
return 1001;
return 1002;
}
/**
* @returns {typeof BaseSavegameInterface}
*/
static getReaderClass() {
return SavegameInterface_V1001;
return savegameInterfaces[Savegame.getCurrentVersion()];
}
/**
@ -82,6 +88,11 @@ export class Savegame extends ReadWriteProxy {
data.version = 1001;
}
if (data.version === 1001) {
SavegameInterface_V1002.migrate1001to1002(data);
data.version = 1002;
}
return ExplainedResult.good();
}

View File

@ -2,11 +2,13 @@ import { BaseSavegameInterface } from "./savegame_interface";
import { SavegameInterface_V1000 } from "./schemas/1000";
import { createLogger } from "../core/logging";
import { SavegameInterface_V1001 } from "./schemas/1001";
import { SavegameInterface_V1002 } from "./schemas/1002";
/** @type {Object.<number, typeof BaseSavegameInterface>} */
const interfaces = {
export const savegameInterfaces = {
1000: SavegameInterface_V1000,
1001: SavegameInterface_V1001,
1002: SavegameInterface_V1002,
};
const logger = createLogger("savegame_interface_registry");
@ -27,7 +29,7 @@ export function getSavegameInterface(savegame) {
return null;
}
const interfaceClass = interfaces[version];
const interfaceClass = savegameInterfaces[version];
if (!interfaceClass) {
logger.warn("Version", version, "has no implemented interface!");
return null;

View File

@ -0,0 +1,37 @@
import { createLogger } from "../../core/logging.js";
import { T } from "../../translations.js";
import { SavegameInterface_V1001 } from "./1001.js";
const schema = require("./1002.json");
const logger = createLogger("savegame_interface/1002");
export class SavegameInterface_V1002 extends SavegameInterface_V1001 {
getVersion() {
return 1002;
}
getSchemaUncached() {
return schema;
}
/**
* @param {import("../savegame_typedefs.js").SavegameData} data
*/
static migrate1001to1002(data) {
logger.log("Migrating 1001 to 1002");
const dump = data.dump;
if (!dump) {
return true;
}
const entities = dump.entities;
for (let i = 0; i < entities.length; ++i) {
const entity = entities[i];
const beltComp = entity.components.Belt;
const ejectorComp = entity.components.ItemEjector;
if (beltComp && ejectorComp) {
ejectorComp.instantEject = true;
}
}
}
}

View File

@ -0,0 +1,5 @@
{
"type": "object",
"required": [],
"additionalProperties": true
}

View File

@ -105,6 +105,10 @@ export class KeybindingsState extends TextualGameState {
event.preventDefault();
}
if (event.target && event.target.tagName === "BUTTON" && keyCode === 1) {
return;
}
if (
// Enter
keyCode === 13 ||
@ -122,8 +126,8 @@ export class KeybindingsState extends TextualGameState {
});
dialog.inputReciever.backButton.add(() => {});
this.dialogs.internalShowDialog(dialog);
this.app.sound.playUiSound(SOUNDS.dialogOk);
}

View File

@ -26,6 +26,13 @@ global:
# How big numbers are rendered, e.g. "10,000"
thousandsDivider: ","
# The suffix for large numbers, e.g. 1.3k, 400.2M, etc.
suffix:
thousands: k
millions: M
billions: B
trillions: T
# Shown for infinitely big numbers
infinite: inf
@ -127,7 +134,7 @@ dialogs:
editKeybinding:
title: Change Keybinding
desc: Press the key you want to assign, or escape to cancel.
desc: Press the key or mouse button you want to assign, or escape to cancel.
resetKeybindingsConfirmation:
title: Reset keybindings
@ -511,6 +518,23 @@ settings:
title: Interface scale
description: >-
Changes the size of the user interface. The interface will still scale based on your device resolution, but this setting controls the amount of scale.
scales:
super_small: Super small
small: Small
regular: Regular
large: Large
huge: Huge
scrollWheelSensitivity:
title: Zoom sensitivity
description: >-
Changes how sensitive the zoom is (Either mouse wheel or trackpad).
sensitivity:
super_slow: Super slow
slow: Slow
regular: Regular
fast: Fast
super_fast: Super fast
fullscreen:
title: Fullscreen

View File

@ -1 +1 @@
1.1.2
1.1.3