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");
|
||||
standalone.gulptasksStandalone($, gulp, buildFolder);
|
||||
|
||||
const translations = require("./translations");
|
||||
translations.gulptasksTranslations($, gulp, buildFolder);
|
||||
|
||||
// FIXME
|
||||
// const cordova = require("./cordova");
|
||||
// cordova.gulptasksCordova($, gulp, buildFolder);
|
||||
|
@ -74,10 +77,12 @@ standalone.gulptasksStandalone($, gulp, buildFolder);
|
|||
///////////////////// BUILD TASKS /////////////////////
|
||||
|
||||
// Cleans up everything
|
||||
gulp.task("utils.cleanup", () => {
|
||||
gulp.task("utils.cleanBuildFolder", () => {
|
||||
return gulp.src(buildFolder, { read: false }).pipe($.clean({ force: true }));
|
||||
});
|
||||
|
||||
gulp.task("utils.cleanup", $.sequence("utils.cleanBuildFolder", "translations.clear"));
|
||||
|
||||
// Requires no uncomitted files
|
||||
gulp.task("utils.requireCleanWorkingTree", cb => {
|
||||
const output = $.trim(execSync("git status -su").toString("ascii"));
|
||||
|
@ -142,6 +147,9 @@ function serve({ standalone }) {
|
|||
// Watch sound files
|
||||
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], ["sounds.dev"]);
|
||||
|
||||
// Watch translations
|
||||
gulp.watch("../translations/**/*.yaml", ["translations.convertToJson"]);
|
||||
|
||||
gulp.watch(
|
||||
["../res_raw/sounds/ui/*.mp3", "../res_raw/sounds/ui/*.wav"],
|
||||
$.sequence("sounds.encodeUi", "sounds.copy")
|
||||
|
@ -163,11 +171,15 @@ function serve({ standalone }) {
|
|||
gulp.watch("../res_built/atlas/*.json", ["imgres.atlas"]);
|
||||
|
||||
// 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) {
|
||||
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)
|
||||
if (standalone) {
|
||||
$.sequence("js.standalone-dev.watch")(() => true);
|
||||
|
@ -202,7 +214,7 @@ gulp.task("build.dev", cb => {
|
|||
"sounds.dev",
|
||||
"imgres.copyImageResources",
|
||||
"imgres.copyNonImageResources",
|
||||
"js.dev",
|
||||
"translations.fullBuild",
|
||||
"css.dev",
|
||||
"html.dev"
|
||||
)(cb);
|
||||
|
@ -216,6 +228,7 @@ gulp.task("build.standalone.dev", cb => {
|
|||
"sounds.dev",
|
||||
"imgres.copyImageResources",
|
||||
"imgres.copyNonImageResources",
|
||||
"translations.fullBuild",
|
||||
"js.standalone-dev",
|
||||
"css.dev",
|
||||
"html.standalone-dev"
|
||||
|
@ -223,7 +236,7 @@ gulp.task("build.standalone.dev", cb => {
|
|||
});
|
||||
|
||||
// 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 =>
|
||||
$.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"));
|
||||
|
||||
// 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 =>
|
||||
$.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"));
|
||||
|
||||
// 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 =>
|
||||
$.multiProcess(
|
||||
["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"));
|
||||
|
||||
// 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 =>
|
||||
$.multiProcess(
|
||||
["utils.copyAdditionalBuildFiles", "step.baseResources", "step.standalone-prod.code"],
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
"gulp-sftp": "^0.1.5",
|
||||
"gulp-terser": "^1.2.0",
|
||||
"gulp-webserver": "^0.9.1",
|
||||
"gulp-yaml": "^2.0.4",
|
||||
"imagemin-mozjpeg": "^8.0.0",
|
||||
"imagemin-pngquant": "^8.0.0",
|
||||
"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"
|
||||
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:
|
||||
version "3.0.0"
|
||||
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"
|
||||
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:
|
||||
version "3.9.1"
|
||||
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"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a"
|
||||
integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==
|
||||
|
|
|
@ -39,6 +39,13 @@
|
|||
.hotkey {
|
||||
color: lighten($colorGreenBright, 10);
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.keybinding {
|
||||
position: relative;
|
||||
@include S(margin-left, 5px);
|
||||
}
|
||||
}
|
||||
|
||||
.buildingImage {
|
||||
|
|
|
@ -66,17 +66,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.keybinding.shift {
|
||||
.keybinding.builtinKey {
|
||||
transition: all 0.1s ease-in-out;
|
||||
transition-property: background-color, color, border-color;
|
||||
background: $colorRedBright;
|
||||
border-color: $colorRedBright;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.shiftDown .keybinding.shift {
|
||||
border-color: darken($colorRedBright, 40);
|
||||
}
|
||||
}
|
||||
|
||||
body.uiHidden #ingame_HUD_KeybindingOverlay .binding:not(.hudToggle) {
|
||||
|
|
|
@ -251,9 +251,9 @@
|
|||
|
||||
@include S(padding, 15px);
|
||||
> a {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: 1fr auto;
|
||||
|
||||
justify-content: center;
|
||||
background: #fafafa;
|
||||
|
@ -280,8 +280,8 @@
|
|||
|
||||
.thirdpartyLogo {
|
||||
display: inline-block;
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
@include S(width, 50px);
|
||||
@include S(height, 50px);
|
||||
background: center center / 80% no-repeat;
|
||||
&.githubLogo {
|
||||
background-image: uiResource("main_menu/github.png");
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
translations-built
|
|
@ -76,7 +76,7 @@ export const globalConfig = {
|
|||
|
||||
debug: {
|
||||
/* dev:start */
|
||||
// fastGameEnter: true,
|
||||
fastGameEnter: true,
|
||||
noArtificialDelays: true,
|
||||
// disableSavegameWrite: true,
|
||||
showEntityBounds: false,
|
||||
|
@ -90,6 +90,7 @@ export const globalConfig = {
|
|||
allBuildingsUnlocked: true,
|
||||
upgradesNoCost: true,
|
||||
disableUnlockDialog: false,
|
||||
testTranslations: true,
|
||||
/* dev:end */
|
||||
},
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import { FormElement } from "./modal_dialog_forms";
|
|||
import { globalConfig } from "./config";
|
||||
import { getStringForKeyCode } from "../game/key_action_mapper";
|
||||
import { createLogger } from "./logging";
|
||||
import { T } from "../translations";
|
||||
|
||||
const kbEnter = 13;
|
||||
const kbCancel = 27;
|
||||
|
@ -146,8 +147,7 @@ export class Dialog {
|
|||
button.classList.add("button");
|
||||
button.classList.add("styledButton");
|
||||
button.classList.add(buttonStyle);
|
||||
// button.innerText = T.dialog_buttons[buttonId];
|
||||
button.innerText = buttonId;
|
||||
button.innerText = T.dialogs.buttons[buttonId];
|
||||
|
||||
const params = (rawParams || "").split("/");
|
||||
const useTimeout = params.indexOf("timeout") >= 0;
|
||||
|
@ -277,7 +277,7 @@ export class DialogLoading extends Dialog {
|
|||
const loader = document.createElement("div");
|
||||
loader.classList.add("prefab_LoadingTextWithAnim");
|
||||
loader.classList.add("loadingIndicator");
|
||||
loader.innerText = "Loading";
|
||||
loader.innerText = T.global.loading;
|
||||
elem.appendChild(loader);
|
||||
|
||||
this.app.inputMgr.pushReciever(this.inputReciever);
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
performanceNow,
|
||||
} from "./builtins";
|
||||
import { Vector } from "./vector";
|
||||
import { T } from "../translations";
|
||||
|
||||
// Constants
|
||||
export const TOP = new Vector(0, -1);
|
||||
|
@ -421,7 +422,7 @@ export function formatBigNumber(num, divider = ".") {
|
|||
num = Math_abs(num);
|
||||
|
||||
if (num > 1e54) {
|
||||
return sign + "inf";
|
||||
return sign + T.global.infinite;
|
||||
}
|
||||
|
||||
if (num < 10 && !Number.isInteger(num)) {
|
||||
|
@ -459,7 +460,7 @@ export function formatBigNumberFull(num, divider = ",") {
|
|||
return num + "";
|
||||
}
|
||||
if (num > 1e54) {
|
||||
return "infinite";
|
||||
return T.global.infinite;
|
||||
}
|
||||
let rest = num;
|
||||
let out = "";
|
||||
|
@ -831,24 +832,47 @@ export function formatSecondsToTimeAgo(secs) {
|
|||
|
||||
if (seconds <= 60) {
|
||||
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) {
|
||||
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) {
|
||||
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 {
|
||||
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();
|
||||
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";
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Belt";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Transports items, hold and drag to place multiple.";
|
||||
}
|
||||
|
||||
getPreviewSprite(rotationVariant) {
|
||||
switch (arrayBeltVariantToRotation[rotationVariant]) {
|
||||
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) {
|
||||
return [defaultBuildingVariant, enumCutterVariants.quad];
|
||||
}
|
||||
|
|
|
@ -20,14 +20,6 @@ export class MetaHubBuilding extends MetaBuilding {
|
|||
return "#eb5555";
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Hub";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Your central hub, deliver shapes to it to unlock new buildings.";
|
||||
}
|
||||
|
||||
isRotateable() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -13,18 +13,10 @@ export class MetaMinerBuilding extends MetaBuilding {
|
|||
super("miner");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Extract";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#b37dcd";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Place over a shape or color to extract it. Six extractors fill exactly one belt.";
|
||||
}
|
||||
|
||||
getAvailableVariants(root) {
|
||||
return [defaultBuildingVariant, enumMinerVariants.chainable];
|
||||
}
|
||||
|
|
|
@ -17,14 +17,6 @@ export class MetaMixerBuilding extends MetaBuilding {
|
|||
return new Vector(2, 1);
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Mix Colors";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Mixes two colors using additive blending.";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
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() {
|
||||
return "#cd9b7d";
|
||||
}
|
||||
|
|
|
@ -16,14 +16,6 @@ export class MetaRotaterBuilding extends MetaBuilding {
|
|||
super("rotater");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Rotate";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Rotates shapes clockwise by 90 degrees.";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#7dc6cd";
|
||||
}
|
||||
|
|
|
@ -27,18 +27,10 @@ export class MetaSplitterBuilding extends MetaBuilding {
|
|||
}
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Balancer";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#444";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Multifunctional - Evenly distributes all inputs onto all outputs.";
|
||||
}
|
||||
|
||||
getAvailableVariants(root) {
|
||||
return [defaultBuildingVariant, enumSplitterVariants.compact];
|
||||
}
|
||||
|
|
|
@ -13,18 +13,10 @@ export class MetaStackerBuilding extends MetaBuilding {
|
|||
super("stacker");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Combine";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#9fcd7d";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Combines both items. If they can not be merged, the right item is placed above the left item.";
|
||||
}
|
||||
|
||||
getDimensions() {
|
||||
return new Vector(2, 1);
|
||||
}
|
||||
|
|
|
@ -12,14 +12,6 @@ export class MetaTrashBuilding extends MetaBuilding {
|
|||
super("trash");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Destroyer";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Accepts inputs from all sides and destroys them. Forever.";
|
||||
}
|
||||
|
||||
isRotateable() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -28,18 +28,10 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding {
|
|||
super("underground_belt");
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Tunnel";
|
||||
}
|
||||
|
||||
getSilhouetteColor() {
|
||||
return "#555";
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return "Allows to tunnel resources under buildings and belts.";
|
||||
}
|
||||
|
||||
getFlipOrientationAfterPlacement() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* typehints:start */
|
||||
import { Application } from "../application";
|
||||
/* typehints:end */
|
||||
import { T } from "../translations";
|
||||
|
||||
export class GameLoadingOverlay {
|
||||
/**
|
||||
|
@ -51,7 +52,7 @@ export class GameLoadingOverlay {
|
|||
internalAddSpinnerAndText(element) {
|
||||
const inner = document.createElement("span");
|
||||
inner.classList.add("prefab_LoadingTextWithAnim");
|
||||
inner.innerText = "Loading";
|
||||
inner.innerText = T.global.loading;
|
||||
element.appendChild(inner);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { MetaBuilding, defaultBuildingVariant } from "../../meta_building";
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { Math_abs, Math_degrees, Math_radians } from "../../../core/builtins";
|
||||
import { globalConfig } from "../../../core/config";
|
||||
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||
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 { DrawParameters } from "../../../core/draw_parameters";
|
||||
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 { 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 {
|
||||
initialize() {
|
||||
|
@ -231,13 +232,16 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
|||
this.abortDragging();
|
||||
this.root.hud.signals.selectedPlacementBuildingChanged.dispatch(metaBuilding);
|
||||
if (metaBuilding) {
|
||||
this.buildingInfoElements.label.innerHTML = metaBuilding.getName();
|
||||
this.buildingInfoElements.descText.innerHTML = metaBuilding.getDescription();
|
||||
this.buildingInfoElements.label.innerHTML = T.buildings[metaBuilding.id].name;
|
||||
this.buildingInfoElements.descText.innerHTML = T.buildings[metaBuilding.id].description;
|
||||
|
||||
const binding = this.root.gameState.keyActionMapper.getBinding(
|
||||
"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;
|
||||
this.currentVariant.set(variant);
|
||||
|
@ -283,11 +287,12 @@ export class HUDBuildingPlacer extends BaseHUDPart {
|
|||
this.variantsElement,
|
||||
null,
|
||||
["explanation"],
|
||||
`
|
||||
Press <code class='keybinding'>${this.root.gameState.keyActionMapper
|
||||
.getBinding("cycle_variants")
|
||||
.getKeyCodeString()}</code> to cycle variants.
|
||||
`
|
||||
T.ingame.buildingPlacement.cycleBuildingVariants.replace(
|
||||
"<key>",
|
||||
"<code class='keybinding'>" +
|
||||
this.root.gameState.keyActionMapper.getBinding("cycle_variants").getKeyCodeString() +
|
||||
"</code>"
|
||||
)
|
||||
);
|
||||
|
||||
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 { SOUNDS } from "../../../platform/sound";
|
||||
import { enumNotificationType } from "./notifications";
|
||||
import { T } from "../../../translations";
|
||||
|
||||
export class HUDGameMenu extends BaseHUDPart {
|
||||
initialize() {}
|
||||
|
@ -16,7 +17,7 @@ export class HUDGameMenu extends BaseHUDPart {
|
|||
keybinding: "menu_open_shop",
|
||||
badge: () => this.root.hubGoals.getAvailableUpgradeCount(),
|
||||
notification: /** @type {[string, enumNotificationType]} */ ([
|
||||
"A new upgrade is available!",
|
||||
T.ingame.notifications.newUpgrade,
|
||||
enumNotificationType.upgrade,
|
||||
]),
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@ import { makeDiv } from "../../../core/utils";
|
|||
import { getStringForKeyCode } from "../../key_action_mapper";
|
||||
import { TrackedState } from "../../../core/tracked_state";
|
||||
import { queryParamOptions } from "../../../core/query_parameters";
|
||||
import { T } from "../../../translations";
|
||||
|
||||
export class HUDKeybindingOverlay extends BaseHUDPart {
|
||||
initialize() {
|
||||
|
@ -32,7 +33,7 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
|
|||
`
|
||||
<div class="binding">
|
||||
<code class="keybinding">${getKeycode("center_map")}</code>
|
||||
<label>Center</label>
|
||||
<label>${T.ingame.keybindingsOverlay.centerMap}</label>
|
||||
</div>
|
||||
|
||||
<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_down")}</code>
|
||||
<code class="keybinding">${getKeycode("map_move_right")}</code>
|
||||
<label>Move</label>
|
||||
<label>${T.ingame.keybindingsOverlay.moveMap}</label>
|
||||
</div>
|
||||
|
||||
<div class="binding noPlacementOnly">
|
||||
<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>
|
||||
<label>Delete</label>
|
||||
<label>${T.ingame.keybindingsOverlay.removeBuildings}</label>
|
||||
</div>
|
||||
|
||||
|
||||
<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>
|
||||
<label>Stop placement</label>
|
||||
<label>${T.ingame.keybindingsOverlay.stopPlacement}</label>
|
||||
</div>
|
||||
|
||||
<div class="binding placementOnly">
|
||||
<code class="keybinding">${getKeycode("rotate_while_placing")}</code>
|
||||
<label>Rotate Building</label>
|
||||
<label>${T.ingame.keybindingsOverlay.rotateBuilding}</label>
|
||||
</div>
|
||||
|
||||
<div class="binding placementOnly">
|
||||
<code class="keybinding shift">⇧ SHIFT</code>
|
||||
<label>Place Multiple</label>
|
||||
<code class="keybinding builtinKey shift">⇧ ${T.global.keys.shift}</code>
|
||||
<label>${T.ingame.keybindingsOverlay.placeMultiple}</label>
|
||||
</div>
|
||||
|
||||
<div class="binding placementOnly">
|
||||
<code class="keybinding shift">ALT</code>
|
||||
<label>Reverse orientation</label>
|
||||
<code class="keybinding builtinKey">${T.global.keys.alt}</code>
|
||||
<label>${T.ingame.keybindingsOverlay.reverseOrientation}</label>
|
||||
</div>
|
||||
|
||||
<div class="binding placementOnly">
|
||||
<code class="keybinding shift">CTRL</code>
|
||||
<label>Disable auto orientation</label>
|
||||
<code class="keybinding builtinKey">${T.global.keys.control}</code>
|
||||
<label>${T.ingame.keybindingsOverlay.disableAutoOrientation}</label>
|
||||
</div>
|
||||
` +
|
||||
(queryParamOptions.betaMode
|
||||
? `
|
||||
<div class="binding hudToggle">
|
||||
<code class="keybinding">F2</code>
|
||||
<label>Toggle HUD</label>
|
||||
<label>${T.ingame.keybindingsOverlay.toggleHud}</label>
|
||||
</div>
|
||||
`
|
||||
: "")
|
||||
|
|
|
@ -9,6 +9,7 @@ import { makeDiv } from "../../../core/utils";
|
|||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { createLogger } from "../../../core/logging";
|
||||
import { enumMouseButton } from "../../camera";
|
||||
import { T } from "../../../translations";
|
||||
|
||||
const logger = createLogger("hud/mass_selector");
|
||||
|
||||
|
@ -23,10 +24,9 @@ export class HUDMassSelector extends BaseHUDPart {
|
|||
parent,
|
||||
"ingame_HUD_MassSelector",
|
||||
[],
|
||||
`
|
||||
Press <code class="keybinding">${removalKeybinding}</code> to remove selected buildings
|
||||
and <code class="keybinding">${abortKeybinding}</code> to cancel.
|
||||
`
|
||||
T.ingame.massDelete.infoText
|
||||
.replace("<keyDelete>", removalKeybinding)
|
||||
.replace("<keyCancel>", abortKeybinding)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,22 +80,6 @@ export class HUDModalDialogs extends BaseHUDPart {
|
|||
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) {
|
||||
const dialog = new DialogOptionChooser({
|
||||
app: this.app,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { T } from "../../../translations";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumNotificationType = {
|
||||
|
@ -23,7 +24,7 @@ export class HUDNotifications extends BaseHUDPart {
|
|||
|
||||
// Automatic notifications
|
||||
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 { makeDiv } from "../../../core/utils";
|
||||
import { makeDiv, formatSeconds } from "../../../core/utils";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { KeyActionMapper } from "../../key_action_mapper";
|
||||
import { T } from "../../../translations";
|
||||
|
||||
export class HUDSettingsMenu extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
|
@ -14,18 +15,18 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
|||
this.background,
|
||||
null,
|
||||
["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"]);
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
title: "Continue",
|
||||
title: T.ingame.settingsMenu.buttons.continue,
|
||||
action: () => this.close(),
|
||||
},
|
||||
{
|
||||
title: "Return to menu",
|
||||
title: T.ingame.settingsMenu.buttons.menu,
|
||||
action: () => this.returnToMenu(),
|
||||
},
|
||||
];
|
||||
|
@ -79,9 +80,8 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
|||
// this.background.classList.add("visible");
|
||||
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
||||
|
||||
const totalMinutesPlayed = Math.ceil(this.root.time.now() / 60.0);
|
||||
const playtimeString = totalMinutesPlayed === 1 ? "1 minute" : totalMinutesPlayed + " minutes";
|
||||
this.timePlayed.querySelector(".playtime").innerText = playtimeString;
|
||||
const totalSecondsPlayed = Math.ceil(this.root.time.now());
|
||||
this.timePlayed.querySelector(".playtime").innerText = formatSeconds(totalSecondsPlayed);
|
||||
}
|
||||
|
||||
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 { 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 {
|
||||
createElements(parent) {
|
||||
|
@ -14,7 +14,7 @@ export class HUDShop extends BaseHUDPart {
|
|||
|
||||
// DIALOG Inner / Wrapper
|
||||
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.trackClicks(this.closeButton, this.close);
|
||||
this.contentDiv = makeDiv(this.dialogInner, null, ["content"]);
|
||||
|
@ -23,7 +23,6 @@ export class HUDShop extends BaseHUDPart {
|
|||
|
||||
// Upgrades
|
||||
for (const upgradeId in UPGRADES) {
|
||||
const { label } = UPGRADES[upgradeId];
|
||||
const handle = {};
|
||||
handle.requireIndexToElement = [];
|
||||
|
||||
|
@ -32,10 +31,10 @@ export class HUDShop extends BaseHUDPart {
|
|||
handle.elem.setAttribute("data-upgrade-id", upgradeId);
|
||||
|
||||
// Title
|
||||
const title = makeDiv(handle.elem, null, ["title"], label);
|
||||
const title = makeDiv(handle.elem, null, ["title"], T.shopUpgrades[upgradeId].name);
|
||||
|
||||
// Title > Tier
|
||||
handle.elemTierLabel = makeDiv(title, null, ["tier"], "Tier ?");
|
||||
handle.elemTierLabel = makeDiv(title, null, ["tier"]);
|
||||
|
||||
// Icon
|
||||
handle.icon = makeDiv(handle.elem, null, ["icon"]);
|
||||
|
@ -48,7 +47,7 @@ export class HUDShop extends BaseHUDPart {
|
|||
// Buy button
|
||||
handle.buyButton = document.createElement("button");
|
||||
handle.buyButton.classList.add("buy", "styledButton");
|
||||
handle.buyButton.innerText = "Upgrade";
|
||||
handle.buyButton.innerText = T.ingame.shop.buttonUnlock;
|
||||
handle.elem.appendChild(handle.buyButton);
|
||||
|
||||
this.trackClicks(handle.buyButton, () => this.tryUnlockNextTier(upgradeId));
|
||||
|
@ -61,13 +60,17 @@ export class HUDShop extends BaseHUDPart {
|
|||
rerenderFull() {
|
||||
for (const upgradeId in this.upgradeToElements) {
|
||||
const handle = this.upgradeToElements[upgradeId];
|
||||
const { description, tiers } = UPGRADES[upgradeId];
|
||||
const { tiers } = UPGRADES[upgradeId];
|
||||
|
||||
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||
const tierHandle = tiers[currentTier];
|
||||
|
||||
// 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);
|
||||
|
||||
// Cleanup detectors
|
||||
|
@ -84,12 +87,15 @@ export class HUDShop extends BaseHUDPart {
|
|||
|
||||
if (!tierHandle) {
|
||||
// Max level
|
||||
handle.elemDescription.innerText = "Maximum level";
|
||||
handle.elemDescription.innerText = T.ingame.shop.maximumLevel;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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 }) => {
|
||||
const container = makeDiv(handle.elemRequirements, null, ["requirement"]);
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
import { Math_min } from "../../../core/builtins";
|
||||
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 { enumAnalyticsDataSource } from "../../production_analytics";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { enumDisplayMode, HUDShapeStatisticsHandle } from "./statistics_handle";
|
||||
|
||||
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.",
|
||||
};
|
||||
import { T } from "../../../translations";
|
||||
|
||||
export class HUDStatistics extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
|
@ -20,7 +14,7 @@ export class HUDStatistics extends BaseHUDPart {
|
|||
|
||||
// DIALOG Inner / Wrapper
|
||||
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.trackClicks(this.closeButton, this.close);
|
||||
|
||||
|
@ -30,13 +24,21 @@ export class HUDStatistics extends BaseHUDPart {
|
|||
this.filtersDataSource = makeDiv(this.filterHeader, null, ["filtersDataSource"]);
|
||||
this.filtersDisplayMode = makeDiv(this.filterHeader, null, ["filtersDisplayMode"]);
|
||||
|
||||
const buttonModeProduced = makeButton(this.filtersDataSource, ["modeProduced"], "Produced");
|
||||
const buttonModeDelivered = makeButton(this.filtersDataSource, ["modeDelivered"], "Delivered");
|
||||
const buttonModeStored = makeButton(this.filtersDataSource, ["modeStored"], "Stored");
|
||||
const dataSources = [
|
||||
enumAnalyticsDataSource.produced,
|
||||
enumAnalyticsDataSource.delivered,
|
||||
enumAnalyticsDataSource.stored,
|
||||
];
|
||||
|
||||
this.trackClicks(buttonModeProduced, () => this.setDataSource(enumAnalyticsDataSource.produced));
|
||||
this.trackClicks(buttonModeStored, () => this.setDataSource(enumAnalyticsDataSource.stored));
|
||||
this.trackClicks(buttonModeDelivered, () => this.setDataSource(enumAnalyticsDataSource.delivered));
|
||||
for (let i = 0; i < dataSources.length; ++i) {
|
||||
const dataSource = dataSources[i];
|
||||
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 buttonDisplayIcons = makeButton(this.filtersDisplayMode, ["displayIcons"]);
|
||||
|
@ -54,7 +56,7 @@ export class HUDStatistics extends BaseHUDPart {
|
|||
this.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) {
|
||||
this.rerenderFull();
|
||||
}
|
||||
|
@ -204,7 +206,7 @@ export class HUDStatistics extends BaseHUDPart {
|
|||
|
||||
if (entries.length === 0) {
|
||||
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);
|
||||
|
|
|
@ -4,6 +4,7 @@ import { enumAnalyticsDataSource } from "../../production_analytics";
|
|||
import { formatBigNumber, clamp } from "../../../core/utils";
|
||||
import { globalConfig } from "../../../core/config";
|
||||
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
||||
import { T } from "../../../translations";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumDisplayMode = {
|
||||
|
@ -86,7 +87,10 @@ export class HUDShapeStatisticsHandle {
|
|||
(this.root.productionAnalytics.getCurrentShapeRate(dataSource, this.definition) /
|
||||
globalConfig.analyticsSliceDurationSeconds) *
|
||||
60;
|
||||
this.counter.innerText = formatBigNumber(rate) + " / m";
|
||||
this.counter.innerText = T.ingame.statistics.shapesPerMinute.replace(
|
||||
"<shapes>",
|
||||
formatBigNumber(rate)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,10 @@ import { MetaSplitterBuilding } from "../../buildings/splitter";
|
|||
import { MetaStackerBuilding } from "../../buildings/stacker";
|
||||
import { MetaTrashBuilding } from "../../buildings/trash";
|
||||
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
|
||||
import { enumHubGoalRewards, enumHubGoalRewardToString } from "../../tutorial_goals";
|
||||
import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { T } from "../../../translations";
|
||||
|
||||
export class HUDUnlockNotification extends BaseHUDPart {
|
||||
initialize() {
|
||||
|
@ -36,17 +37,10 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
|||
|
||||
const dialog = makeDiv(this.element, null, ["dialog"]);
|
||||
|
||||
this.elemTitle = makeDiv(dialog, null, ["title"], ``);
|
||||
this.elemSubTitle = makeDiv(dialog, null, ["subTitle"], `Completed`);
|
||||
this.elemTitle = makeDiv(dialog, null, ["title"]);
|
||||
this.elemSubTitle = makeDiv(dialog, null, ["subTitle"], T.ingame.levelCompleteNotification.completed);
|
||||
|
||||
this.elemContents = makeDiv(
|
||||
dialog,
|
||||
null,
|
||||
["contents"],
|
||||
`
|
||||
Ready for the next one?
|
||||
`
|
||||
);
|
||||
this.elemContents = makeDiv(dialog, null, ["contents"]);
|
||||
|
||||
this.btnClose = document.createElement("button");
|
||||
this.btnClose.classList.add("close", "styledButton");
|
||||
|
@ -61,9 +55,17 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
|||
* @param {enumHubGoalRewards} 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 metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
|
||||
|
|
|
@ -6,6 +6,7 @@ import { Application } from "../application";
|
|||
|
||||
import { Signal, STOP_PROPAGATION } from "../core/signal";
|
||||
import { IS_MOBILE } from "../core/config";
|
||||
import { T } from "../translations";
|
||||
|
||||
function key(str) {
|
||||
return str.toUpperCase().charCodeAt(0);
|
||||
|
@ -65,23 +66,23 @@ export function getStringForKeyCode(code) {
|
|||
case 8:
|
||||
return "⌫";
|
||||
case 9:
|
||||
return "TAB";
|
||||
return T.global.keys.tab;
|
||||
case 13:
|
||||
return "⏎";
|
||||
case 16:
|
||||
return "⇪";
|
||||
case 17:
|
||||
return "CTRL";
|
||||
return T.global.keys.control;
|
||||
case 18:
|
||||
return "ALT";
|
||||
return T.global.keys.alt;
|
||||
case 19:
|
||||
return "PAUSE";
|
||||
case 20:
|
||||
return "CAPS";
|
||||
case 27:
|
||||
return "ESC";
|
||||
return T.global.keys.escape;
|
||||
case 32:
|
||||
return "SPACE";
|
||||
return T.global.keys.space;
|
||||
case 33:
|
||||
return "PGUP";
|
||||
case 34:
|
||||
|
|
|
@ -31,20 +31,6 @@ export class MetaBuilding {
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -3,8 +3,8 @@ import { HubComponent } from "../components/hub";
|
|||
import { DrawParameters } from "../../core/draw_parameters";
|
||||
import { Entity } from "../entity";
|
||||
import { formatBigNumber } from "../../core/utils";
|
||||
import { enumHubGoalRewardToString } from "../tutorial_goals";
|
||||
import { Loader } from "../../core/loader";
|
||||
import { T } from "../../translations";
|
||||
|
||||
export class HubSystem extends GameSystemWithFilter {
|
||||
constructor(root) {
|
||||
|
@ -84,7 +84,7 @@ export class HubSystem extends GameSystemWithFilter {
|
|||
context.font = "bold 11px GameFont";
|
||||
context.fillStyle = "#fd0752";
|
||||
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
|
||||
context.font = "bold 11px GameFont";
|
||||
|
|
|
@ -15,21 +15,6 @@ export const enumHubGoalRewards = {
|
|||
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 = [
|
||||
// Circle
|
||||
{
|
||||
|
|
|
@ -1,33 +1,8 @@
|
|||
import { findNiceIntegerValue } from "../core/utils";
|
||||
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 = {
|
||||
belt: {
|
||||
label: "Belts, Distributer & Tunnels",
|
||||
description: improvement => "Speed +" + Math.floor(improvement * 100.0) + "%",
|
||||
tiers: [
|
||||
{
|
||||
required: [{ shape: "CuCuCuCu", amount: 80 }],
|
||||
|
@ -49,8 +24,6 @@ export const UPGRADES = {
|
|||
},
|
||||
|
||||
miner: {
|
||||
label: "Extraction",
|
||||
description: improvement => "Speed +" + Math.floor(improvement * 100.0) + "%",
|
||||
tiers: [
|
||||
{
|
||||
required: [{ shape: "RuRuRuRu", amount: 200 }],
|
||||
|
@ -72,8 +45,6 @@ export const UPGRADES = {
|
|||
},
|
||||
|
||||
processors: {
|
||||
label: "Shape Processing",
|
||||
description: improvement => "Speed +" + Math.floor(improvement * 100.0) + "%",
|
||||
tiers: [
|
||||
{
|
||||
required: [{ shape: "SuSuSuSu", amount: 200 }],
|
||||
|
@ -95,8 +66,6 @@ export const UPGRADES = {
|
|||
},
|
||||
|
||||
painting: {
|
||||
label: "Mixing & Painting",
|
||||
description: improvement => "Speed +" + Math.floor(improvement * 100.0) + "%",
|
||||
tiers: [
|
||||
{
|
||||
required: [{ shape: "WuWuWuWu", amount: 200 }],
|
||||
|
|
|
@ -7,6 +7,7 @@ import { createLogger } from "../../core/logging";
|
|||
import { ClickDetector } from "../../core/click_detector";
|
||||
import { performanceNow } from "../../core/builtins";
|
||||
import { clamp } from "../../core/utils";
|
||||
import { T } from "../../translations";
|
||||
|
||||
const logger = createLogger("adprovider/adinplay");
|
||||
|
||||
|
@ -111,7 +112,7 @@ export class AdinplayAdProvider extends AdProviderInterface {
|
|||
AD_HEIGHT: h,
|
||||
AD_FULLSCREEN: false,
|
||||
AD_CENTERPLAYER: false,
|
||||
LOADING_TEXT: "Loading",
|
||||
LOADING_TEXT: T.global.loading,
|
||||
PREROLL_ELEM: function () {
|
||||
return videoElement;
|
||||
},
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
} from "../core/utils";
|
||||
import { ReadWriteProxy } from "../core/read_write_proxy";
|
||||
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
||||
import { T } from "../translations";
|
||||
|
||||
export class MainMenuState extends GameState {
|
||||
constructor() {
|
||||
|
@ -18,14 +19,12 @@ export class MainMenuState extends GameState {
|
|||
|
||||
getInnerHTML() {
|
||||
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>
|
||||
<li>No advertisements and demo banners.</li>
|
||||
<li>Unlimited savegame slots.</li>
|
||||
<li>Supporting the developer ❤️</li>
|
||||
${T.demoBanners.advantages.map(advantage => `<li>${advantage}</li>`).join("")}
|
||||
</ul>
|
||||
|
||||
<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()
|
||||
? ""
|
||||
: `
|
||||
<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="importButton styledButton">Import savegame</button>
|
||||
<button class="playButton styledButton">${T.mainMenu.play}</button>
|
||||
<button class="importButton styledButton">${T.mainMenu.importSavegame}</button>
|
||||
</div>
|
||||
|
||||
${
|
||||
|
@ -86,12 +85,12 @@ export class MainMenuState extends GameState {
|
|||
<div class="footer">
|
||||
|
||||
<a href="https://github.com/tobspr/shapez.io" target="_blank">
|
||||
This game is open source!
|
||||
${T.mainMenu.openSourceHint}
|
||||
<span class="thirdpartyLogo githubLogo"></span>
|
||||
</a>
|
||||
|
||||
<a href="https://discord.gg/HN7EVzV" target="_blank">
|
||||
Official discord server
|
||||
${T.mainMenu.discordLink}
|
||||
<span class="thirdpartyLogo discordLogo"></span>
|
||||
</a>
|
||||
|
||||
|
@ -112,7 +111,6 @@ export class MainMenuState extends GameState {
|
|||
const reader = new FileReader();
|
||||
reader.addEventListener("load", event => {
|
||||
const contents = event.target.result;
|
||||
|
||||
let realContent;
|
||||
|
||||
try {
|
||||
|
@ -120,8 +118,8 @@ export class MainMenuState extends GameState {
|
|||
} catch (err) {
|
||||
closeLoader();
|
||||
this.dialogs.showWarning(
|
||||
"Import error",
|
||||
"Failed to import your savegame:<br><br>" + err
|
||||
T.dialogs.importSavegameError.title,
|
||||
T.dialogs.importSavegameError.text + "<br><br>" + err
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -129,22 +127,27 @@ export class MainMenuState extends GameState {
|
|||
this.app.savegameMgr.importSavegame(realContent).then(
|
||||
() => {
|
||||
closeLoader();
|
||||
this.dialogs.showWarning("Imported", "Your savegame has been imported.");
|
||||
this.dialogs.showWarning(
|
||||
T.dialogs.importSavegameSuccess.title,
|
||||
T.dialogs.importSavegameSuccess.text
|
||||
);
|
||||
|
||||
this.renderSavegames();
|
||||
},
|
||||
err => {
|
||||
closeLoader();
|
||||
this.dialogs.showWarning(
|
||||
"Import error",
|
||||
"Failed to import savegame. Please check the console output."
|
||||
T.dialogs.importSavegameError.title,
|
||||
T.dialogs.importSavegameError.text + ":<br><br>" + err
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
reader.addEventListener("error", error => {
|
||||
console.error(error);
|
||||
alert("Failed to read file: " + error);
|
||||
this.dialogs.showWarning(
|
||||
T.dialogs.importSavegameError.title,
|
||||
T.dialogs.importSavegameError.text + ":<br><br>" + error
|
||||
);
|
||||
});
|
||||
reader.readAsText(file, "utf-8");
|
||||
});
|
||||
|
@ -159,7 +162,10 @@ export class MainMenuState extends GameState {
|
|||
|
||||
onEnter(payload) {
|
||||
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);
|
||||
|
@ -244,8 +250,8 @@ export class MainMenuState extends GameState {
|
|||
*/
|
||||
deleteGame(game) {
|
||||
const signals = this.dialogs.showWarning(
|
||||
"Confirm Deletion",
|
||||
"Are you sure you want to delete the game?",
|
||||
T.dialogs.confirmSavegameDelete.title,
|
||||
T.dialogs.confirmSavegameDelete.text,
|
||||
["delete:bad", "cancel:good"]
|
||||
);
|
||||
|
||||
|
@ -255,7 +261,10 @@ export class MainMenuState extends GameState {
|
|||
this.renderSavegames();
|
||||
},
|
||||
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