Initial support for translations
This commit is contained in:
parent
13c6fc7598
commit
a70a937302
|
@ -67,6 +67,9 @@ docs.gulptasksDocs($, gulp, buildFolder);
|
||||||
const standalone = require("./standalone");
|
const standalone = require("./standalone");
|
||||||
standalone.gulptasksStandalone($, gulp, buildFolder);
|
standalone.gulptasksStandalone($, gulp, buildFolder);
|
||||||
|
|
||||||
|
const translations = require("./translations");
|
||||||
|
translations.gulptasksTranslations($, gulp, buildFolder);
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
// const cordova = require("./cordova");
|
// const cordova = require("./cordova");
|
||||||
// cordova.gulptasksCordova($, gulp, buildFolder);
|
// cordova.gulptasksCordova($, gulp, buildFolder);
|
||||||
|
@ -74,10 +77,12 @@ standalone.gulptasksStandalone($, gulp, buildFolder);
|
||||||
///////////////////// BUILD TASKS /////////////////////
|
///////////////////// BUILD TASKS /////////////////////
|
||||||
|
|
||||||
// Cleans up everything
|
// Cleans up everything
|
||||||
gulp.task("utils.cleanup", () => {
|
gulp.task("utils.cleanBuildFolder", () => {
|
||||||
return gulp.src(buildFolder, { read: false }).pipe($.clean({ force: true }));
|
return gulp.src(buildFolder, { read: false }).pipe($.clean({ force: true }));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task("utils.cleanup", $.sequence("utils.cleanBuildFolder", "translations.clear"));
|
||||||
|
|
||||||
// Requires no uncomitted files
|
// Requires no uncomitted files
|
||||||
gulp.task("utils.requireCleanWorkingTree", cb => {
|
gulp.task("utils.requireCleanWorkingTree", cb => {
|
||||||
const output = $.trim(execSync("git status -su").toString("ascii"));
|
const output = $.trim(execSync("git status -su").toString("ascii"));
|
||||||
|
@ -142,6 +147,9 @@ function serve({ standalone }) {
|
||||||
// Watch sound files
|
// Watch sound files
|
||||||
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], ["sounds.dev"]);
|
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], ["sounds.dev"]);
|
||||||
|
|
||||||
|
// Watch translations
|
||||||
|
gulp.watch("../translations/**/*.yaml", ["translations.convertToJson"]);
|
||||||
|
|
||||||
gulp.watch(
|
gulp.watch(
|
||||||
["../res_raw/sounds/ui/*.mp3", "../res_raw/sounds/ui/*.wav"],
|
["../res_raw/sounds/ui/*.mp3", "../res_raw/sounds/ui/*.wav"],
|
||||||
$.sequence("sounds.encodeUi", "sounds.copy")
|
$.sequence("sounds.encodeUi", "sounds.copy")
|
||||||
|
@ -163,11 +171,15 @@ function serve({ standalone }) {
|
||||||
gulp.watch("../res_built/atlas/*.json", ["imgres.atlas"]);
|
gulp.watch("../res_built/atlas/*.json", ["imgres.atlas"]);
|
||||||
|
|
||||||
// Watch the build folder and reload when anything changed
|
// Watch the build folder and reload when anything changed
|
||||||
const extensions = ["html", "js", "png", "jpg", "svg", "mp3", "ico", "woff2"];
|
const extensions = ["html", "js", "png", "jpg", "svg", "mp3", "ico", "woff2", "json"];
|
||||||
gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", function (e) {
|
gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", function (e) {
|
||||||
return gulp.src(e.path).pipe(browserSync.reload({ stream: true }));
|
return gulp.src(e.path).pipe(browserSync.reload({ stream: true }));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.watch("../src/js/translations-built/*.json").on("change", function (e) {
|
||||||
|
return gulp.src(e.path).pipe(browserSync.reload({ stream: true }));
|
||||||
|
});
|
||||||
|
|
||||||
// Start the webpack watching server (Will never return)
|
// Start the webpack watching server (Will never return)
|
||||||
if (standalone) {
|
if (standalone) {
|
||||||
$.sequence("js.standalone-dev.watch")(() => true);
|
$.sequence("js.standalone-dev.watch")(() => true);
|
||||||
|
@ -202,7 +214,7 @@ gulp.task("build.dev", cb => {
|
||||||
"sounds.dev",
|
"sounds.dev",
|
||||||
"imgres.copyImageResources",
|
"imgres.copyImageResources",
|
||||||
"imgres.copyNonImageResources",
|
"imgres.copyNonImageResources",
|
||||||
"js.dev",
|
"translations.fullBuild",
|
||||||
"css.dev",
|
"css.dev",
|
||||||
"html.dev"
|
"html.dev"
|
||||||
)(cb);
|
)(cb);
|
||||||
|
@ -216,6 +228,7 @@ gulp.task("build.standalone.dev", cb => {
|
||||||
"sounds.dev",
|
"sounds.dev",
|
||||||
"imgres.copyImageResources",
|
"imgres.copyImageResources",
|
||||||
"imgres.copyNonImageResources",
|
"imgres.copyNonImageResources",
|
||||||
|
"translations.fullBuild",
|
||||||
"js.standalone-dev",
|
"js.standalone-dev",
|
||||||
"css.dev",
|
"css.dev",
|
||||||
"html.standalone-dev"
|
"html.standalone-dev"
|
||||||
|
@ -223,7 +236,7 @@ gulp.task("build.standalone.dev", cb => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Builds everything (staging)
|
// Builds everything (staging)
|
||||||
gulp.task("step.staging.code", $.sequence("js.staging"));
|
gulp.task("step.staging.code", $.sequence("translations.fullBuild", "js.staging"));
|
||||||
gulp.task("step.staging.mainbuild", cb =>
|
gulp.task("step.staging.mainbuild", cb =>
|
||||||
$.multiProcess(["utils.copyAdditionalBuildFiles", "step.baseResources", "step.staging.code"], cb, false)
|
$.multiProcess(["utils.copyAdditionalBuildFiles", "step.baseResources", "step.staging.code"], cb, false)
|
||||||
);
|
);
|
||||||
|
@ -231,7 +244,7 @@ gulp.task("step.staging.all", $.sequence("step.staging.mainbuild", "css.prod", "
|
||||||
gulp.task("build.staging", $.sequence("utils.cleanup", "step.staging.all", "step.postbuild"));
|
gulp.task("build.staging", $.sequence("utils.cleanup", "step.staging.all", "step.postbuild"));
|
||||||
|
|
||||||
// Builds everything (prod)
|
// Builds everything (prod)
|
||||||
gulp.task("step.prod.code", $.sequence("js.prod"));
|
gulp.task("step.prod.code", $.sequence("translations.fullBuild", "js.prod"));
|
||||||
gulp.task("step.prod.mainbuild", cb =>
|
gulp.task("step.prod.mainbuild", cb =>
|
||||||
$.multiProcess(["utils.copyAdditionalBuildFiles", "step.baseResources", "step.prod.code"], cb, false)
|
$.multiProcess(["utils.copyAdditionalBuildFiles", "step.baseResources", "step.prod.code"], cb, false)
|
||||||
);
|
);
|
||||||
|
@ -239,7 +252,7 @@ gulp.task("step.prod.all", $.sequence("step.prod.mainbuild", "css.prod", "html.p
|
||||||
gulp.task("build.prod", $.sequence("utils.cleanup", "step.prod.all", "step.postbuild"));
|
gulp.task("build.prod", $.sequence("utils.cleanup", "step.prod.all", "step.postbuild"));
|
||||||
|
|
||||||
// Builds everything (standalone-beta)
|
// Builds everything (standalone-beta)
|
||||||
gulp.task("step.standalone-beta.code", $.sequence("js.standalone-beta"));
|
gulp.task("step.standalone-beta.code", $.sequence("translations.fullBuild", "js.standalone-beta"));
|
||||||
gulp.task("step.standalone-beta.mainbuild", cb =>
|
gulp.task("step.standalone-beta.mainbuild", cb =>
|
||||||
$.multiProcess(
|
$.multiProcess(
|
||||||
["utils.copyAdditionalBuildFiles", "step.baseResources", "step.standalone-beta.code"],
|
["utils.copyAdditionalBuildFiles", "step.baseResources", "step.standalone-beta.code"],
|
||||||
|
@ -254,7 +267,7 @@ gulp.task(
|
||||||
gulp.task("build.standalone-beta", $.sequence("utils.cleanup", "step.standalone-beta.all", "step.postbuild"));
|
gulp.task("build.standalone-beta", $.sequence("utils.cleanup", "step.standalone-beta.all", "step.postbuild"));
|
||||||
|
|
||||||
// Builds everything (standalone-prod)
|
// Builds everything (standalone-prod)
|
||||||
gulp.task("step.standalone-prod.code", $.sequence("js.standalone-prod"));
|
gulp.task("step.standalone-prod.code", $.sequence("translations.fullBuild", "js.standalone-prod"));
|
||||||
gulp.task("step.standalone-prod.mainbuild", cb =>
|
gulp.task("step.standalone-prod.mainbuild", cb =>
|
||||||
$.multiProcess(
|
$.multiProcess(
|
||||||
["utils.copyAdditionalBuildFiles", "step.baseResources", "step.standalone-prod.code"],
|
["utils.copyAdditionalBuildFiles", "step.baseResources", "step.standalone-prod.code"],
|
||||||
|
|
|
@ -97,6 +97,7 @@
|
||||||
"gulp-sftp": "^0.1.5",
|
"gulp-sftp": "^0.1.5",
|
||||||
"gulp-terser": "^1.2.0",
|
"gulp-terser": "^1.2.0",
|
||||||
"gulp-webserver": "^0.9.1",
|
"gulp-webserver": "^0.9.1",
|
||||||
|
"gulp-yaml": "^2.0.4",
|
||||||
"imagemin-mozjpeg": "^8.0.0",
|
"imagemin-mozjpeg": "^8.0.0",
|
||||||
"imagemin-pngquant": "^8.0.0",
|
"imagemin-pngquant": "^8.0.0",
|
||||||
"jimp": "^0.6.1",
|
"jimp": "^0.6.1",
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const yaml = require("gulp-yaml");
|
||||||
|
|
||||||
|
const translationsSourceDir = path.join(__dirname, "..", "translations");
|
||||||
|
const translationsJsonDir = path.join(__dirname, "..", "src", "js", "translations-built");
|
||||||
|
|
||||||
|
function gulptasksTranslations($, gulp, buildFolder) {
|
||||||
|
gulp.task("translations.clear", () => {
|
||||||
|
return gulp.src(translationsJsonDir, { read: false }).pipe($.clean({ force: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("translations.convertToJson", () => {
|
||||||
|
return gulp
|
||||||
|
.src(path.join(translationsSourceDir, "*.yaml"))
|
||||||
|
.pipe($.plumber())
|
||||||
|
.pipe(yaml({ space: 2, safe: true }))
|
||||||
|
.pipe(gulp.dest(translationsJsonDir));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("translations.fullBuild", $.sequence("translations.convertToJson"));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
gulptasksTranslations,
|
||||||
|
};
|
|
@ -2477,6 +2477,13 @@ buffer@^5.2.0, buffer@^5.2.1:
|
||||||
base64-js "^1.0.2"
|
base64-js "^1.0.2"
|
||||||
ieee754 "^1.1.4"
|
ieee754 "^1.1.4"
|
||||||
|
|
||||||
|
bufferstreams@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/bufferstreams/-/bufferstreams-2.0.1.tgz#441b267c2fc3fee02bb1d929289da113903bd5ef"
|
||||||
|
integrity sha512-ZswyIoBfFb3cVDsnZLLj2IDJ/0ppYdil/v2EGlZXvoefO689FokEmFEldhN5dV7R2QBxFneqTJOMIpfqhj+n0g==
|
||||||
|
dependencies:
|
||||||
|
readable-stream "^2.3.6"
|
||||||
|
|
||||||
builtin-status-codes@^3.0.0:
|
builtin-status-codes@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||||
|
@ -6452,6 +6459,18 @@ gulp-webserver@^0.9.1:
|
||||||
tiny-lr "0.1.4"
|
tiny-lr "0.1.4"
|
||||||
watch "^0.11.0"
|
watch "^0.11.0"
|
||||||
|
|
||||||
|
gulp-yaml@^2.0.4:
|
||||||
|
version "2.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/gulp-yaml/-/gulp-yaml-2.0.4.tgz#86569e2becc9f5dfc95dc92db5a71a237f4b6ab4"
|
||||||
|
integrity sha512-S/9Ib8PO+jGkCvWDwBUkmFkeW7QM0pp4PO8NNrMEfWo5Sk30P+KqpyXc4055L/vOX326T/b9MhM4nw5EenyX9g==
|
||||||
|
dependencies:
|
||||||
|
bufferstreams "^2.0.1"
|
||||||
|
js-yaml "^3.13.1"
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
plugin-error "^1.0.1"
|
||||||
|
replace-ext "^1.0.0"
|
||||||
|
through2 "^3.0.0"
|
||||||
|
|
||||||
gulp@^3.9.1:
|
gulp@^3.9.1:
|
||||||
version "3.9.1"
|
version "3.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4"
|
resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4"
|
||||||
|
@ -12889,7 +12908,7 @@ through2@2.0.3:
|
||||||
readable-stream "^2.1.5"
|
readable-stream "^2.1.5"
|
||||||
xtend "~4.0.1"
|
xtend "~4.0.1"
|
||||||
|
|
||||||
through2@3.0.1, through2@^3.0.1:
|
through2@3.0.1, through2@^3.0.0, through2@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a"
|
resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a"
|
||||||
integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==
|
integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==
|
||||||
|
|
|
@ -39,6 +39,13 @@
|
||||||
.hotkey {
|
.hotkey {
|
||||||
color: lighten($colorGreenBright, 10);
|
color: lighten($colorGreenBright, 10);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
.keybinding {
|
||||||
|
position: relative;
|
||||||
|
@include S(margin-left, 5px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.buildingImage {
|
.buildingImage {
|
||||||
|
|
|
@ -66,17 +66,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.keybinding.shift {
|
.keybinding.builtinKey {
|
||||||
transition: all 0.1s ease-in-out;
|
transition: all 0.1s ease-in-out;
|
||||||
transition-property: background-color, color, border-color;
|
transition-property: background-color, color, border-color;
|
||||||
background: $colorRedBright;
|
background: $colorRedBright;
|
||||||
border-color: $colorRedBright;
|
border-color: $colorRedBright;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.shiftDown .keybinding.shift {
|
|
||||||
border-color: darken($colorRedBright, 40);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body.uiHidden #ingame_HUD_KeybindingOverlay .binding:not(.hudToggle) {
|
body.uiHidden #ingame_HUD_KeybindingOverlay .binding:not(.hudToggle) {
|
||||||
|
|
|
@ -251,9 +251,9 @@
|
||||||
|
|
||||||
@include S(padding, 15px);
|
@include S(padding, 15px);
|
||||||
> a {
|
> a {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
|
@ -280,8 +280,8 @@
|
||||||
|
|
||||||
.thirdpartyLogo {
|
.thirdpartyLogo {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 80%;
|
@include S(width, 50px);
|
||||||
height: 80%;
|
@include S(height, 50px);
|
||||||
background: center center / 80% no-repeat;
|
background: center center / 80% no-repeat;
|
||||||
&.githubLogo {
|
&.githubLogo {
|
||||||
background-image: uiResource("main_menu/github.png");
|
background-image: uiResource("main_menu/github.png");
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
translations-built
|
|
@ -76,7 +76,7 @@ export const globalConfig = {
|
||||||
|
|
||||||
debug: {
|
debug: {
|
||||||
/* dev:start */
|
/* dev:start */
|
||||||
// fastGameEnter: true,
|
fastGameEnter: true,
|
||||||
noArtificialDelays: true,
|
noArtificialDelays: true,
|
||||||
// disableSavegameWrite: true,
|
// disableSavegameWrite: true,
|
||||||
showEntityBounds: false,
|
showEntityBounds: false,
|
||||||
|
@ -90,6 +90,7 @@ export const globalConfig = {
|
||||||
allBuildingsUnlocked: true,
|
allBuildingsUnlocked: true,
|
||||||
upgradesNoCost: true,
|
upgradesNoCost: true,
|
||||||
disableUnlockDialog: false,
|
disableUnlockDialog: false,
|
||||||
|
testTranslations: true,
|
||||||
/* dev:end */
|
/* dev:end */
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { FormElement } from "./modal_dialog_forms";
|
||||||
import { globalConfig } from "./config";
|
import { globalConfig } from "./config";
|
||||||
import { getStringForKeyCode } from "../game/key_action_mapper";
|
import { getStringForKeyCode } from "../game/key_action_mapper";
|
||||||
import { createLogger } from "./logging";
|
import { createLogger } from "./logging";
|
||||||
|
import { T } from "../translations";
|
||||||
|
|
||||||
const kbEnter = 13;
|
const kbEnter = 13;
|
||||||
const kbCancel = 27;
|
const kbCancel = 27;
|
||||||
|
@ -146,8 +147,7 @@ export class Dialog {
|
||||||
button.classList.add("button");
|
button.classList.add("button");
|
||||||
button.classList.add("styledButton");
|
button.classList.add("styledButton");
|
||||||
button.classList.add(buttonStyle);
|
button.classList.add(buttonStyle);
|
||||||
// button.innerText = T.dialog_buttons[buttonId];
|
button.innerText = T.dialogs.buttons[buttonId];
|
||||||
button.innerText = buttonId;
|
|
||||||
|
|
||||||
const params = (rawParams || "").split("/");
|
const params = (rawParams || "").split("/");
|
||||||
const useTimeout = params.indexOf("timeout") >= 0;
|
const useTimeout = params.indexOf("timeout") >= 0;
|
||||||
|
@ -277,7 +277,7 @@ export class DialogLoading extends Dialog {
|
||||||
const loader = document.createElement("div");
|
const loader = document.createElement("div");
|
||||||
loader.classList.add("prefab_LoadingTextWithAnim");
|
loader.classList.add("prefab_LoadingTextWithAnim");
|
||||||
loader.classList.add("loadingIndicator");
|
loader.classList.add("loadingIndicator");
|
||||||
loader.innerText = "Loading";
|
loader.innerText = T.global.loading;
|
||||||
elem.appendChild(loader);
|
elem.appendChild(loader);
|
||||||
|
|
||||||
this.app.inputMgr.pushReciever(this.inputReciever);
|
this.app.inputMgr.pushReciever(this.inputReciever);
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
performanceNow,
|
performanceNow,
|
||||||
} from "./builtins";
|
} from "./builtins";
|
||||||
import { Vector } from "./vector";
|
import { Vector } from "./vector";
|
||||||
|
import { T } from "../translations";
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
export const TOP = new Vector(0, -1);
|
export const TOP = new Vector(0, -1);
|
||||||
|
@ -421,7 +422,7 @@ export function formatBigNumber(num, divider = ".") {
|
||||||
num = Math_abs(num);
|
num = Math_abs(num);
|
||||||
|
|
||||||
if (num > 1e54) {
|
if (num > 1e54) {
|
||||||
return sign + "inf";
|
return sign + T.global.infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num < 10 && !Number.isInteger(num)) {
|
if (num < 10 && !Number.isInteger(num)) {
|
||||||
|
@ -459,7 +460,7 @@ export function formatBigNumberFull(num, divider = ",") {
|
||||||
return num + "";
|
return num + "";
|
||||||
}
|
}
|
||||||
if (num > 1e54) {
|
if (num > 1e54) {
|
||||||
return "infinite";
|
return T.global.infinite;
|
||||||
}
|
}
|
||||||
let rest = num;
|
let rest = num;
|
||||||
let out = "";
|
let out = "";
|
||||||
|
@ -831,24 +832,47 @@ export function formatSecondsToTimeAgo(secs) {
|
||||||
|
|
||||||
if (seconds <= 60) {
|
if (seconds <= 60) {
|
||||||
if (seconds <= 1) {
|
if (seconds <= 1) {
|
||||||
return "one second ago";
|
return T.global.time.oneSecondAgo;
|
||||||
}
|
}
|
||||||
return seconds + " seconds ago";
|
return T.global.time.xSecondsAgo.replace("<x>", "" + seconds);
|
||||||
} else if (minutes <= 60) {
|
} else if (minutes <= 60) {
|
||||||
if (minutes <= 1) {
|
if (minutes <= 1) {
|
||||||
return "one minute ago";
|
return T.global.time.oneMinuteAgo;
|
||||||
}
|
}
|
||||||
return minutes + " minutes ago";
|
return T.global.time.xMinutesAgo.replace("<x>", "" + minutes);
|
||||||
} else if (hours <= 60) {
|
} else if (hours <= 60) {
|
||||||
if (hours <= 1) {
|
if (hours <= 1) {
|
||||||
return "one hour ago";
|
return T.global.time.oneHourAgo;
|
||||||
}
|
}
|
||||||
return hours + " hours ago";
|
return T.global.time.xHoursAgo.replace("<x>", "" + hours);
|
||||||
} else {
|
} else {
|
||||||
if (days <= 1) {
|
if (days <= 1) {
|
||||||
return "one day ago";
|
return T.global.time.oneDayAgo;
|
||||||
}
|
}
|
||||||
return days + " days ago";
|
return T.global.time.xDaysAgo.replace("<x>", "" + days);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats seconds into a readable string like "5h 23m"
|
||||||
|
* @param {number} secs Seconds
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function formatSeconds(secs) {
|
||||||
|
const trans = T.global.time;
|
||||||
|
secs = Math_ceil(secs);
|
||||||
|
if (secs < 60) {
|
||||||
|
return trans.secondsShort.replace("<seconds>", "" + secs);
|
||||||
|
} else if (secs < 60 * 60) {
|
||||||
|
const minutes = Math_floor(secs / 60);
|
||||||
|
const seconds = secs % 60;
|
||||||
|
return trans.minutesAndSecondsShort
|
||||||
|
.replace("<seconds>", "" + seconds)
|
||||||
|
.replace("<minutes>", "" + minutes);
|
||||||
|
} else {
|
||||||
|
const hours = Math_floor(secs / 3600);
|
||||||
|
const minutes = Math_floor(secs / 60) % 60;
|
||||||
|
return trans.hoursAndMinutesShort.replace("<minutes>", "" + minutes).replace("<hours>", "" + hours);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,3 +892,11 @@ export function generateFileDownload(filename, text) {
|
||||||
element.click();
|
element.click();
|
||||||
document.body.removeChild(element);
|
document.body.removeChild(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capitalizes the first letter
|
||||||
|
* @param {string} str
|
||||||
|
*/
|
||||||
|
export function capitalizeFirstLetter(str) {
|
||||||
|
return str.substr(0, 1).toUpperCase() + str.substr(1).toLowerCase();
|
||||||
|
}
|
||||||
|
|
|
@ -20,14 +20,6 @@ export class MetaBeltBaseBuilding extends MetaBuilding {
|
||||||
return "#777";
|
return "#777";
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Belt";
|
|
||||||
}
|
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Transports items, hold and drag to place multiple.";
|
|
||||||
}
|
|
||||||
|
|
||||||
getPreviewSprite(rotationVariant) {
|
getPreviewSprite(rotationVariant) {
|
||||||
switch (arrayBeltVariantToRotation[rotationVariant]) {
|
switch (arrayBeltVariantToRotation[rotationVariant]) {
|
||||||
case enumDirection.top: {
|
case enumDirection.top: {
|
||||||
|
|
|
@ -30,14 +30,6 @@ export class MetaCutterBuilding extends MetaBuilding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Cut Half";
|
|
||||||
}
|
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "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>";
|
|
||||||
}
|
|
||||||
|
|
||||||
getAvailableVariants(root) {
|
getAvailableVariants(root) {
|
||||||
return [defaultBuildingVariant, enumCutterVariants.quad];
|
return [defaultBuildingVariant, enumCutterVariants.quad];
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,6 @@ export class MetaHubBuilding extends MetaBuilding {
|
||||||
return "#eb5555";
|
return "#eb5555";
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Hub";
|
|
||||||
}
|
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Your central hub, deliver shapes to it to unlock new buildings.";
|
|
||||||
}
|
|
||||||
|
|
||||||
isRotateable() {
|
isRotateable() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,18 +13,10 @@ export class MetaMinerBuilding extends MetaBuilding {
|
||||||
super("miner");
|
super("miner");
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Extract";
|
|
||||||
}
|
|
||||||
|
|
||||||
getSilhouetteColor() {
|
getSilhouetteColor() {
|
||||||
return "#b37dcd";
|
return "#b37dcd";
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Place over a shape or color to extract it. Six extractors fill exactly one belt.";
|
|
||||||
}
|
|
||||||
|
|
||||||
getAvailableVariants(root) {
|
getAvailableVariants(root) {
|
||||||
return [defaultBuildingVariant, enumMinerVariants.chainable];
|
return [defaultBuildingVariant, enumMinerVariants.chainable];
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,6 @@ export class MetaMixerBuilding extends MetaBuilding {
|
||||||
return new Vector(2, 1);
|
return new Vector(2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Mix Colors";
|
|
||||||
}
|
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Mixes two colors using additive blending.";
|
|
||||||
}
|
|
||||||
|
|
||||||
getSilhouetteColor() {
|
getSilhouetteColor() {
|
||||||
return "#cdbb7d";
|
return "#cdbb7d";
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,14 +29,6 @@ export class MetaPainterBuilding extends MetaBuilding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Dye";
|
|
||||||
}
|
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Colors the whole shape on the left input with the color from the right input.";
|
|
||||||
}
|
|
||||||
|
|
||||||
getSilhouetteColor() {
|
getSilhouetteColor() {
|
||||||
return "#cd9b7d";
|
return "#cd9b7d";
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,6 @@ export class MetaRotaterBuilding extends MetaBuilding {
|
||||||
super("rotater");
|
super("rotater");
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Rotate";
|
|
||||||
}
|
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Rotates shapes clockwise by 90 degrees.";
|
|
||||||
}
|
|
||||||
|
|
||||||
getSilhouetteColor() {
|
getSilhouetteColor() {
|
||||||
return "#7dc6cd";
|
return "#7dc6cd";
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,18 +27,10 @@ export class MetaSplitterBuilding extends MetaBuilding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Balancer";
|
|
||||||
}
|
|
||||||
|
|
||||||
getSilhouetteColor() {
|
getSilhouetteColor() {
|
||||||
return "#444";
|
return "#444";
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Multifunctional - Evenly distributes all inputs onto all outputs.";
|
|
||||||
}
|
|
||||||
|
|
||||||
getAvailableVariants(root) {
|
getAvailableVariants(root) {
|
||||||
return [defaultBuildingVariant, enumSplitterVariants.compact];
|
return [defaultBuildingVariant, enumSplitterVariants.compact];
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,18 +13,10 @@ export class MetaStackerBuilding extends MetaBuilding {
|
||||||
super("stacker");
|
super("stacker");
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Combine";
|
|
||||||
}
|
|
||||||
|
|
||||||
getSilhouetteColor() {
|
getSilhouetteColor() {
|
||||||
return "#9fcd7d";
|
return "#9fcd7d";
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Combines both items. If they can not be merged, the right item is placed above the left item.";
|
|
||||||
}
|
|
||||||
|
|
||||||
getDimensions() {
|
getDimensions() {
|
||||||
return new Vector(2, 1);
|
return new Vector(2, 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,14 +12,6 @@ export class MetaTrashBuilding extends MetaBuilding {
|
||||||
super("trash");
|
super("trash");
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Destroyer";
|
|
||||||
}
|
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Accepts inputs from all sides and destroys them. Forever.";
|
|
||||||
}
|
|
||||||
|
|
||||||
isRotateable() {
|
isRotateable() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,18 +28,10 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding {
|
||||||
super("underground_belt");
|
super("underground_belt");
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
|
||||||
return "Tunnel";
|
|
||||||
}
|
|
||||||
|
|
||||||
getSilhouetteColor() {
|
getSilhouetteColor() {
|
||||||
return "#555";
|
return "#555";
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescription() {
|
|
||||||
return "Allows to tunnel resources under buildings and belts.";
|
|
||||||
}
|
|
||||||
|
|
||||||
getFlipOrientationAfterPlacement() {
|
getFlipOrientationAfterPlacement() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* typehints:start */
|
/* typehints:start */
|
||||||
import { Application } from "../application";
|
import { Application } from "../application";
|
||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
import { T } from "../translations";
|
||||||
|
|
||||||
export class GameLoadingOverlay {
|
export class GameLoadingOverlay {
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +52,7 @@ export class GameLoadingOverlay {
|
||||||
internalAddSpinnerAndText(element) {
|
internalAddSpinnerAndText(element) {
|
||||||
const inner = document.createElement("span");
|
const inner = document.createElement("span");
|
||||||
inner.classList.add("prefab_LoadingTextWithAnim");
|
inner.classList.add("prefab_LoadingTextWithAnim");
|
||||||
inner.innerText = "Loading";
|
inner.innerText = T.global.loading;
|
||||||
element.appendChild(inner);
|
element.appendChild(inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,24 @@
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { Math_abs, Math_degrees, Math_radians } from "../../../core/builtins";
|
||||||
import { MetaBuilding, defaultBuildingVariant } from "../../meta_building";
|
|
||||||
import { DrawParameters } from "../../../core/draw_parameters";
|
|
||||||
import { globalConfig } from "../../../core/config";
|
import { globalConfig } from "../../../core/config";
|
||||||
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
import { DrawParameters } from "../../../core/draw_parameters";
|
||||||
import { STOP_PROPAGATION, Signal } from "../../../core/signal";
|
|
||||||
import {
|
|
||||||
Vector,
|
|
||||||
enumDirectionToAngle,
|
|
||||||
enumInvertedDirections,
|
|
||||||
enumDirectionToVector,
|
|
||||||
} from "../../../core/vector";
|
|
||||||
import { pulseAnimation, makeDiv, removeAllChildren } from "../../../core/utils";
|
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
|
||||||
import { TrackedState } from "../../../core/tracked_state";
|
|
||||||
import { Math_abs, Math_radians, Math_degrees } from "../../../core/builtins";
|
|
||||||
import { Loader } from "../../../core/loader";
|
|
||||||
import { drawRotatedSprite } from "../../../core/draw_utils";
|
import { drawRotatedSprite } from "../../../core/draw_utils";
|
||||||
import { Entity } from "../../entity";
|
import { Loader } from "../../../core/loader";
|
||||||
|
import { STOP_PROPAGATION } from "../../../core/signal";
|
||||||
|
import { TrackedState } from "../../../core/tracked_state";
|
||||||
|
import { makeDiv, removeAllChildren } from "../../../core/utils";
|
||||||
|
import {
|
||||||
|
enumDirectionToAngle,
|
||||||
|
enumDirectionToVector,
|
||||||
|
enumInvertedDirections,
|
||||||
|
Vector,
|
||||||
|
} from "../../../core/vector";
|
||||||
import { enumMouseButton } from "../../camera";
|
import { enumMouseButton } from "../../camera";
|
||||||
|
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||||
|
import { Entity } from "../../entity";
|
||||||
|
import { defaultBuildingVariant, MetaBuilding } from "../../meta_building";
|
||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
|
||||||
export class HUDBuildingPlacer extends BaseHUDPart {
|
export class HUDBuildingPlacer extends BaseHUDPart {
|
||||||
initialize() {
|
initialize() {
|
||||||
|
@ -231,13 +232,16 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||||
this.abortDragging();
|
this.abortDragging();
|
||||||
this.root.hud.signals.selectedPlacementBuildingChanged.dispatch(metaBuilding);
|
this.root.hud.signals.selectedPlacementBuildingChanged.dispatch(metaBuilding);
|
||||||
if (metaBuilding) {
|
if (metaBuilding) {
|
||||||
this.buildingInfoElements.label.innerHTML = metaBuilding.getName();
|
this.buildingInfoElements.label.innerHTML = T.buildings[metaBuilding.id].name;
|
||||||
this.buildingInfoElements.descText.innerHTML = metaBuilding.getDescription();
|
this.buildingInfoElements.descText.innerHTML = T.buildings[metaBuilding.id].description;
|
||||||
|
|
||||||
const binding = this.root.gameState.keyActionMapper.getBinding(
|
const binding = this.root.gameState.keyActionMapper.getBinding(
|
||||||
"building_" + metaBuilding.getId()
|
"building_" + metaBuilding.getId()
|
||||||
);
|
);
|
||||||
this.buildingInfoElements.hotkey.innerHTML = "Hotkey: " + binding.getKeyCodeString();
|
this.buildingInfoElements.hotkey.innerHTML = T.ingame.buildingPlacement.hotkeyLabel.replace(
|
||||||
|
"<key>",
|
||||||
|
"<code class='keybinding'>" + binding.getKeyCodeString() + "</code>"
|
||||||
|
);
|
||||||
|
|
||||||
const variant = this.preferredVariants[metaBuilding.getId()] || defaultBuildingVariant;
|
const variant = this.preferredVariants[metaBuilding.getId()] || defaultBuildingVariant;
|
||||||
this.currentVariant.set(variant);
|
this.currentVariant.set(variant);
|
||||||
|
@ -283,11 +287,12 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
||||||
this.variantsElement,
|
this.variantsElement,
|
||||||
null,
|
null,
|
||||||
["explanation"],
|
["explanation"],
|
||||||
`
|
T.ingame.buildingPlacement.cycleBuildingVariants.replace(
|
||||||
Press <code class='keybinding'>${this.root.gameState.keyActionMapper
|
"<key>",
|
||||||
.getBinding("cycle_variants")
|
"<code class='keybinding'>" +
|
||||||
.getKeyCodeString()}</code> to cycle variants.
|
this.root.gameState.keyActionMapper.getBinding("cycle_variants").getKeyCodeString() +
|
||||||
`
|
"</code>"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let i = 0; i < availableVariants.length; ++i) {
|
for (let i = 0; i < availableVariants.length; ++i) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { makeDiv, randomInt } from "../../../core/utils";
|
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";
|
||||||
|
|
||||||
export class HUDGameMenu extends BaseHUDPart {
|
export class HUDGameMenu extends BaseHUDPart {
|
||||||
initialize() {}
|
initialize() {}
|
||||||
|
@ -16,7 +17,7 @@ export class HUDGameMenu extends BaseHUDPart {
|
||||||
keybinding: "menu_open_shop",
|
keybinding: "menu_open_shop",
|
||||||
badge: () => this.root.hubGoals.getAvailableUpgradeCount(),
|
badge: () => this.root.hubGoals.getAvailableUpgradeCount(),
|
||||||
notification: /** @type {[string, enumNotificationType]} */ ([
|
notification: /** @type {[string, enumNotificationType]} */ ([
|
||||||
"A new upgrade is available!",
|
T.ingame.notifications.newUpgrade,
|
||||||
enumNotificationType.upgrade,
|
enumNotificationType.upgrade,
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { makeDiv } from "../../../core/utils";
|
||||||
import { getStringForKeyCode } from "../../key_action_mapper";
|
import { getStringForKeyCode } 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";
|
||||||
|
|
||||||
export class HUDKeybindingOverlay extends BaseHUDPart {
|
export class HUDKeybindingOverlay extends BaseHUDPart {
|
||||||
initialize() {
|
initialize() {
|
||||||
|
@ -32,7 +33,7 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
|
||||||
`
|
`
|
||||||
<div class="binding">
|
<div class="binding">
|
||||||
<code class="keybinding">${getKeycode("center_map")}</code>
|
<code class="keybinding">${getKeycode("center_map")}</code>
|
||||||
<label>Center</label>
|
<label>${T.ingame.keybindingsOverlay.centerMap}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="binding">
|
<div class="binding">
|
||||||
|
@ -41,48 +42,48 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
|
||||||
<code class="keybinding">${getKeycode("map_move_left")}</code>
|
<code class="keybinding">${getKeycode("map_move_left")}</code>
|
||||||
<code class="keybinding">${getKeycode("map_move_down")}</code>
|
<code class="keybinding">${getKeycode("map_move_down")}</code>
|
||||||
<code class="keybinding">${getKeycode("map_move_right")}</code>
|
<code class="keybinding">${getKeycode("map_move_right")}</code>
|
||||||
<label>Move</label>
|
<label>${T.ingame.keybindingsOverlay.moveMap}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="binding noPlacementOnly">
|
<div class="binding noPlacementOnly">
|
||||||
<code class="keybinding rightMouse"></code><i></i>
|
<code class="keybinding rightMouse"></code><i></i>
|
||||||
<code class="keybinding shift">CTRL</code>+
|
<code class="keybinding builtinKey">${T.global.keys.control}</code>+
|
||||||
<code class="keybinding leftMouse"></code>
|
<code class="keybinding leftMouse"></code>
|
||||||
<label>Delete</label>
|
<label>${T.ingame.keybindingsOverlay.removeBuildings}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<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("building_abort_placement")}</code>
|
||||||
<label>Stop placement</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("rotate_while_placing")}</code>
|
||||||
<label>Rotate Building</label>
|
<label>${T.ingame.keybindingsOverlay.rotateBuilding}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="binding placementOnly">
|
<div class="binding placementOnly">
|
||||||
<code class="keybinding shift">⇧ SHIFT</code>
|
<code class="keybinding builtinKey shift">⇧ ${T.global.keys.shift}</code>
|
||||||
<label>Place Multiple</label>
|
<label>${T.ingame.keybindingsOverlay.placeMultiple}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="binding placementOnly">
|
<div class="binding placementOnly">
|
||||||
<code class="keybinding shift">ALT</code>
|
<code class="keybinding builtinKey">${T.global.keys.alt}</code>
|
||||||
<label>Reverse orientation</label>
|
<label>${T.ingame.keybindingsOverlay.reverseOrientation}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="binding placementOnly">
|
<div class="binding placementOnly">
|
||||||
<code class="keybinding shift">CTRL</code>
|
<code class="keybinding builtinKey">${T.global.keys.control}</code>
|
||||||
<label>Disable auto orientation</label>
|
<label>${T.ingame.keybindingsOverlay.disableAutoOrientation}</label>
|
||||||
</div>
|
</div>
|
||||||
` +
|
` +
|
||||||
(queryParamOptions.betaMode
|
(queryParamOptions.betaMode
|
||||||
? `
|
? `
|
||||||
<div class="binding hudToggle">
|
<div class="binding hudToggle">
|
||||||
<code class="keybinding">F2</code>
|
<code class="keybinding">F2</code>
|
||||||
<label>Toggle HUD</label>
|
<label>${T.ingame.keybindingsOverlay.toggleHud}</label>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: "")
|
: "")
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { makeDiv } from "../../../core/utils";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
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";
|
||||||
|
|
||||||
const logger = createLogger("hud/mass_selector");
|
const logger = createLogger("hud/mass_selector");
|
||||||
|
|
||||||
|
@ -23,10 +24,9 @@ export class HUDMassSelector extends BaseHUDPart {
|
||||||
parent,
|
parent,
|
||||||
"ingame_HUD_MassSelector",
|
"ingame_HUD_MassSelector",
|
||||||
[],
|
[],
|
||||||
`
|
T.ingame.massDelete.infoText
|
||||||
Press <code class="keybinding">${removalKeybinding}</code> to remove selected buildings
|
.replace("<keyDelete>", removalKeybinding)
|
||||||
and <code class="keybinding">${abortKeybinding}</code> to cancel.
|
.replace("<keyCancel>", abortKeybinding)
|
||||||
`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,22 +80,6 @@ export class HUDModalDialogs extends BaseHUDPart {
|
||||||
return dialog.buttonSignals;
|
return dialog.buttonSignals;
|
||||||
}
|
}
|
||||||
|
|
||||||
showVideoTutorial(title, text, videoUrl) {
|
|
||||||
const dialog = new DialogVideoTutorial({
|
|
||||||
app: this.app,
|
|
||||||
title: title,
|
|
||||||
contentHTML: text,
|
|
||||||
videoUrl,
|
|
||||||
});
|
|
||||||
this.internalShowDialog(dialog);
|
|
||||||
|
|
||||||
if (this.app) {
|
|
||||||
this.app.sound.playUiSound(SOUNDS.dialogOk);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dialog.buttonSignals;
|
|
||||||
}
|
|
||||||
|
|
||||||
showOptionChooser(title, options) {
|
showOptionChooser(title, options) {
|
||||||
const dialog = new DialogOptionChooser({
|
const dialog = new DialogOptionChooser({
|
||||||
app: this.app,
|
app: this.app,
|
||||||
|
|
|
@ -1,5 +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 { T } from "../../../translations";
|
||||||
|
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
export const enumNotificationType = {
|
export const enumNotificationType = {
|
||||||
|
@ -23,7 +24,7 @@ export class HUDNotifications extends BaseHUDPart {
|
||||||
|
|
||||||
// Automatic notifications
|
// Automatic notifications
|
||||||
this.root.signals.gameSaved.add(() =>
|
this.root.signals.gameSaved.add(() =>
|
||||||
this.onNotification("Your game has been saved.", enumNotificationType.saved)
|
this.onNotification(T.ingame.notifications.gameSaved, enumNotificationType.saved)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { makeDiv } from "../../../core/utils";
|
import { makeDiv, formatSeconds } 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 } from "../../key_action_mapper";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
|
||||||
export class HUDSettingsMenu extends BaseHUDPart {
|
export class HUDSettingsMenu extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
|
@ -14,18 +15,18 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
||||||
this.background,
|
this.background,
|
||||||
null,
|
null,
|
||||||
["timePlayed"],
|
["timePlayed"],
|
||||||
`<strong>Playtime</strong><span class="playtime"></span>`
|
`<strong>${T.ingame.settingsMenu.playtime}</strong><span class="playtime"></span>`
|
||||||
);
|
);
|
||||||
|
|
||||||
this.buttonContainer = makeDiv(this.menuElement, null, ["buttons"]);
|
this.buttonContainer = makeDiv(this.menuElement, null, ["buttons"]);
|
||||||
|
|
||||||
const buttons = [
|
const buttons = [
|
||||||
{
|
{
|
||||||
title: "Continue",
|
title: T.ingame.settingsMenu.buttons.continue,
|
||||||
action: () => this.close(),
|
action: () => this.close(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Return to menu",
|
title: T.ingame.settingsMenu.buttons.menu,
|
||||||
action: () => this.returnToMenu(),
|
action: () => this.returnToMenu(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -79,9 +80,8 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
||||||
// this.background.classList.add("visible");
|
// this.background.classList.add("visible");
|
||||||
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
||||||
|
|
||||||
const totalMinutesPlayed = Math.ceil(this.root.time.now() / 60.0);
|
const totalSecondsPlayed = Math.ceil(this.root.time.now());
|
||||||
const playtimeString = totalMinutesPlayed === 1 ? "1 minute" : totalMinutesPlayed + " minutes";
|
this.timePlayed.querySelector(".playtime").innerText = formatSeconds(totalSecondsPlayed);
|
||||||
this.timePlayed.querySelector(".playtime").innerText = playtimeString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
|
||||||
import { makeDiv, removeAllChildren, formatBigNumber } from "../../../core/utils";
|
|
||||||
import { UPGRADES, TIER_LABELS } from "../../upgrades";
|
|
||||||
import { ShapeDefinition } from "../../shape_definition";
|
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
|
||||||
import { InputReceiver } from "../../../core/input_receiver";
|
|
||||||
import { KeyActionMapper } from "../../key_action_mapper";
|
|
||||||
import { Math_min } from "../../../core/builtins";
|
import { Math_min } from "../../../core/builtins";
|
||||||
import { ClickDetector } from "../../../core/click_detector";
|
import { ClickDetector } from "../../../core/click_detector";
|
||||||
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
|
import { formatBigNumber, makeDiv } from "../../../core/utils";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
import { KeyActionMapper } from "../../key_action_mapper";
|
||||||
|
import { UPGRADES } from "../../upgrades";
|
||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
|
|
||||||
export class HUDShop extends BaseHUDPart {
|
export class HUDShop extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
|
@ -14,7 +14,7 @@ export class HUDShop extends BaseHUDPart {
|
||||||
|
|
||||||
// DIALOG Inner / Wrapper
|
// DIALOG Inner / Wrapper
|
||||||
this.dialogInner = makeDiv(this.background, null, ["dialogInner"]);
|
this.dialogInner = makeDiv(this.background, null, ["dialogInner"]);
|
||||||
this.title = makeDiv(this.dialogInner, null, ["title"], `Upgrades`);
|
this.title = makeDiv(this.dialogInner, null, ["title"], T.ingame.shop.title);
|
||||||
this.closeButton = makeDiv(this.title, null, ["closeButton"]);
|
this.closeButton = makeDiv(this.title, null, ["closeButton"]);
|
||||||
this.trackClicks(this.closeButton, this.close);
|
this.trackClicks(this.closeButton, this.close);
|
||||||
this.contentDiv = makeDiv(this.dialogInner, null, ["content"]);
|
this.contentDiv = makeDiv(this.dialogInner, null, ["content"]);
|
||||||
|
@ -23,7 +23,6 @@ export class HUDShop extends BaseHUDPart {
|
||||||
|
|
||||||
// Upgrades
|
// Upgrades
|
||||||
for (const upgradeId in UPGRADES) {
|
for (const upgradeId in UPGRADES) {
|
||||||
const { label } = UPGRADES[upgradeId];
|
|
||||||
const handle = {};
|
const handle = {};
|
||||||
handle.requireIndexToElement = [];
|
handle.requireIndexToElement = [];
|
||||||
|
|
||||||
|
@ -32,10 +31,10 @@ export class HUDShop extends BaseHUDPart {
|
||||||
handle.elem.setAttribute("data-upgrade-id", upgradeId);
|
handle.elem.setAttribute("data-upgrade-id", upgradeId);
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
const title = makeDiv(handle.elem, null, ["title"], label);
|
const title = makeDiv(handle.elem, null, ["title"], T.shopUpgrades[upgradeId].name);
|
||||||
|
|
||||||
// Title > Tier
|
// Title > Tier
|
||||||
handle.elemTierLabel = makeDiv(title, null, ["tier"], "Tier ?");
|
handle.elemTierLabel = makeDiv(title, null, ["tier"]);
|
||||||
|
|
||||||
// Icon
|
// Icon
|
||||||
handle.icon = makeDiv(handle.elem, null, ["icon"]);
|
handle.icon = makeDiv(handle.elem, null, ["icon"]);
|
||||||
|
@ -48,7 +47,7 @@ export class HUDShop extends BaseHUDPart {
|
||||||
// Buy button
|
// Buy button
|
||||||
handle.buyButton = document.createElement("button");
|
handle.buyButton = document.createElement("button");
|
||||||
handle.buyButton.classList.add("buy", "styledButton");
|
handle.buyButton.classList.add("buy", "styledButton");
|
||||||
handle.buyButton.innerText = "Upgrade";
|
handle.buyButton.innerText = T.ingame.shop.buttonUnlock;
|
||||||
handle.elem.appendChild(handle.buyButton);
|
handle.elem.appendChild(handle.buyButton);
|
||||||
|
|
||||||
this.trackClicks(handle.buyButton, () => this.tryUnlockNextTier(upgradeId));
|
this.trackClicks(handle.buyButton, () => this.tryUnlockNextTier(upgradeId));
|
||||||
|
@ -61,13 +60,17 @@ export class HUDShop extends BaseHUDPart {
|
||||||
rerenderFull() {
|
rerenderFull() {
|
||||||
for (const upgradeId in this.upgradeToElements) {
|
for (const upgradeId in this.upgradeToElements) {
|
||||||
const handle = this.upgradeToElements[upgradeId];
|
const handle = this.upgradeToElements[upgradeId];
|
||||||
const { description, tiers } = UPGRADES[upgradeId];
|
const { tiers } = UPGRADES[upgradeId];
|
||||||
|
|
||||||
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||||
const tierHandle = tiers[currentTier];
|
const tierHandle = tiers[currentTier];
|
||||||
|
|
||||||
// Set tier
|
// Set tier
|
||||||
handle.elemTierLabel.innerText = "Tier " + TIER_LABELS[currentTier];
|
handle.elemTierLabel.innerText = T.ingame.shop.tier.replace(
|
||||||
|
"<x>",
|
||||||
|
"" + T.ingame.shop.tierLabels[currentTier]
|
||||||
|
);
|
||||||
|
|
||||||
handle.elemTierLabel.setAttribute("data-tier", currentTier);
|
handle.elemTierLabel.setAttribute("data-tier", currentTier);
|
||||||
|
|
||||||
// Cleanup detectors
|
// Cleanup detectors
|
||||||
|
@ -84,12 +87,15 @@ export class HUDShop extends BaseHUDPart {
|
||||||
|
|
||||||
if (!tierHandle) {
|
if (!tierHandle) {
|
||||||
// Max level
|
// Max level
|
||||||
handle.elemDescription.innerText = "Maximum level";
|
handle.elemDescription.innerText = T.ingame.shop.maximumLevel;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set description
|
// Set description
|
||||||
handle.elemDescription.innerText = description(tierHandle.improvement);
|
handle.elemDescription.innerText = T.shopUpgrades[upgradeId].description.replace(
|
||||||
|
"<gain>",
|
||||||
|
Math.floor(tierHandle.improvement * 100.0)
|
||||||
|
);
|
||||||
|
|
||||||
tierHandle.required.forEach(({ shape, amount }) => {
|
tierHandle.required.forEach(({ shape, amount }) => {
|
||||||
const container = makeDiv(handle.elemRequirements, null, ["requirement"]);
|
const container = makeDiv(handle.elemRequirements, null, ["requirement"]);
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
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 } from "../../../core/utils";
|
import { makeButton, makeDiv, removeAllChildren, capitalizeFirstLetter } from "../../../core/utils";
|
||||||
import { KeyActionMapper } from "../../key_action_mapper";
|
import { KeyActionMapper } 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";
|
||||||
import { enumDisplayMode, HUDShapeStatisticsHandle } from "./statistics_handle";
|
import { enumDisplayMode, HUDShapeStatisticsHandle } from "./statistics_handle";
|
||||||
|
import { T } from "../../../translations";
|
||||||
const enumDataSourceToText = {
|
|
||||||
[enumAnalyticsDataSource.stored]: "Displaying amount of stored shapes in your central building.",
|
|
||||||
[enumAnalyticsDataSource.produced]:
|
|
||||||
"Displaying all shapes your whole factory produces, including intermediate products.",
|
|
||||||
[enumAnalyticsDataSource.delivered]: "Displaying shapes which are delivered to your central building.",
|
|
||||||
};
|
|
||||||
|
|
||||||
export class HUDStatistics extends BaseHUDPart {
|
export class HUDStatistics extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
|
@ -20,7 +14,7 @@ export class HUDStatistics extends BaseHUDPart {
|
||||||
|
|
||||||
// DIALOG Inner / Wrapper
|
// DIALOG Inner / Wrapper
|
||||||
this.dialogInner = makeDiv(this.background, null, ["dialogInner"]);
|
this.dialogInner = makeDiv(this.background, null, ["dialogInner"]);
|
||||||
this.title = makeDiv(this.dialogInner, null, ["title"], `statistics`);
|
this.title = makeDiv(this.dialogInner, null, ["title"], T.ingame.statistics.title);
|
||||||
this.closeButton = makeDiv(this.title, null, ["closeButton"]);
|
this.closeButton = makeDiv(this.title, null, ["closeButton"]);
|
||||||
this.trackClicks(this.closeButton, this.close);
|
this.trackClicks(this.closeButton, this.close);
|
||||||
|
|
||||||
|
@ -30,13 +24,21 @@ export class HUDStatistics extends BaseHUDPart {
|
||||||
this.filtersDataSource = makeDiv(this.filterHeader, null, ["filtersDataSource"]);
|
this.filtersDataSource = makeDiv(this.filterHeader, null, ["filtersDataSource"]);
|
||||||
this.filtersDisplayMode = makeDiv(this.filterHeader, null, ["filtersDisplayMode"]);
|
this.filtersDisplayMode = makeDiv(this.filterHeader, null, ["filtersDisplayMode"]);
|
||||||
|
|
||||||
const buttonModeProduced = makeButton(this.filtersDataSource, ["modeProduced"], "Produced");
|
const dataSources = [
|
||||||
const buttonModeDelivered = makeButton(this.filtersDataSource, ["modeDelivered"], "Delivered");
|
enumAnalyticsDataSource.produced,
|
||||||
const buttonModeStored = makeButton(this.filtersDataSource, ["modeStored"], "Stored");
|
enumAnalyticsDataSource.delivered,
|
||||||
|
enumAnalyticsDataSource.stored,
|
||||||
|
];
|
||||||
|
|
||||||
this.trackClicks(buttonModeProduced, () => this.setDataSource(enumAnalyticsDataSource.produced));
|
for (let i = 0; i < dataSources.length; ++i) {
|
||||||
this.trackClicks(buttonModeStored, () => this.setDataSource(enumAnalyticsDataSource.stored));
|
const dataSource = dataSources[i];
|
||||||
this.trackClicks(buttonModeDelivered, () => this.setDataSource(enumAnalyticsDataSource.delivered));
|
const button = makeButton(
|
||||||
|
this.filtersDataSource,
|
||||||
|
["mode" + capitalizeFirstLetter(dataSource)],
|
||||||
|
T.ingame.statistics.dataSources[dataSource].title
|
||||||
|
);
|
||||||
|
this.trackClicks(button, () => this.setDataSource(dataSource));
|
||||||
|
}
|
||||||
|
|
||||||
const buttonDisplayDetailed = makeButton(this.filtersDisplayMode, ["displayDetailed"]);
|
const buttonDisplayDetailed = makeButton(this.filtersDisplayMode, ["displayDetailed"]);
|
||||||
const buttonDisplayIcons = makeButton(this.filtersDisplayMode, ["displayIcons"]);
|
const buttonDisplayIcons = makeButton(this.filtersDisplayMode, ["displayIcons"]);
|
||||||
|
@ -54,7 +56,7 @@ export class HUDStatistics extends BaseHUDPart {
|
||||||
this.dataSource = source;
|
this.dataSource = source;
|
||||||
this.dialogInner.setAttribute("data-datasource", source);
|
this.dialogInner.setAttribute("data-datasource", source);
|
||||||
|
|
||||||
this.sourceExplanation.innerText = enumDataSourceToText[source];
|
this.sourceExplanation.innerText = T.ingame.statistics.dataSources[source].title;
|
||||||
if (this.visible) {
|
if (this.visible) {
|
||||||
this.rerenderFull();
|
this.rerenderFull();
|
||||||
}
|
}
|
||||||
|
@ -204,7 +206,7 @@ export class HUDStatistics extends BaseHUDPart {
|
||||||
|
|
||||||
if (entries.length === 0) {
|
if (entries.length === 0) {
|
||||||
this.contentDiv.innerHTML = `
|
this.contentDiv.innerHTML = `
|
||||||
<strong class="noEntries">No shapes have been produced so far.</strong>`;
|
<strong class="noEntries">${T.ingame.statistics.noShapesProduced}</strong>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.contentDiv.classList.toggle("hasEntries", entries.length > 0);
|
this.contentDiv.classList.toggle("hasEntries", entries.length > 0);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { enumAnalyticsDataSource } from "../../production_analytics";
|
||||||
import { formatBigNumber, clamp } from "../../../core/utils";
|
import { formatBigNumber, clamp } from "../../../core/utils";
|
||||||
import { globalConfig } from "../../../core/config";
|
import { globalConfig } from "../../../core/config";
|
||||||
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
export const enumDisplayMode = {
|
export const enumDisplayMode = {
|
||||||
|
@ -86,7 +87,10 @@ export class HUDShapeStatisticsHandle {
|
||||||
(this.root.productionAnalytics.getCurrentShapeRate(dataSource, this.definition) /
|
(this.root.productionAnalytics.getCurrentShapeRate(dataSource, this.definition) /
|
||||||
globalConfig.analyticsSliceDurationSeconds) *
|
globalConfig.analyticsSliceDurationSeconds) *
|
||||||
60;
|
60;
|
||||||
this.counter.innerText = formatBigNumber(rate) + " / m";
|
this.counter.innerText = T.ingame.statistics.shapesPerMinute.replace(
|
||||||
|
"<shapes>",
|
||||||
|
formatBigNumber(rate)
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,10 @@ import { MetaSplitterBuilding } from "../../buildings/splitter";
|
||||||
import { MetaStackerBuilding } from "../../buildings/stacker";
|
import { MetaStackerBuilding } from "../../buildings/stacker";
|
||||||
import { MetaTrashBuilding } from "../../buildings/trash";
|
import { MetaTrashBuilding } from "../../buildings/trash";
|
||||||
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
|
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
|
||||||
import { enumHubGoalRewards, enumHubGoalRewardToString } from "../../tutorial_goals";
|
import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||||
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";
|
||||||
|
|
||||||
export class HUDUnlockNotification extends BaseHUDPart {
|
export class HUDUnlockNotification extends BaseHUDPart {
|
||||||
initialize() {
|
initialize() {
|
||||||
|
@ -36,17 +37,10 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||||
|
|
||||||
const dialog = makeDiv(this.element, null, ["dialog"]);
|
const dialog = makeDiv(this.element, null, ["dialog"]);
|
||||||
|
|
||||||
this.elemTitle = makeDiv(dialog, null, ["title"], ``);
|
this.elemTitle = makeDiv(dialog, null, ["title"]);
|
||||||
this.elemSubTitle = makeDiv(dialog, null, ["subTitle"], `Completed`);
|
this.elemSubTitle = makeDiv(dialog, null, ["subTitle"], T.ingame.levelCompleteNotification.completed);
|
||||||
|
|
||||||
this.elemContents = makeDiv(
|
this.elemContents = makeDiv(dialog, null, ["contents"]);
|
||||||
dialog,
|
|
||||||
null,
|
|
||||||
["contents"],
|
|
||||||
`
|
|
||||||
Ready for the next one?
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
this.btnClose = document.createElement("button");
|
this.btnClose = document.createElement("button");
|
||||||
this.btnClose.classList.add("close", "styledButton");
|
this.btnClose.classList.add("close", "styledButton");
|
||||||
|
@ -61,9 +55,17 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||||
* @param {enumHubGoalRewards} reward
|
* @param {enumHubGoalRewards} reward
|
||||||
*/
|
*/
|
||||||
showForLevel(level, reward) {
|
showForLevel(level, reward) {
|
||||||
this.elemTitle.innerText = "Level " + ("" + level).padStart(2, "0");
|
this.elemTitle.innerText = T.ingame.levelCompleteNotification.levelTitle.replace(
|
||||||
|
"<level>",
|
||||||
|
("" + level).padStart(2, "0")
|
||||||
|
);
|
||||||
|
|
||||||
let html = `<span class='reward'>Unlocked ${enumHubGoalRewardToString[reward]}!</span>`;
|
const rewardText = T.storyRewards[reward];
|
||||||
|
|
||||||
|
let html =
|
||||||
|
"<span class='reward'>" +
|
||||||
|
T.ingame.levelCompleteNotification.unlockText.replace("<reward>", rewardText) +
|
||||||
|
"</span>";
|
||||||
|
|
||||||
const addBuildingExplanation = metaBuildingClass => {
|
const addBuildingExplanation = metaBuildingClass => {
|
||||||
const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
|
const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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";
|
||||||
|
|
||||||
function key(str) {
|
function key(str) {
|
||||||
return str.toUpperCase().charCodeAt(0);
|
return str.toUpperCase().charCodeAt(0);
|
||||||
|
@ -65,23 +66,23 @@ export function getStringForKeyCode(code) {
|
||||||
case 8:
|
case 8:
|
||||||
return "⌫";
|
return "⌫";
|
||||||
case 9:
|
case 9:
|
||||||
return "TAB";
|
return T.global.keys.tab;
|
||||||
case 13:
|
case 13:
|
||||||
return "⏎";
|
return "⏎";
|
||||||
case 16:
|
case 16:
|
||||||
return "⇪";
|
return "⇪";
|
||||||
case 17:
|
case 17:
|
||||||
return "CTRL";
|
return T.global.keys.control;
|
||||||
case 18:
|
case 18:
|
||||||
return "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 27:
|
||||||
return "ESC";
|
return T.global.keys.escape;
|
||||||
case 32:
|
case 32:
|
||||||
return "SPACE";
|
return T.global.keys.space;
|
||||||
case 33:
|
case 33:
|
||||||
return "PGUP";
|
return "PGUP";
|
||||||
case 34:
|
case 34:
|
||||||
|
|
|
@ -31,20 +31,6 @@ export class MetaBuilding {
|
||||||
return new Vector(1, 1);
|
return new Vector(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Should return the name of this building
|
|
||||||
*/
|
|
||||||
getName() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should return the description of this building
|
|
||||||
*/
|
|
||||||
getDescription() {
|
|
||||||
return "No Description";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to stay in placement mode after having placed a building
|
* Whether to stay in placement mode after having placed a building
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { HubComponent } from "../components/hub";
|
||||||
import { DrawParameters } from "../../core/draw_parameters";
|
import { DrawParameters } from "../../core/draw_parameters";
|
||||||
import { Entity } from "../entity";
|
import { Entity } from "../entity";
|
||||||
import { formatBigNumber } from "../../core/utils";
|
import { formatBigNumber } from "../../core/utils";
|
||||||
import { enumHubGoalRewardToString } from "../tutorial_goals";
|
|
||||||
import { Loader } from "../../core/loader";
|
import { Loader } from "../../core/loader";
|
||||||
|
import { T } from "../../translations";
|
||||||
|
|
||||||
export class HubSystem extends GameSystemWithFilter {
|
export class HubSystem extends GameSystemWithFilter {
|
||||||
constructor(root) {
|
constructor(root) {
|
||||||
|
@ -84,7 +84,7 @@ export class HubSystem extends GameSystemWithFilter {
|
||||||
context.font = "bold 11px GameFont";
|
context.font = "bold 11px GameFont";
|
||||||
context.fillStyle = "#fd0752";
|
context.fillStyle = "#fd0752";
|
||||||
context.textAlign = "center";
|
context.textAlign = "center";
|
||||||
context.fillText(enumHubGoalRewardToString[goals.reward].toUpperCase(), pos.x, pos.y + 46);
|
context.fillText(T.storyRewards[goals.reward].toUpperCase(), pos.x, pos.y + 46);
|
||||||
|
|
||||||
// Level
|
// Level
|
||||||
context.font = "bold 11px GameFont";
|
context.font = "bold 11px GameFont";
|
||||||
|
|
|
@ -15,21 +15,6 @@ export const enumHubGoalRewards = {
|
||||||
no_reward: "no_reward",
|
no_reward: "no_reward",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @enum {string}
|
|
||||||
*/
|
|
||||||
export const enumHubGoalRewardToString = {
|
|
||||||
[enumHubGoalRewards.reward_cutter_and_trash]: "Cutting Shapes",
|
|
||||||
[enumHubGoalRewards.reward_rotater]: "Rotating",
|
|
||||||
[enumHubGoalRewards.reward_painter]: "Painting",
|
|
||||||
[enumHubGoalRewards.reward_mixer]: "Color Mixing",
|
|
||||||
[enumHubGoalRewards.reward_stacker]: "Combiner",
|
|
||||||
[enumHubGoalRewards.reward_splitter]: "Splitter/Merger",
|
|
||||||
[enumHubGoalRewards.reward_tunnel]: "Tunnel",
|
|
||||||
|
|
||||||
[enumHubGoalRewards.no_reward]: "Next level",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const tutorialGoals = [
|
export const tutorialGoals = [
|
||||||
// Circle
|
// Circle
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,33 +1,8 @@
|
||||||
import { findNiceIntegerValue } from "../core/utils";
|
import { findNiceIntegerValue } from "../core/utils";
|
||||||
import { ShapeDefinition } from "./shape_definition";
|
import { ShapeDefinition } from "./shape_definition";
|
||||||
|
|
||||||
export const TIER_LABELS = [
|
|
||||||
"I",
|
|
||||||
"II",
|
|
||||||
"III",
|
|
||||||
"IV",
|
|
||||||
"V",
|
|
||||||
"VI",
|
|
||||||
"VII",
|
|
||||||
"VIII",
|
|
||||||
"IX",
|
|
||||||
"X",
|
|
||||||
"XI",
|
|
||||||
"XII",
|
|
||||||
"XIII",
|
|
||||||
"XIV",
|
|
||||||
"XV",
|
|
||||||
"XVI",
|
|
||||||
"XVII",
|
|
||||||
"XVIII",
|
|
||||||
"XIX",
|
|
||||||
"XX",
|
|
||||||
];
|
|
||||||
|
|
||||||
export const UPGRADES = {
|
export const UPGRADES = {
|
||||||
belt: {
|
belt: {
|
||||||
label: "Belts, Distributer & Tunnels",
|
|
||||||
description: improvement => "Speed +" + Math.floor(improvement * 100.0) + "%",
|
|
||||||
tiers: [
|
tiers: [
|
||||||
{
|
{
|
||||||
required: [{ shape: "CuCuCuCu", amount: 80 }],
|
required: [{ shape: "CuCuCuCu", amount: 80 }],
|
||||||
|
@ -49,8 +24,6 @@ export const UPGRADES = {
|
||||||
},
|
},
|
||||||
|
|
||||||
miner: {
|
miner: {
|
||||||
label: "Extraction",
|
|
||||||
description: improvement => "Speed +" + Math.floor(improvement * 100.0) + "%",
|
|
||||||
tiers: [
|
tiers: [
|
||||||
{
|
{
|
||||||
required: [{ shape: "RuRuRuRu", amount: 200 }],
|
required: [{ shape: "RuRuRuRu", amount: 200 }],
|
||||||
|
@ -72,8 +45,6 @@ export const UPGRADES = {
|
||||||
},
|
},
|
||||||
|
|
||||||
processors: {
|
processors: {
|
||||||
label: "Shape Processing",
|
|
||||||
description: improvement => "Speed +" + Math.floor(improvement * 100.0) + "%",
|
|
||||||
tiers: [
|
tiers: [
|
||||||
{
|
{
|
||||||
required: [{ shape: "SuSuSuSu", amount: 200 }],
|
required: [{ shape: "SuSuSuSu", amount: 200 }],
|
||||||
|
@ -95,8 +66,6 @@ export const UPGRADES = {
|
||||||
},
|
},
|
||||||
|
|
||||||
painting: {
|
painting: {
|
||||||
label: "Mixing & Painting",
|
|
||||||
description: improvement => "Speed +" + Math.floor(improvement * 100.0) + "%",
|
|
||||||
tiers: [
|
tiers: [
|
||||||
{
|
{
|
||||||
required: [{ shape: "WuWuWuWu", amount: 200 }],
|
required: [{ shape: "WuWuWuWu", amount: 200 }],
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { createLogger } from "../../core/logging";
|
||||||
import { ClickDetector } from "../../core/click_detector";
|
import { ClickDetector } from "../../core/click_detector";
|
||||||
import { performanceNow } from "../../core/builtins";
|
import { performanceNow } from "../../core/builtins";
|
||||||
import { clamp } from "../../core/utils";
|
import { clamp } from "../../core/utils";
|
||||||
|
import { T } from "../../translations";
|
||||||
|
|
||||||
const logger = createLogger("adprovider/adinplay");
|
const logger = createLogger("adprovider/adinplay");
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ export class AdinplayAdProvider extends AdProviderInterface {
|
||||||
AD_HEIGHT: h,
|
AD_HEIGHT: h,
|
||||||
AD_FULLSCREEN: false,
|
AD_FULLSCREEN: false,
|
||||||
AD_CENTERPLAYER: false,
|
AD_CENTERPLAYER: false,
|
||||||
LOADING_TEXT: "Loading",
|
LOADING_TEXT: T.global.loading,
|
||||||
PREROLL_ELEM: function () {
|
PREROLL_ELEM: function () {
|
||||||
return videoElement;
|
return videoElement;
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
} from "../core/utils";
|
} from "../core/utils";
|
||||||
import { ReadWriteProxy } from "../core/read_write_proxy";
|
import { ReadWriteProxy } from "../core/read_write_proxy";
|
||||||
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
||||||
|
import { T } from "../translations";
|
||||||
|
|
||||||
export class MainMenuState extends GameState {
|
export class MainMenuState extends GameState {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -18,14 +19,12 @@ export class MainMenuState extends GameState {
|
||||||
|
|
||||||
getInnerHTML() {
|
getInnerHTML() {
|
||||||
const bannerHtml = `
|
const bannerHtml = `
|
||||||
<h3>This is a Demo Version</h3>
|
<h3>${T.demoBanners.title}</h3>
|
||||||
|
|
||||||
<p>Get <strong>shapez.io on steam</strong> for:</p>
|
<p>${T.demoBanners.intro}</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>No advertisements and demo banners.</li>
|
${T.demoBanners.advantages.map(advantage => `<li>${advantage}</li>`).join("")}
|
||||||
<li>Unlimited savegame slots.</li>
|
|
||||||
<li>Supporting the developer ❤️</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a href="https://steam.shapez.io" class="steamLink" target="_blank">Get shapez.io on steam!</a>
|
<a href="https://steam.shapez.io" class="steamLink" target="_blank">Get shapez.io on steam!</a>
|
||||||
|
@ -65,12 +64,12 @@ export class MainMenuState extends GameState {
|
||||||
isSupportedBrowser()
|
isSupportedBrowser()
|
||||||
? ""
|
? ""
|
||||||
: `
|
: `
|
||||||
<div class="browserWarning">This game is optimized for Google Chrome. Your browser is not supported or slow!</div>
|
<div class="browserWarning">${T.mainMenu.browserWarning}</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
<button class="playButton styledButton">Play</button>
|
<button class="playButton styledButton">${T.mainMenu.play}</button>
|
||||||
<button class="importButton styledButton">Import savegame</button>
|
<button class="importButton styledButton">${T.mainMenu.importSavegame}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${
|
${
|
||||||
|
@ -86,13 +85,13 @@ export class MainMenuState extends GameState {
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
|
|
||||||
<a href="https://github.com/tobspr/shapez.io" target="_blank">
|
<a href="https://github.com/tobspr/shapez.io" target="_blank">
|
||||||
This game is open source!
|
${T.mainMenu.openSourceHint}
|
||||||
<span class="thirdpartyLogo githubLogo"></span>
|
<span class="thirdpartyLogo githubLogo"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="https://discord.gg/HN7EVzV" target="_blank">
|
<a href="https://discord.gg/HN7EVzV" target="_blank">
|
||||||
Official discord server
|
${T.mainMenu.discordLink}
|
||||||
<span class="thirdpartyLogo discordLogo"></span>
|
<span class="thirdpartyLogo discordLogo"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -112,7 +111,6 @@ export class MainMenuState extends GameState {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.addEventListener("load", event => {
|
reader.addEventListener("load", event => {
|
||||||
const contents = event.target.result;
|
const contents = event.target.result;
|
||||||
|
|
||||||
let realContent;
|
let realContent;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -120,8 +118,8 @@ export class MainMenuState extends GameState {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
closeLoader();
|
closeLoader();
|
||||||
this.dialogs.showWarning(
|
this.dialogs.showWarning(
|
||||||
"Import error",
|
T.dialogs.importSavegameError.title,
|
||||||
"Failed to import your savegame:<br><br>" + err
|
T.dialogs.importSavegameError.text + "<br><br>" + err
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -129,22 +127,27 @@ export class MainMenuState extends GameState {
|
||||||
this.app.savegameMgr.importSavegame(realContent).then(
|
this.app.savegameMgr.importSavegame(realContent).then(
|
||||||
() => {
|
() => {
|
||||||
closeLoader();
|
closeLoader();
|
||||||
this.dialogs.showWarning("Imported", "Your savegame has been imported.");
|
this.dialogs.showWarning(
|
||||||
|
T.dialogs.importSavegameSuccess.title,
|
||||||
|
T.dialogs.importSavegameSuccess.text
|
||||||
|
);
|
||||||
|
|
||||||
this.renderSavegames();
|
this.renderSavegames();
|
||||||
},
|
},
|
||||||
err => {
|
err => {
|
||||||
closeLoader();
|
closeLoader();
|
||||||
this.dialogs.showWarning(
|
this.dialogs.showWarning(
|
||||||
"Import error",
|
T.dialogs.importSavegameError.title,
|
||||||
"Failed to import savegame. Please check the console output."
|
T.dialogs.importSavegameError.text + ":<br><br>" + err
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
reader.addEventListener("error", error => {
|
reader.addEventListener("error", error => {
|
||||||
console.error(error);
|
this.dialogs.showWarning(
|
||||||
alert("Failed to read file: " + error);
|
T.dialogs.importSavegameError.title,
|
||||||
|
T.dialogs.importSavegameError.text + ":<br><br>" + error
|
||||||
|
);
|
||||||
});
|
});
|
||||||
reader.readAsText(file, "utf-8");
|
reader.readAsText(file, "utf-8");
|
||||||
});
|
});
|
||||||
|
@ -159,7 +162,10 @@ export class MainMenuState extends GameState {
|
||||||
|
|
||||||
onEnter(payload) {
|
onEnter(payload) {
|
||||||
if (payload.loadError) {
|
if (payload.loadError) {
|
||||||
alert("Error while loading game: " + payload.loadError);
|
this.dialogs.showWarning(
|
||||||
|
T.dialogs.gameLoadFailure.title,
|
||||||
|
T.dialogs.gameLoadFailure.text + "<br><br>" + payload.loadError
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dialogs = new HUDModalDialogs(null, this.app);
|
this.dialogs = new HUDModalDialogs(null, this.app);
|
||||||
|
@ -244,8 +250,8 @@ export class MainMenuState extends GameState {
|
||||||
*/
|
*/
|
||||||
deleteGame(game) {
|
deleteGame(game) {
|
||||||
const signals = this.dialogs.showWarning(
|
const signals = this.dialogs.showWarning(
|
||||||
"Confirm Deletion",
|
T.dialogs.confirmSavegameDelete.title,
|
||||||
"Are you sure you want to delete the game?",
|
T.dialogs.confirmSavegameDelete.text,
|
||||||
["delete:bad", "cancel:good"]
|
["delete:bad", "cancel:good"]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -255,7 +261,10 @@ export class MainMenuState extends GameState {
|
||||||
this.renderSavegames();
|
this.renderSavegames();
|
||||||
},
|
},
|
||||||
err => {
|
err => {
|
||||||
this.dialogs.showWarning("Failed to delete", "Error: " + err);
|
this.dialogs.showWarning(
|
||||||
|
T.dialogs.savegameDeletionError.title,
|
||||||
|
T.dialogs.savegameDeletionError.text + "<br><br>" + err
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { globalConfig } from "./core/config";
|
||||||
|
|
||||||
|
const baseTranslations = require("./translations-built/base-en.json");
|
||||||
|
|
||||||
|
export const T = baseTranslations;
|
||||||
|
|
||||||
|
if (G_IS_DEV && globalConfig.debug.testTranslations) {
|
||||||
|
// Replaces all translations by fake translations to see whats translated and what not
|
||||||
|
const mapTranslations = obj => {
|
||||||
|
for (const key in obj) {
|
||||||
|
const value = obj[key];
|
||||||
|
if (typeof value === "string") {
|
||||||
|
obj[key] = value.replace(/[a-z]/gi, "x");
|
||||||
|
} else {
|
||||||
|
mapTranslations(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mapTranslations(T);
|
||||||
|
}
|
|
@ -0,0 +1,259 @@
|
||||||
|
#
|
||||||
|
# GAME TRANSLATIONS
|
||||||
|
#
|
||||||
|
# Contributing:
|
||||||
|
#
|
||||||
|
# If you want to contribute, please make a pull request on this respository
|
||||||
|
# and I will have a look.
|
||||||
|
#
|
||||||
|
# Placeholders:
|
||||||
|
#
|
||||||
|
# Do *not* replace placeholders! Placeholders have a special syntax like
|
||||||
|
# `Hotkey: <key>`. They are encapsulated within angle brackets. The correct
|
||||||
|
# translation for this one in German for example would be: `Taste: <key>` (notice
|
||||||
|
# how the placeholder stayed '<key>' and was not replaced!)
|
||||||
|
#
|
||||||
|
# Adding a new language:
|
||||||
|
#
|
||||||
|
# If you want to add a new language, ask me in the discord and I will setup
|
||||||
|
# the basic structure so the game also detects it.
|
||||||
|
#
|
||||||
|
|
||||||
|
global:
|
||||||
|
loading: Loading
|
||||||
|
|
||||||
|
# How big numbers are rendered, e.g. "10,000"
|
||||||
|
thousandsDivider: ","
|
||||||
|
|
||||||
|
# Shown for infinitely big numbers
|
||||||
|
infinite: inf
|
||||||
|
|
||||||
|
time:
|
||||||
|
# Used for formatting past time dates
|
||||||
|
oneSecondAgo: one second ago
|
||||||
|
xSecondsAgo: <x> seconds ago
|
||||||
|
oneMinuteAgo: one minute ago
|
||||||
|
xMinutesAgo: <x> minutes ago
|
||||||
|
oneHourAgo: one hour ago
|
||||||
|
xHoursAgo: <x> hours ago
|
||||||
|
oneDayAgo: one day ago
|
||||||
|
xDaysAgo: <x> days ago
|
||||||
|
|
||||||
|
# Short formats for times, e.g. '5h 23m'
|
||||||
|
secondsShort: <seconds>s
|
||||||
|
minutesAndSecondsShort: <minutes>m <seconds>s
|
||||||
|
hoursAndMinutesShort: <hours>h <minutes>s
|
||||||
|
|
||||||
|
keys:
|
||||||
|
tab: TAB
|
||||||
|
control: CTRL
|
||||||
|
alt: ALT
|
||||||
|
escape: ESC
|
||||||
|
shift: SHIFT
|
||||||
|
space: SPACE
|
||||||
|
|
||||||
|
demoBanners:
|
||||||
|
# This is the "advertisement" shown in the main menu and other various places
|
||||||
|
title: This is a demo version
|
||||||
|
intro: >-
|
||||||
|
Get <strong>shapez.io on steam</strong> for:
|
||||||
|
advantages:
|
||||||
|
- No advertisements.
|
||||||
|
- Unlimited savegame slots.
|
||||||
|
- Supporting the developer ❤️
|
||||||
|
|
||||||
|
mainMenu:
|
||||||
|
play: Play
|
||||||
|
importSavegame: Import Savegame
|
||||||
|
openSourceHint: This game is open source!
|
||||||
|
discordLink: Official Discord Server
|
||||||
|
|
||||||
|
# This is shown when using firefox and other browsers which are not supported.
|
||||||
|
browserWarning: >-
|
||||||
|
This game is optimized for Google Chrome. Your browser is not supported or slow!
|
||||||
|
|
||||||
|
dialogs:
|
||||||
|
buttons:
|
||||||
|
ok: OK
|
||||||
|
delete: Delete
|
||||||
|
cancel: Cancel
|
||||||
|
|
||||||
|
importSavegameError:
|
||||||
|
title: Import Error
|
||||||
|
text: >-
|
||||||
|
Failed to import your savegame:
|
||||||
|
|
||||||
|
importSavegameSuccess:
|
||||||
|
title: Savegame Imported
|
||||||
|
text: >-
|
||||||
|
Your savegame has been successfully imported.
|
||||||
|
|
||||||
|
gameLoadFailure:
|
||||||
|
title: Game is broken
|
||||||
|
text: >-
|
||||||
|
Failed to load your savegame:
|
||||||
|
|
||||||
|
confirmSavegameDelete:
|
||||||
|
title: Confirm deletion
|
||||||
|
text: >-
|
||||||
|
Are you sure you want to delete the game?
|
||||||
|
|
||||||
|
savegameDeletionError:
|
||||||
|
title: Failed to delete
|
||||||
|
text: >-
|
||||||
|
Failed to delete the savegame:
|
||||||
|
|
||||||
|
ingame:
|
||||||
|
# This is shown in the top left corner and displays useful keybindings in
|
||||||
|
# every situation
|
||||||
|
keybindingsOverlay:
|
||||||
|
centerMap: Center
|
||||||
|
moveMap: Move
|
||||||
|
removeBuildings: Delete
|
||||||
|
stopPlacement: Stop placement
|
||||||
|
rotateBuilding: Rotate building
|
||||||
|
placeMultiple: Place multiple
|
||||||
|
reverseOrientation: Reverse orientation
|
||||||
|
disableAutoOrientation: Disable auto orientation
|
||||||
|
toggleHud: Toggle HUD
|
||||||
|
|
||||||
|
# Everything related to placing buildings (I.e. as soon as you selected a building
|
||||||
|
# from the toolbar)
|
||||||
|
buildingPlacement:
|
||||||
|
# Buildings can have different variants which are unlocked at later levels,
|
||||||
|
# and this is the hint shown when there are multiple variants available.
|
||||||
|
cycleBuildingVariants: Press <key> to cycle variants.
|
||||||
|
|
||||||
|
# Shows the hotkey in the ui, e.g. "Hotkey: Q"
|
||||||
|
hotkeyLabel: >-
|
||||||
|
Hotkey: <key>
|
||||||
|
|
||||||
|
# The notification when completing a level
|
||||||
|
levelCompleteNotification:
|
||||||
|
# <level> is replaced by the actual level, so this gets 'Level 03' for example.
|
||||||
|
levelTitle: Level <level>
|
||||||
|
completed: Completed
|
||||||
|
unlockText: Unlocked <reward>!
|
||||||
|
buttonNextLevel: Next Level
|
||||||
|
|
||||||
|
# Notifications on the lower right
|
||||||
|
notifications:
|
||||||
|
newUpgrade: A new upgrade is available!
|
||||||
|
gameSaved: Your game has been saved.
|
||||||
|
|
||||||
|
# Mass delete information, this is when you hold CTRL and then drag with your mouse
|
||||||
|
# to select multiple buildings to delete
|
||||||
|
massDelete:
|
||||||
|
infoText: Press <keyDelete> to remove selected buildings and <keyCancel> to cancel.
|
||||||
|
|
||||||
|
# The "Upgrades" window
|
||||||
|
shop:
|
||||||
|
title: Upgrades
|
||||||
|
buttonUnlock: Upgrade
|
||||||
|
|
||||||
|
# Gets replaced to e.g. "Tier IX"
|
||||||
|
tier: Tier <x>
|
||||||
|
|
||||||
|
# The roman number for each tier
|
||||||
|
tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X]
|
||||||
|
|
||||||
|
maximumLevel: Maximum level
|
||||||
|
|
||||||
|
# The "Statistics" window
|
||||||
|
statistics:
|
||||||
|
title: Statistics
|
||||||
|
dataSources:
|
||||||
|
stored:
|
||||||
|
title: Stored
|
||||||
|
description: Displaying amount of stored shapes in your central building.
|
||||||
|
produced:
|
||||||
|
title: Produced
|
||||||
|
description: Displaying all shapes your whole factory produces, including intermediate products.
|
||||||
|
delivered:
|
||||||
|
title: Delivered
|
||||||
|
description: Displaying shapes which are delivered to your central building.
|
||||||
|
noShapesProduced: No shapes have been produced so far.
|
||||||
|
|
||||||
|
# Displays the shapes per minute, e.g. '523 / m'
|
||||||
|
shapesPerMinute: <shapes> / m
|
||||||
|
|
||||||
|
# Settings menu, when you press "ESC"
|
||||||
|
settingsMenu:
|
||||||
|
playtime: Playtime
|
||||||
|
|
||||||
|
playtime1Minute: 1 minutes
|
||||||
|
playtimeXMinutes: <x> minutes
|
||||||
|
|
||||||
|
buttons:
|
||||||
|
continue: Continue
|
||||||
|
menu: Return to menu
|
||||||
|
|
||||||
|
# All shop upgrades
|
||||||
|
shopUpgrades:
|
||||||
|
belt:
|
||||||
|
name: Belts, Distributor & Tunnels
|
||||||
|
description: Speed +<gain>%
|
||||||
|
miner:
|
||||||
|
name: Extraction
|
||||||
|
description: Speed +<gain>%
|
||||||
|
processors:
|
||||||
|
name: Shape Processing
|
||||||
|
description: Speed +<gain>%
|
||||||
|
painting:
|
||||||
|
name: Mixing & Painting
|
||||||
|
description: Speed +<gain>%
|
||||||
|
|
||||||
|
# Buildings and their name / description
|
||||||
|
buildings:
|
||||||
|
belt:
|
||||||
|
name: Belt
|
||||||
|
description: Transports items, hold and drag to place multiple.
|
||||||
|
|
||||||
|
miner: # Internal name for the Extractor
|
||||||
|
name: Extractor
|
||||||
|
description: Place over a shape or color to extract it. Six extractors fill exactly one belt.
|
||||||
|
|
||||||
|
underground_belt: # Internal name for the Tunnel
|
||||||
|
name: Tunnel
|
||||||
|
description: Allows to tunnel resources under buildings and belts.
|
||||||
|
|
||||||
|
splitter: # Internal name for the Balancer
|
||||||
|
name: Balancer
|
||||||
|
description: Multifunctional - Evenly distributes all inputs onto all outputs.
|
||||||
|
|
||||||
|
cutter:
|
||||||
|
name: 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>
|
||||||
|
|
||||||
|
rotater:
|
||||||
|
name: Rotate
|
||||||
|
description: Rotates shapes clockwise by 90 degrees.
|
||||||
|
|
||||||
|
stacker: # Internal name for the Combiner
|
||||||
|
name: Combine
|
||||||
|
description: Combines both items. If they can not be merged, the right item is placed above the left item.
|
||||||
|
|
||||||
|
mixer:
|
||||||
|
name: Mix Colors
|
||||||
|
description: Mixes two colors using additive blending.
|
||||||
|
|
||||||
|
painter:
|
||||||
|
name: Dye
|
||||||
|
description: Colors the whole shape on the left input with the color from the right input.
|
||||||
|
|
||||||
|
trash: # Internal name for the destroyer
|
||||||
|
name: Destroyed
|
||||||
|
description: Accepts inputs from all sides and destroys them. Forever.
|
||||||
|
|
||||||
|
storyRewards:
|
||||||
|
# Those are the rewards gained from completing the store
|
||||||
|
reward_cutter_and_trash: Cutting Shapes
|
||||||
|
reward_rotater: Rotating
|
||||||
|
reward_painter: Painting
|
||||||
|
reward_mixer: Color Mixing
|
||||||
|
reward_stacker: Combiner
|
||||||
|
reward_splitter: Splitter/Merger
|
||||||
|
reward_tunnel: Tunnel
|
||||||
|
|
||||||
|
# Special reward, which is shown when there is no reward actually
|
||||||
|
no_reward: Next level
|
Loading…
Reference in New Issue