diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile new file mode 100644 index 00000000..41956947 --- /dev/null +++ b/.gitpod.Dockerfile @@ -0,0 +1,4 @@ +FROM gitpod/workspace-full + +RUN sudo apt-get update \ + && sudo apt install ffmpeg -yq diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000..18373c95 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,10 @@ +image: + file: .gitpod.Dockerfile +tasks: + - init: yarn && gp sync-done boot + - before: cd gulp + init: gp sync-await boot && yarn + command: yarn gulp +ports: + - port: 3005 + onOpen: open-preview diff --git a/README.md b/README.md index 00e57ecc..85b5d26b 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,16 @@ Your goal is to produce shapes by cutting, rotating, merging and painting parts **Notice**: This will produce a debug build with several debugging flags enabled. If you want to disable them, modify [`src/js/core/config.js`](src/js/core/config.js). +## Build Online with one-click setup + +You can use [Gitpod](https://www.gitpod.io/) (an Online Open Source VS Code-like IDE which is free for Open Source) for working on issues and making PRs to this project. With a single click it will start a workspace and automatically: + +- clone the `shapez.io` repo. +- install all of the dependencies. +- start `gulp` in `gulp/` directory. + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/from-referrer/) + ## Helping translate Please checkout the [Translations readme](translations/). diff --git a/gulp/gulpfile.js b/gulp/gulpfile.js index 7ac426a1..7b0416ca 100644 --- a/gulp/gulpfile.js +++ b/gulp/gulpfile.js @@ -71,10 +71,6 @@ releaseUploader.gulptasksReleaseUploader($, gulp, buildFolder); const translations = require("./translations"); translations.gulptasksTranslations($, gulp, buildFolder); -// FIXME -// const cordova = require("./cordova"); -// cordova.gulptasksCordova($, gulp, buildFolder); - ///////////////////// BUILD TASKS ///////////////////// // Cleans up everything diff --git a/res/ui/building_tutorials/virtual_processor-rotater.png b/res/ui/building_tutorials/virtual_processor-rotater.png index 61f8e866..752d21f8 100644 Binary files a/res/ui/building_tutorials/virtual_processor-rotater.png and b/res/ui/building_tutorials/virtual_processor-rotater.png differ diff --git a/res/ui/interactive_tutorial.noinline/21_1_place_quad_painter.gif b/res/ui/interactive_tutorial.noinline/21_1_place_quad_painter.gif new file mode 100644 index 00000000..ea854cf2 Binary files /dev/null and b/res/ui/interactive_tutorial.noinline/21_1_place_quad_painter.gif differ diff --git a/res/ui/interactive_tutorial.noinline/21_2_switch_to_wires.gif b/res/ui/interactive_tutorial.noinline/21_2_switch_to_wires.gif new file mode 100644 index 00000000..78ab6fd2 Binary files /dev/null and b/res/ui/interactive_tutorial.noinline/21_2_switch_to_wires.gif differ diff --git a/res/ui/interactive_tutorial.noinline/21_3_place_button.gif b/res/ui/interactive_tutorial.noinline/21_3_place_button.gif new file mode 100644 index 00000000..52ffb076 Binary files /dev/null and b/res/ui/interactive_tutorial.noinline/21_3_place_button.gif differ diff --git a/res/ui/interactive_tutorial.noinline/21_4_press_button.gif b/res/ui/interactive_tutorial.noinline/21_4_press_button.gif new file mode 100644 index 00000000..5d79f1e3 Binary files /dev/null and b/res/ui/interactive_tutorial.noinline/21_4_press_button.gif differ diff --git a/res/ui/interactive_tutorial.noinline/2_1_place_cutter.gif b/res/ui/interactive_tutorial.noinline/2_1_place_cutter.gif new file mode 100644 index 00000000..1678c0b2 Binary files /dev/null and b/res/ui/interactive_tutorial.noinline/2_1_place_cutter.gif differ diff --git a/res/ui/interactive_tutorial.noinline/2_2_place_trash.gif b/res/ui/interactive_tutorial.noinline/2_2_place_trash.gif new file mode 100644 index 00000000..0d60fa9f Binary files /dev/null and b/res/ui/interactive_tutorial.noinline/2_2_place_trash.gif differ diff --git a/res/ui/interactive_tutorial.noinline/2_3_more_cutters.gif b/res/ui/interactive_tutorial.noinline/2_3_more_cutters.gif new file mode 100644 index 00000000..50ce88f9 Binary files /dev/null and b/res/ui/interactive_tutorial.noinline/2_3_more_cutters.gif differ diff --git a/res/ui/interactive_tutorial.noinline/3_1_rectangles.gif b/res/ui/interactive_tutorial.noinline/3_1_rectangles.gif new file mode 100644 index 00000000..418d3123 Binary files /dev/null and b/res/ui/interactive_tutorial.noinline/3_1_rectangles.gif differ diff --git a/res/ui/languages/da.svg b/res/ui/languages/da.svg index ea9d950a..b6ace9ab 100644 --- a/res/ui/languages/da.svg +++ b/res/ui/languages/da.svg @@ -1,36 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res_raw/sprites/buildings/underground_belt_exit-tier2.png b/res_raw/sprites/buildings/underground_belt_exit-tier2.png index e3c8df88..2ee15c61 100644 Binary files a/res_raw/sprites/buildings/underground_belt_exit-tier2.png and b/res_raw/sprites/buildings/underground_belt_exit-tier2.png differ diff --git a/src/css/ingame_hud/buildings_toolbar.scss b/src/css/ingame_hud/buildings_toolbar.scss index a20626af..54205d64 100644 --- a/src/css/ingame_hud/buildings_toolbar.scss +++ b/src/css/ingame_hud/buildings_toolbar.scss @@ -27,7 +27,7 @@ @include S(border-radius, $globalBorderRadius); @include DarkThemeOverride { - background-color: rgba(darken($darkModeGameBackground, 15), 0.4); + background-color: rgba(darken($darkModeGameBackground, 15), 0.95); } &.secondary { diff --git a/src/css/ingame_hud/interactive_tutorial.scss b/src/css/ingame_hud/interactive_tutorial.scss index 9d4aeffc..45750b04 100644 --- a/src/css/ingame_hud/interactive_tutorial.scss +++ b/src/css/ingame_hud/interactive_tutorial.scss @@ -56,8 +56,9 @@ .helperGif { @include S(margin-top, 5px); + @include S(width, 150px); @include S(height, 150px); - background: center center / contain no-repeat; + background: center center / cover no-repeat; transition: opacity 0.1s ease-out; } } diff --git a/src/css/ingame_hud/unlock_notification.scss b/src/css/ingame_hud/unlock_notification.scss index 431259f0..828c55a9 100644 --- a/src/css/ingame_hud/unlock_notification.scss +++ b/src/css/ingame_hud/unlock_notification.scss @@ -4,9 +4,7 @@ left: 0; right: 0; bottom: 0; - display: flex; - justify-content: center; - align-items: center; + overflow: auto; pointer-events: all; & { @@ -33,7 +31,6 @@ display: flex; align-items: center; flex-direction: column; - max-height: 100vh; color: #fff; text-align: center; diff --git a/src/css/main.scss b/src/css/main.scss index 5c4686e9..4f6a771e 100644 --- a/src/css/main.scss +++ b/src/css/main.scss @@ -73,8 +73,8 @@ ingame_HUD_KeybindingOverlay, ingame_HUD_Notifications, ingame_HUD_DebugInfo, ingame_HUD_EntityDebugger, -ingame_HUD_InteractiveTutorial, ingame_HUD_TutorialHints, +ingame_HUD_InteractiveTutorial, ingame_HUD_BuildingsToolbar, ingame_HUD_wires_toolbar, ingame_HUD_BlueprintPlacer, diff --git a/src/js/changelog.js b/src/js/changelog.js index 95aca51d..84f0bc07 100644 --- a/src/js/changelog.js +++ b/src/js/changelog.js @@ -1,4 +1,13 @@ export const CHANGELOG = [ + { + version: "1.2.1", + date: "unreleased", + entries: [ + "Fixed stacking bug for level 26 which required restarting the game", + "Fix reward notification being too long sometimes (by LeopoldTal)", + "Updated translations", + ], + }, { version: "1.2.0", date: "09.10.2020", diff --git a/src/js/core/click_detector.js b/src/js/core/click_detector.js index ea6abf48..fb62f0f1 100644 --- a/src/js/core/click_detector.js +++ b/src/js/core/click_detector.js @@ -1,467 +1,465 @@ -import { createLogger } from "../core/logging"; -import { Signal } from "../core/signal"; -import { fastArrayDelete, fastArrayDeleteValueIfContained } from "./utils"; -import { Vector } from "./vector"; -import { IS_MOBILE, SUPPORT_TOUCH } from "./config"; -import { SOUNDS } from "../platform/sound"; -import { GLOBAL_APP } from "./globals"; - -const logger = createLogger("click_detector"); - -export const MAX_MOVE_DISTANCE_PX = IS_MOBILE ? 20 : 80; - -// For debugging -const registerClickDetectors = G_IS_DEV && true; -if (registerClickDetectors) { - /** @type {Array} */ - window.activeClickDetectors = []; -} - -// Store active click detectors so we can cancel them -/** @type {Array} */ -const ongoingClickDetectors = []; - -// Store when the last touch event was registered, to avoid accepting a touch *and* a click event - -export let clickDetectorGlobals = { - lastTouchTime: -1000, -}; - -/** - * Click detector creation payload typehints - * @typedef {{ - * consumeEvents?: boolean, - * preventDefault?: boolean, - * applyCssClass?: string, - * captureTouchmove?: boolean, - * targetOnly?: boolean, - * maxDistance?: number, - * clickSound?: string, - * preventClick?: boolean, - * }} ClickDetectorConstructorArgs - */ - -// Detects clicks -export class ClickDetector { - /** - * - * @param {Element} element - * @param {object} param1 - * @param {boolean=} param1.consumeEvents Whether to call stopPropagation - * (Useful for nested elements where the parent has a click handler as wel) - * @param {boolean=} param1.preventDefault Whether to call preventDefault (Usually makes the handler faster) - * @param {string=} param1.applyCssClass The css class to add while the element is pressed - * @param {boolean=} param1.captureTouchmove Whether to capture touchmove events as well - * @param {boolean=} param1.targetOnly Whether to also accept clicks on child elements (e.target !== element) - * @param {number=} param1.maxDistance The maximum distance in pixels to accept clicks - * @param {string=} param1.clickSound Sound key to play on touchdown - * @param {boolean=} param1.preventClick Whether to prevent click events - */ - constructor( - element, - { - consumeEvents = false, - preventDefault = true, - applyCssClass = "pressed", - captureTouchmove = false, - targetOnly = false, - maxDistance = MAX_MOVE_DISTANCE_PX, - clickSound = SOUNDS.uiClick, - preventClick = false, - } - ) { - assert(element, "No element given!"); - this.clickDownPosition = null; - - this.consumeEvents = consumeEvents; - this.preventDefault = preventDefault; - this.applyCssClass = applyCssClass; - this.captureTouchmove = captureTouchmove; - this.targetOnly = targetOnly; - this.clickSound = clickSound; - this.maxDistance = maxDistance; - this.preventClick = preventClick; - - // Signals - this.click = new Signal(); - this.rightClick = new Signal(); - this.touchstart = new Signal(); - this.touchmove = new Signal(); - this.touchend = new Signal(); - this.touchcancel = new Signal(); - - // Simple signals which just receive the touch position - this.touchstartSimple = new Signal(); - this.touchmoveSimple = new Signal(); - this.touchendSimple = new Signal(); - - // Store time of touch start - this.clickStartTime = null; - - // A click can be cancelled if another detector registers a click - this.cancelled = false; - - this.internalBindTo(/** @type {HTMLElement} */ (element)); - } - - /** - * Cleans up all event listeners of this detector - */ - cleanup() { - if (this.element) { - if (registerClickDetectors) { - const index = window.activeClickDetectors.indexOf(this); - if (index < 0) { - logger.error("Click detector cleanup but is not active"); - } else { - window.activeClickDetectors.splice(index, 1); - } - } - const options = this.internalGetEventListenerOptions(); - - if (SUPPORT_TOUCH) { - this.element.removeEventListener("touchstart", this.handlerTouchStart, options); - this.element.removeEventListener("touchend", this.handlerTouchEnd, options); - this.element.removeEventListener("touchcancel", this.handlerTouchCancel, options); - } - - this.element.removeEventListener("mouseup", this.handlerTouchStart, options); - this.element.removeEventListener("mousedown", this.handlerTouchEnd, options); - this.element.removeEventListener("mouseout", this.handlerTouchCancel, options); - - if (this.captureTouchmove) { - if (SUPPORT_TOUCH) { - this.element.removeEventListener("touchmove", this.handlerTouchMove, options); - } - this.element.removeEventListener("mousemove", this.handlerTouchMove, options); - } - - if (this.preventClick) { - this.element.removeEventListener("click", this.handlerPreventClick, options); - } - - this.click.removeAll(); - this.touchstart.removeAll(); - this.touchmove.removeAll(); - this.touchend.removeAll(); - this.touchcancel.removeAll(); - - // TODO: Remove pointer captures - - this.element = null; - } - } - - // INTERNAL METHODS - - /** - * - * @param {Event} event - */ - internalPreventClick(event) { - window.focus(); - event.preventDefault(); - } - - /** - * Internal method to get the options to pass to an event listener - */ - internalGetEventListenerOptions() { - return { - capture: this.consumeEvents, - passive: !this.preventDefault, - }; - } - - /** - * Binds the click detector to an element - * @param {HTMLElement} element - */ - internalBindTo(element) { - const options = this.internalGetEventListenerOptions(); - - this.handlerTouchStart = this.internalOnPointerDown.bind(this); - this.handlerTouchEnd = this.internalOnPointerEnd.bind(this); - this.handlerTouchMove = this.internalOnPointerMove.bind(this); - this.handlerTouchCancel = this.internalOnTouchCancel.bind(this); - - if (this.preventClick) { - this.handlerPreventClick = this.internalPreventClick.bind(this); - element.addEventListener("click", this.handlerPreventClick, options); - } - - if (SUPPORT_TOUCH) { - element.addEventListener("touchstart", this.handlerTouchStart, options); - element.addEventListener("touchend", this.handlerTouchEnd, options); - element.addEventListener("touchcancel", this.handlerTouchCancel, options); - } - - element.addEventListener("mousedown", this.handlerTouchStart, options); - element.addEventListener("mouseup", this.handlerTouchEnd, options); - element.addEventListener("mouseout", this.handlerTouchCancel, options); - - if (this.captureTouchmove) { - if (SUPPORT_TOUCH) { - element.addEventListener("touchmove", this.handlerTouchMove, options); - } - element.addEventListener("mousemove", this.handlerTouchMove, options); - } - - if (registerClickDetectors) { - window.activeClickDetectors.push(this); - } - this.element = element; - } - - /** - * Returns if the bound element is currently in the DOM. - */ - internalIsDomElementAttached() { - return this.element && document.documentElement.contains(this.element); - } - - /** - * Checks if the given event is relevant for this detector - * @param {TouchEvent|MouseEvent} event - */ - internalEventPreHandler(event, expectedRemainingTouches = 1) { - if (!this.element) { - // Already cleaned up - return false; - } - - if (this.targetOnly && event.target !== this.element) { - // Clicked a child element - return false; - } - - // Stop any propagation and defaults if configured - if (this.consumeEvents && event.cancelable) { - event.stopPropagation(); - } - - if (this.preventDefault && event.cancelable) { - event.preventDefault(); - } - - if (window.TouchEvent && event instanceof TouchEvent) { - clickDetectorGlobals.lastTouchTime = performance.now(); - - // console.log("Got touches", event.targetTouches.length, "vs", expectedRemainingTouches); - if (event.targetTouches.length !== expectedRemainingTouches) { - return false; - } - } - - if (event instanceof MouseEvent) { - if (performance.now() - clickDetectorGlobals.lastTouchTime < 1000.0) { - return false; - } - } - - return true; - } - - /** - * Extracts the mous position from an event - * @param {TouchEvent|MouseEvent} event - * @returns {Vector} The client space position - */ - static extractPointerPosition(event) { - if (window.TouchEvent && event instanceof TouchEvent) { - if (event.changedTouches.length !== 1) { - logger.warn( - "Got unexpected target touches:", - event.targetTouches.length, - "->", - event.targetTouches - ); - return new Vector(0, 0); - } - - const touch = event.changedTouches[0]; - return new Vector(touch.clientX, touch.clientY); - } - - if (event instanceof MouseEvent) { - return new Vector(event.clientX, event.clientY); - } - - assertAlways(false, "Got unknown event: " + event); - - return new Vector(0, 0); - } - - /** - * Cacnels all ongoing events on this detector - */ - cancelOngoingEvents() { - if (this.applyCssClass && this.element) { - this.element.classList.remove(this.applyCssClass); - } - this.clickDownPosition = null; - this.clickStartTime = null; - this.cancelled = true; - fastArrayDeleteValueIfContained(ongoingClickDetectors, this); - } - - /** - * Internal pointer down handler - * @param {TouchEvent|MouseEvent} event - */ - internalOnPointerDown(event) { - window.focus(); - - if (!this.internalEventPreHandler(event, 1)) { - return false; - } - - const position = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event); - - if (event instanceof MouseEvent) { - const isRightClick = event.button === 2; - if (isRightClick) { - // Ignore right clicks - this.rightClick.dispatch(position, event); - this.cancelled = true; - this.clickDownPosition = null; - return; - } - } - - if (this.clickDownPosition) { - logger.warn("Ignoring double click"); - return false; - } - - this.cancelled = false; - this.touchstart.dispatch(event); - - // Store where the touch started - this.clickDownPosition = position; - this.clickStartTime = performance.now(); - this.touchstartSimple.dispatch(this.clickDownPosition.x, this.clickDownPosition.y); - - // If we are not currently within a click, register it - if (ongoingClickDetectors.indexOf(this) < 0) { - ongoingClickDetectors.push(this); - } else { - logger.warn("Click detector got pointer down of active pointer twice"); - } - - // If we should apply any classes, do this now - if (this.applyCssClass) { - this.element.classList.add(this.applyCssClass); - } - - // If we should play any sound, do this - if (this.clickSound) { - GLOBAL_APP.sound.playUiSound(this.clickSound); - } - - return false; - } - - /** - * Internal pointer move handler - * @param {TouchEvent|MouseEvent} event - */ - internalOnPointerMove(event) { - if (!this.internalEventPreHandler(event, 1)) { - return false; - } - this.touchmove.dispatch(event); - const pos = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event); - this.touchmoveSimple.dispatch(pos.x, pos.y); - return false; - } - - /** - * Internal pointer end handler - * @param {TouchEvent|MouseEvent} event - */ - internalOnPointerEnd(event) { - window.focus(); - - if (!this.internalEventPreHandler(event, 0)) { - return false; - } - - if (this.cancelled) { - // warn(this, "Not dispatching touchend on cancelled listener"); - return false; - } - - if (event instanceof MouseEvent) { - const isRightClick = event.button === 2; - if (isRightClick) { - return; - } - } - - const index = ongoingClickDetectors.indexOf(this); - if (index < 0) { - logger.warn("Got pointer end but click detector is not in pressed state"); - } else { - fastArrayDelete(ongoingClickDetectors, index); - } - - let dispatchClick = false; - let dispatchClickPos = null; - - // Check for correct down position, otherwise must have pinched or so - if (this.clickDownPosition) { - const pos = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event); - const distance = pos.distance(this.clickDownPosition); - if (!IS_MOBILE || distance <= this.maxDistance) { - dispatchClick = true; - dispatchClickPos = pos; - } else { - console.warn("[ClickDetector] Touch does not count as click:", "(was", distance, ")"); - } - } - - this.clickDownPosition = null; - this.clickStartTime = null; - - if (this.applyCssClass) { - this.element.classList.remove(this.applyCssClass); - } - - // Dispatch in the end to avoid the element getting invalidated - // Also make sure that the element is still in the dom - if (this.internalIsDomElementAttached()) { - this.touchend.dispatch(event); - this.touchendSimple.dispatch(); - - if (dispatchClick) { - const detectors = ongoingClickDetectors.slice(); - for (let i = 0; i < detectors.length; ++i) { - detectors[i].cancelOngoingEvents(); - } - this.click.dispatch(dispatchClickPos, event); - } - } - return false; - } - - /** - * Internal touch cancel handler - * @param {TouchEvent|MouseEvent} event - */ - internalOnTouchCancel(event) { - if (!this.internalEventPreHandler(event, 0)) { - return false; - } - - if (this.cancelled) { - // warn(this, "Not dispatching touchcancel on cancelled listener"); - return false; - } - - this.cancelOngoingEvents(); - this.touchcancel.dispatch(event); - this.touchendSimple.dispatch(event); - return false; - } -} +import { createLogger } from "../core/logging"; +import { Signal } from "../core/signal"; +import { fastArrayDelete, fastArrayDeleteValueIfContained } from "./utils"; +import { Vector } from "./vector"; +import { IS_MOBILE, SUPPORT_TOUCH } from "./config"; +import { SOUNDS } from "../platform/sound"; +import { GLOBAL_APP } from "./globals"; + +const logger = createLogger("click_detector"); + +export const MAX_MOVE_DISTANCE_PX = IS_MOBILE ? 20 : 80; + +// For debugging +const registerClickDetectors = G_IS_DEV && true; +if (registerClickDetectors) { + /** @type {Array} */ + window.activeClickDetectors = []; +} + +// Store active click detectors so we can cancel them +/** @type {Array} */ +const ongoingClickDetectors = []; + +// Store when the last touch event was registered, to avoid accepting a touch *and* a click event + +export let clickDetectorGlobals = { + lastTouchTime: -1000, +}; + +/** + * Click detector creation payload typehints + * @typedef {{ + * consumeEvents?: boolean, + * preventDefault?: boolean, + * applyCssClass?: string, + * captureTouchmove?: boolean, + * targetOnly?: boolean, + * maxDistance?: number, + * clickSound?: string, + * preventClick?: boolean, + * }} ClickDetectorConstructorArgs + */ + +// Detects clicks +export class ClickDetector { + /** + * + * @param {Element} element + * @param {object} param1 + * @param {boolean=} param1.consumeEvents Whether to call stopPropagation + * (Useful for nested elements where the parent has a click handler as wel) + * @param {boolean=} param1.preventDefault Whether to call preventDefault (Usually makes the handler faster) + * @param {string=} param1.applyCssClass The css class to add while the element is pressed + * @param {boolean=} param1.captureTouchmove Whether to capture touchmove events as well + * @param {boolean=} param1.targetOnly Whether to also accept clicks on child elements (e.target !== element) + * @param {number=} param1.maxDistance The maximum distance in pixels to accept clicks + * @param {string=} param1.clickSound Sound key to play on touchdown + * @param {boolean=} param1.preventClick Whether to prevent click events + */ + constructor( + element, + { + consumeEvents = false, + preventDefault = true, + applyCssClass = "pressed", + captureTouchmove = false, + targetOnly = false, + maxDistance = MAX_MOVE_DISTANCE_PX, + clickSound = SOUNDS.uiClick, + preventClick = false, + } + ) { + assert(element, "No element given!"); + this.clickDownPosition = null; + + this.consumeEvents = consumeEvents; + this.preventDefault = preventDefault; + this.applyCssClass = applyCssClass; + this.captureTouchmove = captureTouchmove; + this.targetOnly = targetOnly; + this.clickSound = clickSound; + this.maxDistance = maxDistance; + this.preventClick = preventClick; + + // Signals + this.click = new Signal(); + this.rightClick = new Signal(); + this.touchstart = new Signal(); + this.touchmove = new Signal(); + this.touchend = new Signal(); + this.touchcancel = new Signal(); + + // Simple signals which just receive the touch position + this.touchstartSimple = new Signal(); + this.touchmoveSimple = new Signal(); + this.touchendSimple = new Signal(); + + // Store time of touch start + this.clickStartTime = null; + + // A click can be cancelled if another detector registers a click + this.cancelled = false; + + this.internalBindTo(/** @type {HTMLElement} */ (element)); + } + + /** + * Cleans up all event listeners of this detector + */ + cleanup() { + if (this.element) { + if (registerClickDetectors) { + const index = window.activeClickDetectors.indexOf(this); + if (index < 0) { + logger.error("Click detector cleanup but is not active"); + } else { + window.activeClickDetectors.splice(index, 1); + } + } + const options = this.internalGetEventListenerOptions(); + + if (SUPPORT_TOUCH) { + this.element.removeEventListener("touchstart", this.handlerTouchStart, options); + this.element.removeEventListener("touchend", this.handlerTouchEnd, options); + this.element.removeEventListener("touchcancel", this.handlerTouchCancel, options); + } + + this.element.removeEventListener("mouseup", this.handlerTouchStart, options); + this.element.removeEventListener("mousedown", this.handlerTouchEnd, options); + this.element.removeEventListener("mouseout", this.handlerTouchCancel, options); + + if (this.captureTouchmove) { + if (SUPPORT_TOUCH) { + this.element.removeEventListener("touchmove", this.handlerTouchMove, options); + } + this.element.removeEventListener("mousemove", this.handlerTouchMove, options); + } + + if (this.preventClick) { + this.element.removeEventListener("click", this.handlerPreventClick, options); + } + + this.click.removeAll(); + this.touchstart.removeAll(); + this.touchmove.removeAll(); + this.touchend.removeAll(); + this.touchcancel.removeAll(); + + this.element = null; + } + } + + // INTERNAL METHODS + + /** + * + * @param {Event} event + */ + internalPreventClick(event) { + window.focus(); + event.preventDefault(); + } + + /** + * Internal method to get the options to pass to an event listener + */ + internalGetEventListenerOptions() { + return { + capture: this.consumeEvents, + passive: !this.preventDefault, + }; + } + + /** + * Binds the click detector to an element + * @param {HTMLElement} element + */ + internalBindTo(element) { + const options = this.internalGetEventListenerOptions(); + + this.handlerTouchStart = this.internalOnPointerDown.bind(this); + this.handlerTouchEnd = this.internalOnPointerEnd.bind(this); + this.handlerTouchMove = this.internalOnPointerMove.bind(this); + this.handlerTouchCancel = this.internalOnTouchCancel.bind(this); + + if (this.preventClick) { + this.handlerPreventClick = this.internalPreventClick.bind(this); + element.addEventListener("click", this.handlerPreventClick, options); + } + + if (SUPPORT_TOUCH) { + element.addEventListener("touchstart", this.handlerTouchStart, options); + element.addEventListener("touchend", this.handlerTouchEnd, options); + element.addEventListener("touchcancel", this.handlerTouchCancel, options); + } + + element.addEventListener("mousedown", this.handlerTouchStart, options); + element.addEventListener("mouseup", this.handlerTouchEnd, options); + element.addEventListener("mouseout", this.handlerTouchCancel, options); + + if (this.captureTouchmove) { + if (SUPPORT_TOUCH) { + element.addEventListener("touchmove", this.handlerTouchMove, options); + } + element.addEventListener("mousemove", this.handlerTouchMove, options); + } + + if (registerClickDetectors) { + window.activeClickDetectors.push(this); + } + this.element = element; + } + + /** + * Returns if the bound element is currently in the DOM. + */ + internalIsDomElementAttached() { + return this.element && document.documentElement.contains(this.element); + } + + /** + * Checks if the given event is relevant for this detector + * @param {TouchEvent|MouseEvent} event + */ + internalEventPreHandler(event, expectedRemainingTouches = 1) { + if (!this.element) { + // Already cleaned up + return false; + } + + if (this.targetOnly && event.target !== this.element) { + // Clicked a child element + return false; + } + + // Stop any propagation and defaults if configured + if (this.consumeEvents && event.cancelable) { + event.stopPropagation(); + } + + if (this.preventDefault && event.cancelable) { + event.preventDefault(); + } + + if (window.TouchEvent && event instanceof TouchEvent) { + clickDetectorGlobals.lastTouchTime = performance.now(); + + // console.log("Got touches", event.targetTouches.length, "vs", expectedRemainingTouches); + if (event.targetTouches.length !== expectedRemainingTouches) { + return false; + } + } + + if (event instanceof MouseEvent) { + if (performance.now() - clickDetectorGlobals.lastTouchTime < 1000.0) { + return false; + } + } + + return true; + } + + /** + * Extracts the mous position from an event + * @param {TouchEvent|MouseEvent} event + * @returns {Vector} The client space position + */ + static extractPointerPosition(event) { + if (window.TouchEvent && event instanceof TouchEvent) { + if (event.changedTouches.length !== 1) { + logger.warn( + "Got unexpected target touches:", + event.targetTouches.length, + "->", + event.targetTouches + ); + return new Vector(0, 0); + } + + const touch = event.changedTouches[0]; + return new Vector(touch.clientX, touch.clientY); + } + + if (event instanceof MouseEvent) { + return new Vector(event.clientX, event.clientY); + } + + assertAlways(false, "Got unknown event: " + event); + + return new Vector(0, 0); + } + + /** + * Cacnels all ongoing events on this detector + */ + cancelOngoingEvents() { + if (this.applyCssClass && this.element) { + this.element.classList.remove(this.applyCssClass); + } + this.clickDownPosition = null; + this.clickStartTime = null; + this.cancelled = true; + fastArrayDeleteValueIfContained(ongoingClickDetectors, this); + } + + /** + * Internal pointer down handler + * @param {TouchEvent|MouseEvent} event + */ + internalOnPointerDown(event) { + window.focus(); + + if (!this.internalEventPreHandler(event, 1)) { + return false; + } + + const position = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event); + + if (event instanceof MouseEvent) { + const isRightClick = event.button === 2; + if (isRightClick) { + // Ignore right clicks + this.rightClick.dispatch(position, event); + this.cancelled = true; + this.clickDownPosition = null; + return; + } + } + + if (this.clickDownPosition) { + logger.warn("Ignoring double click"); + return false; + } + + this.cancelled = false; + this.touchstart.dispatch(event); + + // Store where the touch started + this.clickDownPosition = position; + this.clickStartTime = performance.now(); + this.touchstartSimple.dispatch(this.clickDownPosition.x, this.clickDownPosition.y); + + // If we are not currently within a click, register it + if (ongoingClickDetectors.indexOf(this) < 0) { + ongoingClickDetectors.push(this); + } else { + logger.warn("Click detector got pointer down of active pointer twice"); + } + + // If we should apply any classes, do this now + if (this.applyCssClass) { + this.element.classList.add(this.applyCssClass); + } + + // If we should play any sound, do this + if (this.clickSound) { + GLOBAL_APP.sound.playUiSound(this.clickSound); + } + + return false; + } + + /** + * Internal pointer move handler + * @param {TouchEvent|MouseEvent} event + */ + internalOnPointerMove(event) { + if (!this.internalEventPreHandler(event, 1)) { + return false; + } + this.touchmove.dispatch(event); + const pos = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event); + this.touchmoveSimple.dispatch(pos.x, pos.y); + return false; + } + + /** + * Internal pointer end handler + * @param {TouchEvent|MouseEvent} event + */ + internalOnPointerEnd(event) { + window.focus(); + + if (!this.internalEventPreHandler(event, 0)) { + return false; + } + + if (this.cancelled) { + // warn(this, "Not dispatching touchend on cancelled listener"); + return false; + } + + if (event instanceof MouseEvent) { + const isRightClick = event.button === 2; + if (isRightClick) { + return; + } + } + + const index = ongoingClickDetectors.indexOf(this); + if (index < 0) { + logger.warn("Got pointer end but click detector is not in pressed state"); + } else { + fastArrayDelete(ongoingClickDetectors, index); + } + + let dispatchClick = false; + let dispatchClickPos = null; + + // Check for correct down position, otherwise must have pinched or so + if (this.clickDownPosition) { + const pos = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event); + const distance = pos.distance(this.clickDownPosition); + if (!IS_MOBILE || distance <= this.maxDistance) { + dispatchClick = true; + dispatchClickPos = pos; + } else { + console.warn("[ClickDetector] Touch does not count as click:", "(was", distance, ")"); + } + } + + this.clickDownPosition = null; + this.clickStartTime = null; + + if (this.applyCssClass) { + this.element.classList.remove(this.applyCssClass); + } + + // Dispatch in the end to avoid the element getting invalidated + // Also make sure that the element is still in the dom + if (this.internalIsDomElementAttached()) { + this.touchend.dispatch(event); + this.touchendSimple.dispatch(); + + if (dispatchClick) { + const detectors = ongoingClickDetectors.slice(); + for (let i = 0; i < detectors.length; ++i) { + detectors[i].cancelOngoingEvents(); + } + this.click.dispatch(dispatchClickPos, event); + } + } + return false; + } + + /** + * Internal touch cancel handler + * @param {TouchEvent|MouseEvent} event + */ + internalOnTouchCancel(event) { + if (!this.internalEventPreHandler(event, 0)) { + return false; + } + + if (this.cancelled) { + // warn(this, "Not dispatching touchcancel on cancelled listener"); + return false; + } + + this.cancelOngoingEvents(); + this.touchcancel.dispatch(event); + this.touchendSimple.dispatch(event); + return false; + } +} diff --git a/src/js/core/config.js b/src/js/core/config.js index 57224b6a..a7df2a90 100644 --- a/src/js/core/config.js +++ b/src/js/core/config.js @@ -18,6 +18,12 @@ export const THIRDPARTY_URLS = { shapeViewer: "https://viewer.shapez.io", standaloneStorePage: "https://store.steampowered.com/app/1318690/shapezio/", + + levelTutorialVideos: { + 21: "https://www.youtube.com/watch?v=0nUfRLMCcgo&", + 25: "https://www.youtube.com/watch?v=7OCV1g40Iew&", + 26: "https://www.youtube.com/watch?v=gfm6dS1dCoY", + }, }; export const A_B_TESTING_LINK_TYPE = Math.random() > 0.5 ? "steam_1_pr" : "steam_2_npr"; @@ -132,3 +138,8 @@ if (G_IS_DEV && globalConfig.debug.renderForTrailer) { if (globalConfig.debug.fastGameEnter) { globalConfig.debug.noArtificialDelays = true; } + +if (G_IS_DEV && globalConfig.debug.noArtificialDelays) { + globalConfig.warmupTimeSecondsFast = 0; + globalConfig.warmupTimeSecondsRegular = 0; +} diff --git a/src/js/core/draw_parameters.js b/src/js/core/draw_parameters.js index 71971ed1..95e71bf2 100644 --- a/src/js/core/draw_parameters.js +++ b/src/js/core/draw_parameters.js @@ -1,26 +1,25 @@ -import { globalConfig } from "./config"; - -/** - * @typedef {import("../game/root").GameRoot} GameRoot - * @typedef {import("./rectangle").Rectangle} Rectangle - */ - -export class DrawParameters { - constructor({ context, visibleRect, desiredAtlasScale, zoomLevel, root }) { - /** @type {CanvasRenderingContext2D} */ - this.context = context; - - /** @type {Rectangle} */ - this.visibleRect = visibleRect; - - /** @type {string} */ - this.desiredAtlasScale = desiredAtlasScale; - - /** @type {number} */ - this.zoomLevel = zoomLevel; - - // FIXME: Not really nice - /** @type {GameRoot} */ - this.root = root; - } -} +import { globalConfig } from "./config"; + +/** + * @typedef {import("../game/root").GameRoot} GameRoot + * @typedef {import("./rectangle").Rectangle} Rectangle + */ + +export class DrawParameters { + constructor({ context, visibleRect, desiredAtlasScale, zoomLevel, root }) { + /** @type {CanvasRenderingContext2D} */ + this.context = context; + + /** @type {Rectangle} */ + this.visibleRect = visibleRect; + + /** @type {string} */ + this.desiredAtlasScale = desiredAtlasScale; + + /** @type {number} */ + this.zoomLevel = zoomLevel; + + /** @type {GameRoot} */ + this.root = root; + } +} diff --git a/src/js/core/modal_dialog_elements.js b/src/js/core/modal_dialog_elements.js index 934e2de5..5f0ed59f 100644 --- a/src/js/core/modal_dialog_elements.js +++ b/src/js/core/modal_dialog_elements.js @@ -13,6 +13,17 @@ import { getStringForKeyCode } from "../game/key_action_mapper"; import { createLogger } from "./logging"; import { T } from "../translations"; +/* + * *************************************************** + * + * LEGACY CODE WARNING + * + * This is old code from yorg3.io and needs to be refactored + * @TODO + * + * *************************************************** + */ + const kbEnter = 13; const kbCancel = 27; diff --git a/src/js/core/modal_dialog_forms.js b/src/js/core/modal_dialog_forms.js index 58fd2543..1c5b1986 100644 --- a/src/js/core/modal_dialog_forms.js +++ b/src/js/core/modal_dialog_forms.js @@ -2,6 +2,17 @@ import { BaseItem } from "../game/base_item"; import { ClickDetector } from "./click_detector"; import { Signal } from "./signal"; +/* + * *************************************************** + * + * LEGACY CODE WARNING + * + * This is old code from yorg3.io and needs to be refactored + * @TODO + * + * *************************************************** + */ + export class FormElement { constructor(id, label) { this.id = id; diff --git a/src/js/core/restriction_manager.js b/src/js/core/restriction_manager.js index fb34acb8..2912d30f 100644 --- a/src/js/core/restriction_manager.js +++ b/src/js/core/restriction_manager.js @@ -44,7 +44,6 @@ export class RestrictionManager extends ReadWriteProxy { * @param {any} data */ migrate(data) { - // Todo return ExplainedResult.good(); } diff --git a/src/js/core/rng.js b/src/js/core/rng.js index 9c5c1c43..7a6766cd 100644 --- a/src/js/core/rng.js +++ b/src/js/core/rng.js @@ -108,17 +108,6 @@ export class RandomNumberGenerator { assert(max > min, "rng: max <= min"); return Math.floor(this.next() * (max - min) + min); } - /** - * @param {number} min - * @param {number} max - * @returns {number} Integer in range [min, max] - */ - nextIntRangeInclusive(min, max) { - assert(Number.isFinite(min), "Minimum is no integer"); - assert(Number.isFinite(max), "Maximum is no integer"); - assert(max > min, "rng: max <= min"); - return Math.round(this.next() * (max - min) + min); - } /** * @param {number} min diff --git a/src/js/game/building_codes.js b/src/js/game/building_codes.js index 0a3cbc36..78240c31 100644 --- a/src/js/game/building_codes.js +++ b/src/js/game/building_codes.js @@ -41,7 +41,7 @@ const variantsCache = new Map(); export function registerBuildingVariant( code, meta, - variant = "default" /* FIXME: Circular dependency, actually its defaultBuildingVariant */, + variant = "default" /* @TODO: Circular dependency, actually its defaultBuildingVariant */, rotationVariant = 0 ) { assert(!gBuildingVariants[code], "Duplicate id: " + code); diff --git a/src/js/game/buildings/belt.js b/src/js/game/buildings/belt.js index 562b47d5..84646b19 100644 --- a/src/js/game/buildings/belt.js +++ b/src/js/game/buildings/belt.js @@ -7,6 +7,7 @@ import { BeltComponent } from "../components/belt"; import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; import { GameRoot } from "../root"; +import { THEME } from "../theme"; export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right]; @@ -22,7 +23,7 @@ export class MetaBeltBuilding extends MetaBuilding { } getSilhouetteColor() { - return "#777"; + return THEME.map.chunkOverview.beltColor; } getPlacementSound() { diff --git a/src/js/game/buildings/underground_belt.js b/src/js/game/buildings/underground_belt.js index fde018fe..2761443d 100644 --- a/src/js/game/buildings/underground_belt.js +++ b/src/js/game/buildings/underground_belt.js @@ -191,7 +191,6 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding { ) { tile = tile.addScalars(searchVector.x, searchVector.y); - /* WIRES: FIXME */ const contents = root.map.getTileContent(tile, "regular"); if (contents) { const undergroundComp = contents.components.UndergroundBelt; diff --git a/src/js/game/components/item_ejector.js b/src/js/game/components/item_ejector.js index 4eda52f9..47253b4b 100644 --- a/src/js/game/components/item_ejector.js +++ b/src/js/game/components/item_ejector.js @@ -26,7 +26,7 @@ export class ItemEjectorComponent extends Component { static getSchema() { // The cachedDestSlot, cachedTargetEntity fields are not serialized. return { - slots: types.array( + slots: types.fixedSizeArray( types.structured({ item: types.nullable(typeItemSingleton), progress: types.float, diff --git a/src/js/game/components/wired_pins.js b/src/js/game/components/wired_pins.js index ff339b86..81a6ec62 100644 --- a/src/js/game/components/wired_pins.js +++ b/src/js/game/components/wired_pins.js @@ -31,7 +31,7 @@ export class WiredPinsComponent extends Component { static getSchema() { return { - slots: types.array( + slots: types.fixedSizeArray( types.structured({ value: types.nullable(typeItemSingleton), }) diff --git a/src/js/game/entity_manager.js b/src/js/game/entity_manager.js index 613ed12d..b4101fc8 100644 --- a/src/js/game/entity_manager.js +++ b/src/js/game/entity_manager.js @@ -182,23 +182,6 @@ export class EntityManager extends BasicSerializableObject { return this.componentToEntity[componentHandle.getId()] || []; } - /** - * Return all of a given class. This is SLOW! - * @param {object} entityClass - * @returns {Array} entities - */ - getAllOfClass(entityClass) { - // FIXME: Slow - const result = []; - for (let i = 0; i < this.entities.length; ++i) { - const entity = this.entities[i]; - if (entity instanceof entityClass) { - result.push(entity); - } - } - return result; - } - /** * Unregisters all components of an entity from the component to entity mapping * @param {Entity} entity diff --git a/src/js/game/hub_goals.js b/src/js/game/hub_goals.js index e7a1fea7..c9d9494f 100644 --- a/src/js/game/hub_goals.js +++ b/src/js/game/hub_goals.js @@ -369,7 +369,7 @@ export class HubGoals extends BasicSerializableObject { if (allowUncolored) { universalColors.push(enumColors.uncolored); } - const index = rng.nextIntRangeInclusive(0, colorWheel.length - 3); + const index = rng.nextIntRange(0, colorWheel.length - 2); const pickedColors = colorWheel.slice(index, index + 3); pickedColors.push(rng.choice(universalColors)); return pickedColors; diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js index a9edffd0..5f1bd226 100644 --- a/src/js/game/hud/hud.js +++ b/src/js/game/hud/hud.js @@ -47,6 +47,7 @@ import { HUDMinerHighlight } from "./parts/miner_highlight"; import { HUDBetaOverlay } from "./parts/beta_overlay"; import { HUDStandaloneAdvantages } from "./parts/standalone_advantages"; import { HUDCatMemes } from "./parts/cat_memes"; +import { HUDTutorialVideoOffer } from "./parts/tutorial_video_offer"; export class GameHUD { /** @@ -60,6 +61,18 @@ export class GameHUD { * Initializes the hud parts */ initialize() { + this.signals = { + buildingSelectedForPlacement: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()), + selectedPlacementBuildingChanged: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()), + shapePinRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()), + shapeUnpinRequested: /** @type {TypedSignal<[string]>} */ (new Signal()), + notification: /** @type {TypedSignal<[string, enumNotificationType]>} */ (new Signal()), + buildingsSelectedForCopy: /** @type {TypedSignal<[Array]>} */ (new Signal()), + pasteBlueprintRequested: /** @type {TypedSignal<[]>} */ (new Signal()), + viewShapeDetailsRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()), + unlockNotificationFinished: /** @type {TypedSignal<[]>} */ (new Signal()), + }; + this.parts = { buildingsToolbar: new HUDBuildingsToolbar(this.root), wiresToolbar: new HUDWiresToolbar(this.root), @@ -87,6 +100,7 @@ export class GameHUD { layerPreview: new HUDLayerPreview(this.root), minerHighlight: new HUDMinerHighlight(this.root), + tutorialVideoOffer: new HUDTutorialVideoOffer(this.root), // Typing hints /* typehints:start */ @@ -95,17 +109,6 @@ export class GameHUD { /* typehints:end */ }; - this.signals = { - buildingSelectedForPlacement: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()), - selectedPlacementBuildingChanged: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()), - shapePinRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()), - shapeUnpinRequested: /** @type {TypedSignal<[string]>} */ (new Signal()), - notification: /** @type {TypedSignal<[string, enumNotificationType]>} */ (new Signal()), - buildingsSelectedForCopy: /** @type {TypedSignal<[Array]>} */ (new Signal()), - pasteBlueprintRequested: /** @type {TypedSignal<[]>} */ (new Signal()), - viewShapeDetailsRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()), - }; - if (!IS_MOBILE) { this.parts.keybindingOverlay = new HUDKeybindingOverlay(this.root); } diff --git a/src/js/game/hud/parts/interactive_tutorial.js b/src/js/game/hud/parts/interactive_tutorial.js index ffebc639..e48a77fb 100644 --- a/src/js/game/hud/parts/interactive_tutorial.js +++ b/src/js/game/hud/parts/interactive_tutorial.js @@ -6,23 +6,25 @@ import { DynamicDomAttach } from "../dynamic_dom_attach"; import { TrackedState } from "../../../core/tracked_state"; import { cachebust } from "../../../core/cachebust"; import { T } from "../../../translations"; +import { enumItemProcessorTypes, ItemProcessorComponent } from "../../components/item_processor"; +import { ShapeItem } from "../../items/shape_item"; +import { WireComponent } from "../../components/wire"; +import { LeverComponent } from "../../components/lever"; +// @todo: Make dictionary const tutorialsByLevel = [ // Level 1 [ // 1.1. place an extractor { id: "1_1_extractor", - condition: /** @param {GameRoot} root */ root => { - return root.entityMgr.getAllWithComponent(MinerComponent).length === 0; - }, + condition: /** @param {GameRoot} root */ root => + root.entityMgr.getAllWithComponent(MinerComponent).length === 0, }, // 1.2. connect to hub { id: "1_2_conveyor", - condition: /** @param {GameRoot} root */ root => { - return root.hubGoals.getCurrentGoalDelivered() === 0; - }, + condition: /** @param {GameRoot} root */ root => root.hubGoals.getCurrentGoalDelivered() === 0, }, // 1.3 wait for completion { @@ -30,6 +32,108 @@ const tutorialsByLevel = [ condition: () => true, }, ], + // Level 2 + [ + // 2.1 place a cutter + { + id: "2_1_place_cutter", + condition: /** @param {GameRoot} root */ root => + root.entityMgr + .getAllWithComponent(ItemProcessorComponent) + .filter(e => e.components.ItemProcessor.type === enumItemProcessorTypes.cutter).length === + 0, + }, + // 2.2 place trash + { + id: "2_2_place_trash", + condition: /** @param {GameRoot} root */ root => + root.entityMgr + .getAllWithComponent(ItemProcessorComponent) + .filter(e => e.components.ItemProcessor.type === enumItemProcessorTypes.trash).length === + 0, + }, + // 2.3 place more cutters + { + id: "2_3_more_cutters", + condition: /** @param {GameRoot} root */ root => + root.entityMgr + .getAllWithComponent(ItemProcessorComponent) + .filter(e => e.components.ItemProcessor.type === enumItemProcessorTypes.cutter).length < + 3, + }, + ], + + // Level 3 + [ + // 3.1. rectangles + { + id: "3_1_rectangles", + condition: /** @param {GameRoot} root */ root => + // 4 miners placed above rectangles and 10 delivered + root.hubGoals.getCurrentGoalDelivered() < 10 || + root.entityMgr.getAllWithComponent(MinerComponent).filter(entity => { + const tile = entity.components.StaticMapEntity.origin; + const below = root.map.getLowerLayerContentXY(tile.x, tile.y); + if (below && below.getItemType() === "shape") { + const shape = /** @type {ShapeItem} */ (below).definition.getHash(); + return shape === "RuRuRuRu"; + } + return false; + }).length < 4, + }, + ], + + [], // Level 4 + [], // Level 5 + [], // Level 6 + [], // Level 7 + [], // Level 8 + [], // Level 9 + [], // Level 10 + [], // Level 11 + [], // Level 12 + [], // Level 13 + [], // Level 14 + [], // Level 15 + [], // Level 16 + [], // Level 17 + [], // Level 18 + [], // Level 19 + [], // Level 20 + + // Level 21 + [ + // 21.1 place quad painter + { + id: "21_1_place_quad_painter", + condition: /** @param {GameRoot} root */ root => + root.entityMgr + .getAllWithComponent(ItemProcessorComponent) + .filter(e => e.components.ItemProcessor.type === enumItemProcessorTypes.painterQuad) + .length === 0, + }, + + // 21.2 switch to wires layer + { + id: "21_2_switch_to_wires", + condition: /** @param {GameRoot} root */ root => + root.entityMgr.getAllWithComponent(WireComponent).length < 5, + }, + + // 21.3 place button + { + id: "21_3_place_button", + condition: /** @param {GameRoot} root */ root => + root.entityMgr.getAllWithComponent(LeverComponent).length === 0, + }, + + // 21.4 activate button + { + id: "21_4_press_button", + condition: /** @param {GameRoot} root */ root => + root.entityMgr.getAllWithComponent(LeverComponent).some(e => !e.components.Lever.toggled), + }, + ], ]; export class HUDInteractiveTutorial extends BaseHUDPart { diff --git a/src/js/game/hud/parts/tutorial_video_offer.js b/src/js/game/hud/parts/tutorial_video_offer.js new file mode 100644 index 00000000..3cd2cb90 --- /dev/null +++ b/src/js/game/hud/parts/tutorial_video_offer.js @@ -0,0 +1,34 @@ +import { THIRDPARTY_URLS } from "../../../core/config"; +import { T } from "../../../translations"; +import { BaseHUDPart } from "../base_hud_part"; + +/** + * Offers to open the tutorial video after completing a level + */ +export class HUDTutorialVideoOffer extends BaseHUDPart { + createElements() {} + + initialize() { + this.root.hud.signals.unlockNotificationFinished.add(() => { + const level = this.root.hubGoals.level; + const tutorialVideoLink = THIRDPARTY_URLS.levelTutorialVideos[level]; + if (tutorialVideoLink) { + const isForeign = this.root.app.settings.getLanguage() !== "en"; + const dialogData = isForeign + ? T.dialogs.tutorialVideoAvailableForeignLanguage + : T.dialogs.tutorialVideoAvailable; + + const { ok } = this.root.hud.parts.dialogs.showInfo(dialogData.title, dialogData.desc, [ + "cancel:bad", + "ok:good", + ]); + + this.root.app.analytics.trackUiClick("ingame_video_link_show_" + level); + ok.add(() => { + this.root.app.platformWrapper.openExternalLink(tutorialVideoLink); + this.root.app.analytics.trackUiClick("ingame_video_link_open_" + level); + }); + } + }); + } +} diff --git a/src/js/game/hud/parts/unlock_notification.js b/src/js/game/hud/parts/unlock_notification.js index 5fa0e3e2..98549784 100644 --- a/src/js/game/hud/parts/unlock_notification.js +++ b/src/js/game/hud/parts/unlock_notification.js @@ -129,6 +129,8 @@ export class HUDUnlockNotification extends BaseHUDPart { this.root.app.adProvider.showVideoAd().then(() => { this.close(); + this.root.hud.signals.unlockNotificationFinished.dispatch(); + if (!this.root.app.settings.getAllSettings().offerHints) { return; } diff --git a/src/js/game/hud/parts/wires_toolbar.js b/src/js/game/hud/parts/wires_toolbar.js index e44d7186..5141bbeb 100644 --- a/src/js/game/hud/parts/wires_toolbar.js +++ b/src/js/game/hud/parts/wires_toolbar.js @@ -11,6 +11,7 @@ import { MetaComparatorBuilding } from "../../buildings/comparator"; import { MetaReaderBuilding } from "../../buildings/reader"; import { MetaFilterBuilding } from "../../buildings/filter"; import { MetaDisplayBuilding } from "../../buildings/display"; +import { MetaStorageBuilding } from "../../buildings/storage"; export class HUDWiresToolbar extends HUDBaseToolbar { constructor(root) { @@ -26,6 +27,7 @@ export class HUDWiresToolbar extends HUDBaseToolbar { MetaTransistorBuilding, ], secondaryBuildings: [ + MetaStorageBuilding, MetaReaderBuilding, MetaLeverBuilding, MetaFilterBuilding, diff --git a/src/js/game/key_action_mapper.js b/src/js/game/key_action_mapper.js index 497cd5de..6c424535 100644 --- a/src/js/game/key_action_mapper.js +++ b/src/js/game/key_action_mapper.js @@ -122,6 +122,7 @@ export const KEYCODE_RMB = 3; * @returns {string} */ export function getStringForKeyCode(code) { + // @todo: Refactor into dictionary switch (code) { case KEYCODE_LMB: return "LMB"; diff --git a/src/js/game/map_chunk_view.js b/src/js/game/map_chunk_view.js index 5bb5d2c4..848afbab 100644 --- a/src/js/game/map_chunk_view.js +++ b/src/js/game/map_chunk_view.js @@ -104,15 +104,17 @@ export class MapChunkView extends MapChunk { }); parameters.context.imageSmoothingEnabled = true; + const resourcesScale = this.root.app.settings.getAllSettings().mapResourcesScale; // Draw patch items - if (this.root.currentLayer === "regular") { + if (this.root.currentLayer === "regular" && resourcesScale > 0.05) { + const diameter = (70 / Math.pow(parameters.zoomLevel, 0.35)) * (0.2 + 2 * resourcesScale); + for (let i = 0; i < this.patches.length; ++i) { const patch = this.patches[i]; if (patch.item.getItemType() === "shape") { const destX = this.x * dims + patch.pos.x * globalConfig.tileSize; const destY = this.y * dims + patch.pos.y * globalConfig.tileSize; - const diameter = 80 / Math.pow(parameters.zoomLevel, 0.35); patch.item.drawItemCenteredClipped(destX, destY, parameters, diameter); } } diff --git a/src/js/game/modes/regular.js b/src/js/game/modes/regular.js index b7f84216..e99f4a7c 100644 --- a/src/js/game/modes/regular.js +++ b/src/js/game/modes/regular.js @@ -45,7 +45,7 @@ function generateUpgrades(limitedVersion = false) { const upgrades = { belt: [ { - required: [{ shape: "CuCuCuCu", amount: 60 }], + required: [{ shape: "CuCuCuCu", amount: 30 }], }, { required: [{ shape: "--CuCu--", amount: 500 }], @@ -334,7 +334,7 @@ export function generateLevelDefinitions(limitedVersion = false) { // Belt reader { shape: "--Cg----:--Cr----", // unused - required: 16, // Per second! + required: 8, // Per second! reward: enumHubGoalRewards.reward_belt_reader, throughputOnly: true, }, diff --git a/src/js/game/shape_definition_manager.js b/src/js/game/shape_definition_manager.js index 86723fcd..5bcfcc4b 100644 --- a/src/js/game/shape_definition_manager.js +++ b/src/js/game/shape_definition_manager.js @@ -31,7 +31,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject { */ this.shapeKeyToItem = {}; - // Caches operations in the form of 'operation:def1[:def2]' + // Caches operations in the form of 'operation/def1[/def2]' /** @type {Object.|ShapeDefinition>} */ this.operationCache = {}; } @@ -89,7 +89,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject { * @returns {[ShapeDefinition, ShapeDefinition]} */ shapeActionCutHalf(definition) { - const key = "cut:" + definition.getHash(); + const key = "cut/" + definition.getHash(); if (this.operationCache[key]) { return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key]); } @@ -108,7 +108,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject { * @returns {[ShapeDefinition, ShapeDefinition, ShapeDefinition, ShapeDefinition]} */ shapeActionCutQuad(definition) { - const key = "cut-quad:" + definition.getHash(); + const key = "cut-quad/" + definition.getHash(); if (this.operationCache[key]) { return /** @type {[ShapeDefinition, ShapeDefinition, ShapeDefinition, ShapeDefinition]} */ (this .operationCache[key]); @@ -130,7 +130,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject { * @returns {ShapeDefinition} */ shapeActionRotateCW(definition) { - const key = "rotate-cw:" + definition.getHash(); + const key = "rotate-cw/" + definition.getHash(); if (this.operationCache[key]) { return /** @type {ShapeDefinition} */ (this.operationCache[key]); } @@ -148,7 +148,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject { * @returns {ShapeDefinition} */ shapeActionRotateCCW(definition) { - const key = "rotate-ccw:" + definition.getHash(); + const key = "rotate-ccw/" + definition.getHash(); if (this.operationCache[key]) { return /** @type {ShapeDefinition} */ (this.operationCache[key]); } @@ -166,7 +166,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject { * @returns {ShapeDefinition} */ shapeActionRotate180(definition) { - const key = "rotate-fl:" + definition.getHash(); + const key = "rotate-fl/" + definition.getHash(); if (this.operationCache[key]) { return /** @type {ShapeDefinition} */ (this.operationCache[key]); } @@ -185,7 +185,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject { * @returns {ShapeDefinition} */ shapeActionStack(lowerDefinition, upperDefinition) { - const key = "stack:" + lowerDefinition.getHash() + ":" + upperDefinition.getHash(); + const key = "stack/" + lowerDefinition.getHash() + "/" + upperDefinition.getHash(); if (this.operationCache[key]) { return /** @type {ShapeDefinition} */ (this.operationCache[key]); } @@ -202,7 +202,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject { * @returns {ShapeDefinition} */ shapeActionPaintWith(definition, color) { - const key = "paint:" + definition.getHash() + ":" + color; + const key = "paint/" + definition.getHash() + "/" + color; if (this.operationCache[key]) { return /** @type {ShapeDefinition} */ (this.operationCache[key]); } @@ -219,7 +219,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject { * @returns {ShapeDefinition} */ shapeActionPaintWith4Colors(definition, colors) { - const key = "paint4:" + definition.getHash() + ":" + colors.join(","); + const key = "paint4/" + definition.getHash() + "/" + colors.join(","); if (this.operationCache[key]) { return /** @type {ShapeDefinition} */ (this.operationCache[key]); } diff --git a/src/js/game/systems/belt_reader.js b/src/js/game/systems/belt_reader.js index 4ce75af4..fbd00b6c 100644 --- a/src/js/game/systems/belt_reader.js +++ b/src/js/game/systems/belt_reader.js @@ -48,7 +48,7 @@ export class BeltReaderSystem extends GameSystemWithFilter { throughput = 1 / (averageSpacing / averageSpacingNum); } - readerComp.lastThroughput = Math.min(30, throughput); + readerComp.lastThroughput = Math.min(globalConfig.beltSpeedItemsPerSecond * 23.9, throughput); } } } diff --git a/src/js/game/systems/item_ejector.js b/src/js/game/systems/item_ejector.js index 4f7d29be..56535111 100644 --- a/src/js/game/systems/item_ejector.js +++ b/src/js/game/systems/item_ejector.js @@ -225,8 +225,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter { */ tryPassOverItem(item, receiver, slotIndex) { // Try figuring out how what to do with the item - // TODO: Kinda hacky. How to solve this properly? Don't want to go through inheritance hell. - // Also its just a few cases (hope it stays like this .. :x). + // @TODO: Kinda hacky. How to solve this properly? Don't want to go through inheritance hell. const beltComp = receiver.components.Belt; if (beltComp) { diff --git a/src/js/game/themes/dark.json b/src/js/game/themes/dark.json index 227d4532..733b7682 100644 --- a/src/js/game/themes/dark.json +++ b/src/js/game/themes/dark.json @@ -32,7 +32,8 @@ }, "chunkOverview": { "empty": "#444856", - "filled": "#646b7d" + "filled": "#646b7d", + "beltColor": "#9096a3" }, "wires": { diff --git a/src/js/game/themes/light.json b/src/js/game/themes/light.json index 47616d82..0c793c26 100644 --- a/src/js/game/themes/light.json +++ b/src/js/game/themes/light.json @@ -33,7 +33,8 @@ "chunkOverview": { "empty": "#a6afbb", - "filled": "#c5ccd6" + "filled": "#c5ccd6", + "beltColor": "#777" }, "wires": { diff --git a/src/js/game/tutorial_goals_mappings.js b/src/js/game/tutorial_goals_mappings.js index 5cd966b9..e0d17cbc 100644 --- a/src/js/game/tutorial_goals_mappings.js +++ b/src/js/game/tutorial_goals_mappings.js @@ -55,7 +55,7 @@ export const enumHubGoalRewardsToContentUnlocked = { ]), [enumHubGoalRewards.reward_logic_gates]: typed([[MetaLogicGateBuilding, defaultBuildingVariant]]), [enumHubGoalRewards.reward_filter]: typed([[MetaFilterBuilding, defaultBuildingVariant]]), - [enumHubGoalRewards.reward_virtual_processing]: null, // @TODO! + [enumHubGoalRewards.reward_virtual_processing]: null, [enumHubGoalRewards.reward_wires_painter_and_levers]: typed([ [MetaPainterBuilding, enumPainterVariants.quad], diff --git a/src/js/languages.js b/src/js/languages.js index c46c3e88..46ff8af9 100644 --- a/src/js/languages.js +++ b/src/js/languages.js @@ -1,113 +1,120 @@ -/** - * @type {Object} - */ -export const LANGUAGES = { - "en": { - name: "English", - data: null, - code: "en", - region: "", - }, - "de": { - name: "Deutsch", - data: require("./built-temp/base-de.json"), - code: "de", - region: "", - }, - "fr": { - name: "Français", - data: require("./built-temp/base-fr.json"), - code: "fr", - region: "", - }, - "ja": { - name: "日本語", - data: require("./built-temp/base-ja.json"), - code: "ja", - region: "", - }, - "pt-PT": { - name: "Português (Portugal)", - data: require("./built-temp/base-pt-PT.json"), - code: "pt", - region: "PT", - }, - "pt-BR": { - name: "Português (Brasil)", - data: require("./built-temp/base-pt-BR.json"), - code: "pt", - region: "BR", - }, - "ru": { - name: "Русский", - data: require("./built-temp/base-ru.json"), - code: "ru", - region: "", - }, - "cs": { - name: "Čeština", - data: require("./built-temp/base-cz.json"), - code: "cs", - region: "", - }, - "es-419": { - name: "Español", - data: require("./built-temp/base-es.json"), - code: "es", - region: "", - }, - "pl": { - name: "Polski", - data: require("./built-temp/base-pl.json"), - code: "pl", - region: "", - }, - "kor": { - name: "한국어", - data: require("./built-temp/base-kor.json"), - code: "kor", - region: "", - }, - "nl": { - name: "Nederlands", - data: require("./built-temp/base-nl.json"), - code: "nl", - region: "", - }, - "no": { - name: "Norsk", - data: require("./built-temp/base-no.json"), - code: "no", - region: "", - }, - - "tr": { - name: "Türkçe", - data: require("./built-temp/base-tr.json"), - code: "tr", - region: "", - }, - - "zh-CN": { - // simplified - name: "中文简体", - data: require("./built-temp/base-zh-CN.json"), - code: "zh", - region: "CN", - }, - - "zh-TW": { - // traditional - name: "中文繁體", - data: require("./built-temp/base-zh-TW.json"), - code: "zh", - region: "TW", - }, - - "sv": { - name: "Svenska", - data: require("./built-temp/base-sv.json"), - code: "sv", - region: "", - }, -}; +/** + * @type {Object} + */ +export const LANGUAGES = { + "en": { + name: "English", + data: null, + code: "en", + region: "", + }, + "de": { + name: "Deutsch", + data: require("./built-temp/base-de.json"), + code: "de", + region: "", + }, + "fr": { + name: "Français", + data: require("./built-temp/base-fr.json"), + code: "fr", + region: "", + }, + "ja": { + name: "日本語", + data: require("./built-temp/base-ja.json"), + code: "ja", + region: "", + }, + "pt-PT": { + name: "Português (Portugal)", + data: require("./built-temp/base-pt-PT.json"), + code: "pt", + region: "PT", + }, + "pt-BR": { + name: "Português (Brasil)", + data: require("./built-temp/base-pt-BR.json"), + code: "pt", + region: "BR", + }, + "ru": { + name: "Русский", + data: require("./built-temp/base-ru.json"), + code: "ru", + region: "", + }, + "cs": { + name: "Čeština", + data: require("./built-temp/base-cz.json"), + code: "cs", + region: "", + }, + "es-419": { + name: "Español", + data: require("./built-temp/base-es.json"), + code: "es", + region: "", + }, + "pl": { + name: "Polski", + data: require("./built-temp/base-pl.json"), + code: "pl", + region: "", + }, + "kor": { + name: "한국어", + data: require("./built-temp/base-kor.json"), + code: "kor", + region: "", + }, + "nl": { + name: "Nederlands", + data: require("./built-temp/base-nl.json"), + code: "nl", + region: "", + }, + "no": { + name: "Norsk", + data: require("./built-temp/base-no.json"), + code: "no", + region: "", + }, + + "tr": { + name: "Türkçe", + data: require("./built-temp/base-tr.json"), + code: "tr", + region: "", + }, + + "zh-CN": { + // simplified + name: "中文简体", + data: require("./built-temp/base-zh-CN.json"), + code: "zh", + region: "CN", + }, + + "zh-TW": { + // traditional + name: "中文繁體", + data: require("./built-temp/base-zh-TW.json"), + code: "zh", + region: "TW", + }, + + "sv": { + name: "Svenska", + data: require("./built-temp/base-sv.json"), + code: "sv", + region: "", + }, + + "da": { + name: "Dansk", + data: require("./built-temp/base-da.json"), + code: "da", + region: "", + }, +}; diff --git a/src/js/profile/application_settings.js b/src/js/profile/application_settings.js index 10f38fef..68abf5bb 100644 --- a/src/js/profile/application_settings.js +++ b/src/js/profile/application_settings.js @@ -267,6 +267,7 @@ export const allApplicationSettings = [ new BoolSetting("rotationByBuilding", enumCategories.advanced, (app, value) => {}), new BoolSetting("displayChunkBorders", enumCategories.advanced, (app, value) => {}), new BoolSetting("pickMinerOnPatch", enumCategories.advanced, (app, value) => {}), + new RangeSetting("mapResourcesScale", enumCategories.advanced, () => null), new EnumSetting("refreshRate", { options: refreshRateOptions, @@ -324,6 +325,7 @@ class SettingsStorage { this.lowQualityTextures = false; this.simplifiedBelts = false; this.zoomToCursor = true; + this.mapResourcesScale = 0.5; /** * @type {Object.} @@ -534,7 +536,7 @@ export class ApplicationSettings extends ReadWriteProxy { } getCurrentVersion() { - return 29; + return 30; } /** @param {{settings: SettingsStorage, version: number}} data */ @@ -672,6 +674,15 @@ export class ApplicationSettings extends ReadWriteProxy { data.version = 29; } + if (data.version < 30) { + data.settings.mapResourcesScale = 0.5; + + // Re-enable hints as well + data.settings.offerHints = true; + + data.version = 30; + } + return ExplainedResult.good(); } } diff --git a/src/js/profile/setting_types.js b/src/js/profile/setting_types.js index 66c9f01d..4df02892 100644 --- a/src/js/profile/setting_types.js +++ b/src/js/profile/setting_types.js @@ -7,6 +7,17 @@ import { T } from "../translations"; const logger = createLogger("setting_types"); +/* + * *************************************************** + * + * LEGACY CODE WARNING + * + * This is old code from yorg3.io and needs to be refactored + * @TODO + * + * *************************************************** + */ + export class BaseSetting { /** * diff --git a/src/js/savegame/savegame_manager.js b/src/js/savegame/savegame_manager.js index ed31dbcf..eb0d53d0 100644 --- a/src/js/savegame/savegame_manager.js +++ b/src/js/savegame/savegame_manager.js @@ -41,7 +41,7 @@ export class SavegameManager extends ReadWriteProxy { } verify(data) { - // TODO / FIXME!!!! + // @TODO return ExplainedResult.good(); } diff --git a/src/js/savegame/schemas/1006.js b/src/js/savegame/schemas/1006.js index d1c0b48f..79226772 100644 --- a/src/js/savegame/schemas/1006.js +++ b/src/js/savegame/schemas/1006.js @@ -248,7 +248,7 @@ export class SavegameInterface_V1006 extends SavegameInterface_V1005 { if (components.Storage) { // @ts-ignore components.Storage = { - storedCount: 0, + storedCount: rebalance(components.Storage.storedCount), storedItem: null, }; } diff --git a/src/js/savegame/serialization.js b/src/js/savegame/serialization.js index 9f998a0f..801b26ab 100644 --- a/src/js/savegame/serialization.js +++ b/src/js/savegame/serialization.js @@ -1,344 +1,351 @@ -import { createLogger } from "../core/logging"; -import { - BaseDataType, - TypeArray, - TypeBoolean, - TypeClass, - TypeClassData, - TypeClassFromMetaclass, - TypeClassId, - TypeEntity, - TypeEntityWeakref, - TypeEnum, - TypeFixedClass, - TypeInteger, - TypeKeyValueMap, - TypeMetaClass, - TypeNullable, - TypeNumber, - TypePair, - TypePositiveInteger, - TypePositiveNumber, - TypeString, - TypeStructuredObject, - TypeVector, -} from "./serialization_data_types"; - -const logger = createLogger("serialization"); - -// Schema declarations -export const types = { - int: new TypeInteger(), - uint: new TypePositiveInteger(), - float: new TypeNumber(), - ufloat: new TypePositiveNumber(), - string: new TypeString(), - entity: new TypeEntity(), - weakEntityRef: new TypeEntityWeakref(), - vector: new TypeVector(), - tileVector: new TypeVector(), - bool: new TypeBoolean(), - - /** - * @param {BaseDataType} wrapped - */ - nullable(wrapped) { - return new TypeNullable(wrapped); - }, - - /** - * @param {FactoryTemplate<*>|SingletonFactoryTemplate<*>} registry - */ - classId(registry) { - return new TypeClassId(registry); - }, - /** - * @param {BaseDataType} valueType - * @param {boolean=} includeEmptyValues - */ - keyValueMap(valueType, includeEmptyValues = true) { - return new TypeKeyValueMap(valueType, includeEmptyValues); - }, - - /** - * @param {Object} values - */ - enum(values) { - return new TypeEnum(values); - }, - - /** - * @param {FactoryTemplate<*>} registry - * @param {(GameRoot, any) => object=} resolver - */ - obj(registry, resolver = null) { - return new TypeClass(registry, resolver); - }, - - /** - * @param {FactoryTemplate<*>} registry - */ - objData(registry) { - return new TypeClassData(registry); - }, - - /** - * @param {typeof BasicSerializableObject} cls - */ - knownType(cls) { - return new TypeFixedClass(cls); - }, - - /** - * @param {BaseDataType} innerType - */ - array(innerType) { - return new TypeArray(innerType); - }, - - /** - * @param {SingletonFactoryTemplate<*>} innerType - */ - classRef(registry) { - return new TypeMetaClass(registry); - }, - - /** - * @param {Object.} descriptor - */ - structured(descriptor) { - return new TypeStructuredObject(descriptor); - }, - - /** - * @param {BaseDataType} a - * @param {BaseDataType} b - */ - pair(a, b) { - return new TypePair(a, b); - }, - - /** - * @param {typeof BasicSerializableObject} classHandle - * @param {SingletonFactoryTemplate<*>} registry - */ - classWithMetaclass(classHandle, registry) { - return new TypeClassFromMetaclass(classHandle, registry); - }, -}; - -/** - * A full schema declaration - * @typedef {Object.} Schema - */ - -const globalSchemaCache = {}; - -/* dev:start */ -const classnamesCache = {}; -/* dev:end*/ - -export class BasicSerializableObject { - /* dev:start */ - /** - * Fixes typeof DerivedComponent is not assignable to typeof Component, compiled out - * in non-dev builds - */ - constructor(...args) {} - - /* dev:end */ - - static getId() { - abstract; - } - - /** - * Should return the serialization schema - * @returns {Schema} - */ - static getSchema() { - return {}; - } - - // Implementation - /** @returns {Schema} */ - static getCachedSchema() { - const id = this.getId(); - - /* dev:start */ - assert( - classnamesCache[id] === this || classnamesCache[id] === undefined, - "Class name taken twice: " + id + " (from " + this.name + ")" - ); - classnamesCache[id] = this; - /* dev:end */ - - const entry = globalSchemaCache[id]; - if (entry) { - return entry; - } - - const schema = this.getSchema(); - globalSchemaCache[id] = schema; - return schema; - } - - /** @returns {object} */ - serialize() { - return serializeSchema( - this, - /** @type {typeof BasicSerializableObject} */ (this.constructor).getCachedSchema() - ); - } - - /** - * @param {any} data - * @param {import("./savegame_serializer").GameRoot} root - * @returns {string|void} - */ - deserialize(data, root = null) { - return deserializeSchema( - this, - /** @type {typeof BasicSerializableObject} */ (this.constructor).getCachedSchema(), - data, - null, - root - ); - } - - /** @returns {string|void} */ - static verify(data) { - return verifySchema(this.getCachedSchema(), data); - } -} - -/** - * Serializes an object using the given schema, mergin with the given properties - * @param {object} obj The object to serialize - * @param {Schema} schema The schema to use - * @param {object=} mergeWith Any additional properties to merge with the schema, useful for super calls - * @returns {object} Serialized data object - */ -export function serializeSchema(obj, schema, mergeWith = {}) { - for (const key in schema) { - if (!obj.hasOwnProperty(key)) { - logger.error("Invalid schema, property", key, "does not exist on", obj, "(schema=", schema, ")"); - assert( - obj.hasOwnProperty(key), - "serialization: invalid schema, property does not exist on object: " + key - ); - } - if (!schema[key]) { - assert(false, "Invalid schema (bad key '" + key + "'): " + JSON.stringify(schema)); - } - - if (G_IS_DEV) { - try { - mergeWith[key] = schema[key].serialize(obj[key]); - } catch (ex) { - logger.error( - "Serialization of", - obj, - "failed on key '" + key + "' ->", - ex, - "(schema was", - schema, - ")" - ); - throw ex; - } - } else { - mergeWith[key] = schema[key].serialize(obj[key]); - } - } - return mergeWith; -} - -/** - * Deserializes data into an object - * @param {object} obj The object to store the deserialized data into - * @param {Schema} schema The schema to use - * @param {object} data The serialized data - * @param {string|void|null=} baseclassErrorResult Convenience, if this is a string error code, do nothing and return it - * @param {import("../game/root").GameRoot=} root Optional game root reference - * @returns {string|void} String error code or nothing on success - */ -export function deserializeSchema(obj, schema, data, baseclassErrorResult = null, root) { - if (baseclassErrorResult) { - return baseclassErrorResult; - } - - if (!data) { - logger.error("Got 'NULL' data for", obj, "and schema", schema, "!"); - return "Got null data"; - } - - for (const key in schema) { - if (!data.hasOwnProperty(key)) { - logger.error("Data", data, "does not contain", key, "(schema:", schema, ")"); - return "Missing key in schema: " + key + " of class " + obj.constructor.name; - } - if (!schema[key].allowNull() && (data[key] === null || data[key] === undefined)) { - logger.error("Data", data, "has null value for", key, "(schema:", schema, ")"); - return "Non-nullable entry is null: " + key + " of class " + obj.constructor.name; - } - - const errorStatus = schema[key].deserializeWithVerify(data[key], obj, key, obj.root || root); - if (errorStatus) { - logger.error( - "Deserialization failed with error '" + errorStatus + "' on object", - obj, - "and key", - key, - "(root? =", - obj.root ? "y" : "n", - ")" - ); - return errorStatus; - } - } -} - -/** - * Verifies stored data using the given schema - * @param {Schema} schema The schema to use - * @param {object} data The data to verify - * @returns {string|void} String error code or nothing on success - */ -export function verifySchema(schema, data) { - for (const key in schema) { - if (!data.hasOwnProperty(key)) { - logger.error("Data", data, "does not contain", key, "(schema:", schema, ")"); - return "verify: missing key required by schema in stored data: " + key; - } - if (!schema[key].allowNull() && (data[key] === null || data[key] === undefined)) { - logger.error("Data", data, "has null value for", key, "(schema:", schema, ")"); - return "verify: non-nullable entry is null: " + key; - } - - const errorStatus = schema[key].verifySerializedValue(data[key]); - if (errorStatus) { - logger.error(errorStatus); - return "verify: " + errorStatus; - } - } -} - -/** - * Extends a schema by adding the properties from the new schema to the existing base schema - * @param {Schema} base - * @param {Schema} newOne - * @returns {Schema} - */ -export function extendSchema(base, newOne) { - /** @type {Schema} */ - const result = Object.assign({}, base); - for (const key in newOne) { - if (result.hasOwnProperty(key)) { - logger.error("Extend schema got duplicate key:", key); - continue; - } - result[key] = newOne[key]; - } - return result; -} +import { createLogger } from "../core/logging"; +import { + BaseDataType, + TypeArray, + TypeBoolean, + TypeClass, + TypeClassData, + TypeClassFromMetaclass, + TypeClassId, + TypeEntity, + TypeEntityWeakref, + TypeEnum, + TypeFixedClass, + TypeInteger, + TypeKeyValueMap, + TypeMetaClass, + TypeNullable, + TypeNumber, + TypePair, + TypePositiveInteger, + TypePositiveNumber, + TypeString, + TypeStructuredObject, + TypeVector, +} from "./serialization_data_types"; + +const logger = createLogger("serialization"); + +// Schema declarations +export const types = { + int: new TypeInteger(), + uint: new TypePositiveInteger(), + float: new TypeNumber(), + ufloat: new TypePositiveNumber(), + string: new TypeString(), + entity: new TypeEntity(), + weakEntityRef: new TypeEntityWeakref(), + vector: new TypeVector(), + tileVector: new TypeVector(), + bool: new TypeBoolean(), + + /** + * @param {BaseDataType} wrapped + */ + nullable(wrapped) { + return new TypeNullable(wrapped); + }, + + /** + * @param {FactoryTemplate<*>|SingletonFactoryTemplate<*>} registry + */ + classId(registry) { + return new TypeClassId(registry); + }, + /** + * @param {BaseDataType} valueType + * @param {boolean=} includeEmptyValues + */ + keyValueMap(valueType, includeEmptyValues = true) { + return new TypeKeyValueMap(valueType, includeEmptyValues); + }, + + /** + * @param {Object} values + */ + enum(values) { + return new TypeEnum(values); + }, + + /** + * @param {FactoryTemplate<*>} registry + * @param {(GameRoot, any) => object=} resolver + */ + obj(registry, resolver = null) { + return new TypeClass(registry, resolver); + }, + + /** + * @param {FactoryTemplate<*>} registry + */ + objData(registry) { + return new TypeClassData(registry); + }, + + /** + * @param {typeof BasicSerializableObject} cls + */ + knownType(cls) { + return new TypeFixedClass(cls); + }, + + /** + * @param {BaseDataType} innerType + */ + array(innerType) { + return new TypeArray(innerType); + }, + + /** + * @param {BaseDataType} innerType + */ + fixedSizeArray(innerType) { + return new TypeArray(innerType, true); + }, + + /** + * @param {SingletonFactoryTemplate<*>} innerType + */ + classRef(registry) { + return new TypeMetaClass(registry); + }, + + /** + * @param {Object.} descriptor + */ + structured(descriptor) { + return new TypeStructuredObject(descriptor); + }, + + /** + * @param {BaseDataType} a + * @param {BaseDataType} b + */ + pair(a, b) { + return new TypePair(a, b); + }, + + /** + * @param {typeof BasicSerializableObject} classHandle + * @param {SingletonFactoryTemplate<*>} registry + */ + classWithMetaclass(classHandle, registry) { + return new TypeClassFromMetaclass(classHandle, registry); + }, +}; + +/** + * A full schema declaration + * @typedef {Object.} Schema + */ + +const globalSchemaCache = {}; + +/* dev:start */ +const classnamesCache = {}; +/* dev:end*/ + +export class BasicSerializableObject { + /* dev:start */ + /** + * Fixes typeof DerivedComponent is not assignable to typeof Component, compiled out + * in non-dev builds + */ + constructor(...args) {} + + /* dev:end */ + + static getId() { + abstract; + } + + /** + * Should return the serialization schema + * @returns {Schema} + */ + static getSchema() { + return {}; + } + + // Implementation + /** @returns {Schema} */ + static getCachedSchema() { + const id = this.getId(); + + /* dev:start */ + assert( + classnamesCache[id] === this || classnamesCache[id] === undefined, + "Class name taken twice: " + id + " (from " + this.name + ")" + ); + classnamesCache[id] = this; + /* dev:end */ + + const entry = globalSchemaCache[id]; + if (entry) { + return entry; + } + + const schema = this.getSchema(); + globalSchemaCache[id] = schema; + return schema; + } + + /** @returns {object} */ + serialize() { + return serializeSchema( + this, + /** @type {typeof BasicSerializableObject} */ (this.constructor).getCachedSchema() + ); + } + + /** + * @param {any} data + * @param {import("./savegame_serializer").GameRoot} root + * @returns {string|void} + */ + deserialize(data, root = null) { + return deserializeSchema( + this, + /** @type {typeof BasicSerializableObject} */ (this.constructor).getCachedSchema(), + data, + null, + root + ); + } + + /** @returns {string|void} */ + static verify(data) { + return verifySchema(this.getCachedSchema(), data); + } +} + +/** + * Serializes an object using the given schema, mergin with the given properties + * @param {object} obj The object to serialize + * @param {Schema} schema The schema to use + * @param {object=} mergeWith Any additional properties to merge with the schema, useful for super calls + * @returns {object} Serialized data object + */ +export function serializeSchema(obj, schema, mergeWith = {}) { + for (const key in schema) { + if (!obj.hasOwnProperty(key)) { + logger.error("Invalid schema, property", key, "does not exist on", obj, "(schema=", schema, ")"); + assert( + obj.hasOwnProperty(key), + "serialization: invalid schema, property does not exist on object: " + key + ); + } + if (!schema[key]) { + assert(false, "Invalid schema (bad key '" + key + "'): " + JSON.stringify(schema)); + } + + if (G_IS_DEV) { + try { + mergeWith[key] = schema[key].serialize(obj[key]); + } catch (ex) { + logger.error( + "Serialization of", + obj, + "failed on key '" + key + "' ->", + ex, + "(schema was", + schema, + ")" + ); + throw ex; + } + } else { + mergeWith[key] = schema[key].serialize(obj[key]); + } + } + return mergeWith; +} + +/** + * Deserializes data into an object + * @param {object} obj The object to store the deserialized data into + * @param {Schema} schema The schema to use + * @param {object} data The serialized data + * @param {string|void|null=} baseclassErrorResult Convenience, if this is a string error code, do nothing and return it + * @param {import("../game/root").GameRoot=} root Optional game root reference + * @returns {string|void} String error code or nothing on success + */ +export function deserializeSchema(obj, schema, data, baseclassErrorResult = null, root) { + if (baseclassErrorResult) { + return baseclassErrorResult; + } + + if (!data) { + logger.error("Got 'NULL' data for", obj, "and schema", schema, "!"); + return "Got null data"; + } + + for (const key in schema) { + if (!data.hasOwnProperty(key)) { + logger.error("Data", data, "does not contain", key, "(schema:", schema, ")"); + return "Missing key in schema: " + key + " of class " + obj.constructor.name; + } + if (!schema[key].allowNull() && (data[key] === null || data[key] === undefined)) { + logger.error("Data", data, "has null value for", key, "(schema:", schema, ")"); + return "Non-nullable entry is null: " + key + " of class " + obj.constructor.name; + } + + const errorStatus = schema[key].deserializeWithVerify(data[key], obj, key, obj.root || root); + if (errorStatus) { + logger.error( + "Deserialization failed with error '" + errorStatus + "' on object", + obj, + "and key", + key, + "(root? =", + obj.root ? "y" : "n", + ")" + ); + return errorStatus; + } + } +} + +/** + * Verifies stored data using the given schema + * @param {Schema} schema The schema to use + * @param {object} data The data to verify + * @returns {string|void} String error code or nothing on success + */ +export function verifySchema(schema, data) { + for (const key in schema) { + if (!data.hasOwnProperty(key)) { + logger.error("Data", data, "does not contain", key, "(schema:", schema, ")"); + return "verify: missing key required by schema in stored data: " + key; + } + if (!schema[key].allowNull() && (data[key] === null || data[key] === undefined)) { + logger.error("Data", data, "has null value for", key, "(schema:", schema, ")"); + return "verify: non-nullable entry is null: " + key; + } + + const errorStatus = schema[key].verifySerializedValue(data[key]); + if (errorStatus) { + logger.error(errorStatus); + return "verify: " + errorStatus; + } + } +} + +/** + * Extends a schema by adding the properties from the new schema to the existing base schema + * @param {Schema} base + * @param {Schema} newOne + * @returns {Schema} + */ +export function extendSchema(base, newOne) { + /** @type {Schema} */ + const result = Object.assign({}, base); + for (const key in newOne) { + if (result.hasOwnProperty(key)) { + logger.error("Extend schema got duplicate key:", key); + continue; + } + result[key] = newOne[key]; + } + return result; +} diff --git a/src/js/savegame/serialization_data_types.js b/src/js/savegame/serialization_data_types.js index 9fb53bb8..9d3b689f 100644 --- a/src/js/savegame/serialization_data_types.js +++ b/src/js/savegame/serialization_data_types.js @@ -1,1292 +1,1295 @@ -/* typehints:start */ -import { GameRoot } from "../game/root"; -import { BasicSerializableObject } from "./serialization"; -/* typehints:end */ - -import { Vector } from "../core/vector"; -import { round4Digits } from "../core/utils"; -export const globalJsonSchemaDefs = {}; - -/** - * - * @param {import("./serialization").Schema} schema - */ -export function schemaToJsonSchema(schema) { - const jsonSchema = { - type: "object", - additionalProperties: false, - required: [], - properties: {}, - }; - - for (const key in schema) { - const subSchema = schema[key].getAsJsonSchema(); - jsonSchema.required.push(key); - jsonSchema.properties[key] = subSchema; - } - - return jsonSchema; -} - -/** - * Helper function to create a json schema object - * @param {any} properties - */ -function schemaObject(properties) { - return { - type: "object", - required: Object.keys(properties).slice(), - additionalProperties: false, - properties, - }; -} - -/** - * Base serialization data type - */ -export class BaseDataType { - /** - * Serializes a given raw value - * @param {any} value - */ - serialize(value) { - abstract; - return {}; - } - - /** - * Verifies a given serialized value - * @param {any} value - * @returns {string|void} String error code or null on success - */ - verifySerializedValue(value) {} - - /** - * Deserializes a serialized value into the target object under the given key - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - abstract; - } - - /** - * Returns the json schema - */ - getAsJsonSchema() { - const key = this.getCacheKey(); - const schema = this.getAsJsonSchemaUncached(); - - if (!globalJsonSchemaDefs[key]) { - // schema.$id = key; - globalJsonSchemaDefs[key] = schema; - } - - return { - $ref: "#/definitions/" + key, - }; - } - - /** - * INTERNAL Should return the json schema representation - */ - getAsJsonSchemaUncached() { - abstract; - } - - /** - * Returns whether null values are okay - * @returns {boolean} - */ - allowNull() { - return false; - } - - // Helper methods - - /** - * Deserializes a serialized value, but performs integrity checks before - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserializeWithVerify(value, targetObject, targetKey, root) { - const errorCode = this.verifySerializedValue(value); - if (errorCode) { - return ( - "serialization verify failed: " + - errorCode + - " [value " + - JSON.stringify(value).substr(0, 100) + - "]" - ); - } - return this.deserialize(value, targetObject, targetKey, root); - } - - /** - * Should return a cacheable key - */ - getCacheKey() { - abstract; - return ""; - } -} - -export class TypeInteger extends BaseDataType { - serialize(value) { - assert(Number.isInteger(value), "Type integer got non integer for serialize: " + value); - return value; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = value; - } - - getAsJsonSchemaUncached() { - return { - type: "integer", - }; - } - - verifySerializedValue(value) { - if (!Number.isInteger(value)) { - return "Not a valid number"; - } - } - - getCacheKey() { - return "int"; - } -} - -export class TypePositiveInteger extends BaseDataType { - serialize(value) { - assert(Number.isInteger(value), "Type integer got non integer for serialize: " + value); - assert(value >= 0, "value < 0: " + value); - return value; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = value; - } - - getAsJsonSchemaUncached() { - return { - type: "integer", - minimum: 0, - }; - } - - verifySerializedValue(value) { - if (!Number.isInteger(value)) { - return "Not a valid number"; - } - if (value < 0) { - return "Negative value for positive integer"; - } - } - - getCacheKey() { - return "uint"; - } -} - -export class TypeBoolean extends BaseDataType { - serialize(value) { - assert(value === true || value === false, "Type bool got non bool for serialize: " + value); - return value; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = value; - } - - getAsJsonSchemaUncached() { - return { - type: "boolean", - }; - } - - verifySerializedValue(value) { - if (value !== true && value !== false) { - return "Not a boolean"; - } - } - - getCacheKey() { - return "bool"; - } -} - -export class TypeString extends BaseDataType { - serialize(value) { - assert(typeof value === "string", "Type string got non string for serialize: " + value); - return value; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = value; - } - getAsJsonSchemaUncached() { - return { - type: "string", - }; - } - - verifySerializedValue(value) { - if (typeof value !== "string") { - return "Not a valid string"; - } - } - - getCacheKey() { - return "string"; - } -} - -export class TypeVector extends BaseDataType { - serialize(value) { - assert(value instanceof Vector, "Type vector got non vector for serialize: " + value); - return { - x: round4Digits(value.x), - y: round4Digits(value.y), - }; - } - - getAsJsonSchemaUncached() { - return schemaObject({ - x: { - type: "number", - }, - y: { - type: "number", - }, - }); - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = new Vector(value.x, value.y); - } - - verifySerializedValue(value) { - if (!Number.isFinite(value.x) || !Number.isFinite(value.y)) { - return "Not a valid vector, missing x/y or bad data type"; - } - } - - getCacheKey() { - return "vector"; - } -} - -export class TypeTileVector extends BaseDataType { - serialize(value) { - assert(value instanceof Vector, "Type vector got non vector for serialize: " + value); - assert(Number.isInteger(value.x) && value.x > 0, "Invalid tile x:" + value.x); - assert(Number.isInteger(value.y) && value.y > 0, "Invalid tile x:" + value.y); - return { x: value.x, y: value.y }; - } - - getAsJsonSchemaUncached() { - return schemaObject({ - x: { - type: "integer", - minimum: 0, - maximum: 256, - }, - y: { - type: "integer", - minimum: 0, - maximum: 256, - }, - }); - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = new Vector(value.x, value.y); - } - - verifySerializedValue(value) { - if (!Number.isInteger(value.x) || !Number.isInteger(value.y)) { - return "Not a valid tile vector, missing x/y or bad data type"; - } - if (value.x < 0 || value.y < 0) { - return "Invalid tile vector, x or y < 0"; - } - } - - getCacheKey() { - return "tilevector"; - } -} - -export class TypeNumber extends BaseDataType { - serialize(value) { - assert(Number.isFinite(value), "Type number got non number for serialize: " + value); - assert(!Number.isNaN(value), "Value is nan: " + value); - return round4Digits(value); - } - - getAsJsonSchemaUncached() { - return { - type: "number", - }; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = value; - } - - verifySerializedValue(value) { - if (!Number.isFinite(value)) { - return "Not a valid number: " + value; - } - } - - getCacheKey() { - return "float"; - } -} - -export class TypePositiveNumber extends BaseDataType { - serialize(value) { - assert(Number.isFinite(value), "Type number got non number for serialize: " + value); - assert(value >= 0, "Postitive number got negative value: " + value); - return round4Digits(value); - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = value; - } - - getAsJsonSchemaUncached() { - return { - type: "number", - minimum: 0, - }; - } - - verifySerializedValue(value) { - if (!Number.isFinite(value)) { - return "Not a valid number: " + value; - } - if (value < 0) { - return "Positive number got negative value: " + value; - } - } - - getCacheKey() { - return "ufloat"; - } -} - -export class TypeEnum extends BaseDataType { - /** - * @param {Object.} enumeration - */ - constructor(enumeration = {}) { - super(); - this.availableValues = Object.values(enumeration); - } - - serialize(value) { - assert(this.availableValues.indexOf(value) >= 0, "Unknown value: " + value); - return value; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = value; - } - - getAsJsonSchemaUncached() { - return { - type: "string", - enum: this.availableValues, - }; - } - - verifySerializedValue(value) { - if (this.availableValues.indexOf(value) < 0) { - return "Unknown enum value: " + value; - } - } - - getCacheKey() { - return "enum." + this.availableValues.join(","); - } -} - -export class TypeEntity extends BaseDataType { - serialize(value) { - // assert(value instanceof Entity, "Not a valid entity ref: " + value); - assert(value.uid, "Entity has no uid yet"); - assert(!value.destroyed, "Entity already destroyed"); - assert(!value.queuedForDestroy, "Entity queued for destroy"); - - return value.uid; - } - - getAsJsonSchemaUncached() { - return { - type: "integer", - minimum: 0, - }; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - const entity = root.entityMgr.findByUid(value); - if (!entity) { - return "Entity not found by uid: " + value; - } - targetObject[targetKey] = entity; - } - - verifySerializedValue(value) { - if (!Number.isFinite(value)) { - return "Not a valid uuid: " + value; - } - } - - getCacheKey() { - return "entity"; - } -} - -export class TypeEntityWeakref extends BaseDataType { - serialize(value) { - if (value === null) { - return null; - } - - // assert(value instanceof Entity, "Not a valid entity ref (weak): " + value); - assert(value.uid, "Entity has no uid yet"); - if (value.destroyed || value.queuedForDestroy) { - return null; - } - return value.uid; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - if (value === null) { - targetObject[targetKey] = null; - return; - } - const entity = root.entityMgr.findByUid(value, false); - targetObject[targetKey] = entity; - } - - getAsJsonSchemaUncached() { - return { - type: ["null", "integer"], - minimum: 0, - }; - } - - allowNull() { - return true; - } - - verifySerializedValue(value) { - if (value !== null && !Number.isFinite(value)) { - return "Not a valid uuid: " + value; - } - } - - getCacheKey() { - return "entity-weakref"; - } -} - -export class TypeClass extends BaseDataType { - /** - * - * @param {FactoryTemplate<*>} registry - * @param {(GameRoot, object) => object} customResolver - */ - constructor(registry, customResolver = null) { - super(); - this.registry = registry; - this.customResolver = customResolver; - } - - serialize(value) { - assert(typeof value === "object", "Not a class instance: " + value); - return { - $: value.constructor.getId(), - data: value.serialize(), - }; - } - - getAsJsonSchemaUncached() { - const options = []; - const entries = this.registry.getEntries(); - for (let i = 0; i < entries.length; ++i) { - const entry = entries[i]; - - options.push( - schemaObject({ - $: { - type: "string", - // @ts-ignore - enum: [entry.getId()], - }, - // @ts-ignore - data: schemaToJsonSchema(entry.getCachedSchema()), - }) - ); - } - - return { oneOf: options }; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - let instance; - - if (this.customResolver) { - instance = this.customResolver(root, value); - if (!instance) { - return "Failed to call custom resolver"; - } - } else { - const instanceClass = this.registry.findById(value.$); - if (!instanceClass || !instanceClass.prototype) { - return "Invalid class id (runtime-err): " + value.$ + "->" + instanceClass; - } - instance = Object.create(instanceClass.prototype); - const errorState = instance.deserialize(value.data); - if (errorState) { - return errorState; - } - } - targetObject[targetKey] = instance; - } - - verifySerializedValue(value) { - if (!value) { - return "Got null data"; - } - - if (!this.registry.hasId(value.$)) { - return "Invalid class id: " + value.$ + " (factory is " + this.registry.getId() + ")"; - } - } - - getCacheKey() { - return "class." + this.registry.getId(); - } -} - -export class TypeClassData extends BaseDataType { - /** - * - * @param {FactoryTemplate<*>} registry - */ - constructor(registry) { - super(); - this.registry = registry; - } - - serialize(value) { - assert(typeof value === "object", "Not a class instance: " + value); - return value.serialize(); - } - - getAsJsonSchemaUncached() { - const options = []; - const entries = this.registry.getEntries(); - for (let i = 0; i < entries.length; ++i) { - const entry = entries[i]; - options.push( - schemaToJsonSchema(/** @type {typeof BasicSerializableObject} */ (entry).getCachedSchema()) - ); - } - return { oneOf: options }; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - assert(false, "can not deserialize class data of type " + this.registry.getId()); - } - - verifySerializedValue(value) { - if (!value) { - return "Got null data"; - } - } - - getCacheKey() { - return "class." + this.registry.getId(); - } -} - -export class TypeClassFromMetaclass extends BaseDataType { - /** - * - * @param {typeof BasicSerializableObject} classHandle - * @param {SingletonFactoryTemplate<*>} registry - */ - constructor(classHandle, registry) { - super(); - this.registry = registry; - this.classHandle = classHandle; - } - - serialize(value) { - assert(typeof value === "object", "Not a class instance: " + value); - return { - $: value.getMetaclass().getId(), - data: value.serialize(), - }; - } - - getAsJsonSchemaUncached() { - // const options = []; - const ids = this.registry.getAllIds(); - - return { - $: { - type: "string", - enum: ids, - }, - data: schemaToJsonSchema(this.classHandle.getCachedSchema()), - }; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - const metaClassInstance = this.registry.findById(value.$); - if (!metaClassInstance || !metaClassInstance.prototype) { - return "Invalid meta class id (runtime-err): " + value.$ + "->" + metaClassInstance; - } - - const instanceClass = metaClassInstance.getInstanceClass(); - const instance = Object.create(instanceClass.prototype); - const errorState = instance.deserialize(value.data); - if (errorState) { - return errorState; - } - targetObject[targetKey] = instance; - } - - verifySerializedValue(value) { - if (!value) { - return "Got null data"; - } - - if (!this.registry.hasId(value.$)) { - return "Invalid class id: " + value.$ + " (factory is " + this.registry.getId() + ")"; - } - } - - getCacheKey() { - return "classofmetaclass." + this.registry.getId(); - } -} - -export class TypeMetaClass extends BaseDataType { - /** - * - * @param {SingletonFactoryTemplate<*>} registry - */ - constructor(registry) { - super(); - this.registry = registry; - } - - serialize(value) { - return value.getId(); - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - const instanceClass = this.registry.findById(value); - if (!instanceClass) { - return "Invalid class id (runtime-err): " + value; - } - targetObject[targetKey] = instanceClass; - } - - getAsJsonSchemaUncached() { - return { - type: "string", - enum: this.registry.getAllIds(), - }; - } - - verifySerializedValue(value) { - if (!value) { - return "Got null data"; - } - - if (typeof value !== "string") { - return "Got non string data"; - } - - if (!this.registry.hasId(value)) { - return "Invalid class id: " + value + " (factory is " + this.registry.getId() + ")"; - } - } - - getCacheKey() { - return "metaclass." + this.registry.getId(); - } -} - -export class TypeArray extends BaseDataType { - /** - * @param {BaseDataType} innerType - */ - constructor(innerType) { - super(); - this.innerType = innerType; - } - - serialize(value) { - assert(Array.isArray(value), "Not an array"); - const result = new Array(value.length); - for (let i = 0; i < value.length; ++i) { - result[i] = this.innerType.serialize(value[i]); - } - return result; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - let destination = targetObject[targetKey]; - if (!destination) { - targetObject[targetKey] = destination = new Array(value.length); - } - - for (let i = 0; i < value.length; ++i) { - const errorStatus = this.innerType.deserializeWithVerify(value[i], destination, i, root); - if (errorStatus) { - return errorStatus; - } - } - } - - getAsJsonSchemaUncached() { - return { - type: "array", - items: this.innerType.getAsJsonSchema(), - }; - } - - verifySerializedValue(value) { - if (!Array.isArray(value)) { - return "Not an array: " + value; - } - } - - getCacheKey() { - return "array." + this.innerType.getCacheKey(); - } -} - -export class TypeFixedClass extends BaseDataType { - /** - * - * @param {typeof BasicSerializableObject} baseclass - */ - constructor(baseclass) { - super(); - this.baseclass = baseclass; - } - - serialize(value) { - assert(value instanceof this.baseclass, "Not a valid class instance"); - return value.serialize(); - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - const instance = Object.create(this.baseclass.prototype); - const errorState = instance.deserialize(value); - if (errorState) { - return "Failed to deserialize class: " + errorState; - } - targetObject[targetKey] = instance; - } - - getAsJsonSchemaUncached() { - this.baseclass.getSchema(); - this.baseclass.getCachedSchema(); - return schemaToJsonSchema(this.baseclass.getCachedSchema()); - } - - verifySerializedValue(value) { - if (!value) { - return "Got null data"; - } - } - - getCacheKey() { - return "fixedclass." + this.baseclass.getId(); - } -} - -export class TypeKeyValueMap extends BaseDataType { - /** - * @param {BaseDataType} valueType - * @param {boolean=} includeEmptyValues - */ - constructor(valueType, includeEmptyValues = true) { - super(); - this.valueType = valueType; - this.includeEmptyValues = includeEmptyValues; - } - - serialize(value) { - assert(typeof value === "object", "not an object"); - let result = {}; - for (const key in value) { - const serialized = this.valueType.serialize(value[key]); - if (!this.includeEmptyValues && typeof serialized === "object") { - if ( - serialized.$ && - typeof serialized.data === "object" && - Object.keys(serialized.data).length === 0 - ) { - continue; - } else if (Object.keys(serialized).length === 0) { - continue; - } - } - - result[key] = serialized; - } - return result; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - let result = {}; - for (const key in value) { - const errorCode = this.valueType.deserializeWithVerify(value[key], result, key, root); - if (errorCode) { - return errorCode; - } - } - targetObject[targetKey] = result; - } - - getAsJsonSchemaUncached() { - return { - type: "object", - additionalProperties: this.valueType.getAsJsonSchema(), - }; - } - - verifySerializedValue(value) { - if (typeof value !== "object") { - return "KV map is not an object"; - } - } - - getCacheKey() { - return "kvmap." + this.valueType.getCacheKey(); - } -} - -export class TypeClassId extends BaseDataType { - /** - * @param {FactoryTemplate<*>|SingletonFactoryTemplate<*>} registry - */ - constructor(registry) { - super(); - this.registry = registry; - } - - serialize(value) { - assert(typeof value === "string", "Not a valid string"); - assert(this.registry.hasId(value), "Id " + value + " not found in registry"); - return value; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - targetObject[targetKey] = value; - } - - getAsJsonSchemaUncached() { - return { - type: "string", - enum: this.registry.getAllIds(), - }; - } - - verifySerializedValue(value) { - if (typeof value !== "string") { - return "Not a valid registry id key: " + value; - } - if (!this.registry.hasId(value)) { - return "Id " + value + " not known to registry"; - } - } - - getCacheKey() { - return "classid." + this.registry.getId(); - } -} - -export class TypePair extends BaseDataType { - /** - * @param {BaseDataType} type1 - * @param {BaseDataType} type2 - */ - constructor(type1, type2) { - super(); - assert(type1 && type1 instanceof BaseDataType, "bad first type given for pair"); - assert(type2 && type2 instanceof BaseDataType, "bad second type given for pair"); - this.type1 = type1; - this.type2 = type2; - } - - serialize(value) { - assert(Array.isArray(value), "pair: not an array"); - assert(value.length === 2, "pair: length != 2"); - return [this.type1.serialize(value[0]), this.type2.serialize(value[1])]; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - const result = [undefined, undefined]; - - let errorCode = this.type1.deserialize(value[0], result, 0, root); - if (errorCode) { - return errorCode; - } - errorCode = this.type2.deserialize(value[1], result, 1, root); - if (errorCode) { - return errorCode; - } - - targetObject[targetKey] = result; - } - - getAsJsonSchemaUncached() { - return { - type: "array", - minLength: 2, - maxLength: 2, - items: [this.type1.getAsJsonSchema(), this.type2.getAsJsonSchema()], - }; - } - - verifySerializedValue(value) { - if (!Array.isArray(value)) { - return "Pair is not an array"; - } - if (value.length !== 2) { - return "Pair length != 2"; - } - let errorCode = this.type1.verifySerializedValue(value[0]); - if (errorCode) { - return errorCode; - } - errorCode = this.type2.verifySerializedValue(value[1]); - if (errorCode) { - return errorCode; - } - } - - getCacheKey() { - return "pair.(" + this.type1.getCacheKey() + "," + this.type2.getCacheKey + ")"; - } -} - -export class TypeNullable extends BaseDataType { - /** - * @param {BaseDataType} wrapped - */ - constructor(wrapped) { - super(); - this.wrapped = wrapped; - } - - serialize(value) { - if (value === null || value === undefined) { - return null; - } - return this.wrapped.serialize(value); - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - if (value === null || value === undefined) { - targetObject[targetKey] = null; - return; - } - return this.wrapped.deserialize(value, targetObject, targetKey, root); - } - - verifySerializedValue(value) { - if (value === null) { - return; - } - return this.wrapped.verifySerializedValue(value); - } - - getAsJsonSchemaUncached() { - return { - oneOf: [ - { - type: "null", - }, - this.wrapped.getAsJsonSchema(), - ], - }; - } - - allowNull() { - return true; - } - - getCacheKey() { - return "nullable." + this.wrapped.getCacheKey(); - } -} - -export class TypeStructuredObject extends BaseDataType { - /** - * @param {Object.} descriptor - */ - constructor(descriptor) { - super(); - this.descriptor = descriptor; - } - - serialize(value) { - assert(typeof value === "object", "not an object"); - let result = {}; - for (const key in this.descriptor) { - // assert(value.hasOwnProperty(key), "Serialization: Object does not have", key, "property!"); - result[key] = this.descriptor[key].serialize(value[key]); - } - return result; - } - - /** - * @see BaseDataType.deserialize - * @param {any} value - * @param {GameRoot} root - * @param {object} targetObject - * @param {string|number} targetKey - * @returns {string|void} String error code or null on success - */ - deserialize(value, targetObject, targetKey, root) { - let target = targetObject[targetKey]; - if (!target) { - targetObject[targetKey] = target = {}; - } - - for (const key in value) { - const valueType = this.descriptor[key]; - const errorCode = valueType.deserializeWithVerify(value[key], target, key, root); - if (errorCode) { - return errorCode; - } - } - } - - getAsJsonSchemaUncached() { - let properties = {}; - for (const key in this.descriptor) { - properties[key] = this.descriptor[key].getAsJsonSchema(); - } - - return { - type: "object", - required: Object.keys(this.descriptor), - properties, - }; - } - - verifySerializedValue(value) { - if (typeof value !== "object") { - return "structured object is not an object"; - } - for (const key in this.descriptor) { - if (!value.hasOwnProperty(key)) { - return "structured object is missing key " + key; - } - const subError = this.descriptor[key].verifySerializedValue(value[key]); - if (subError) { - return "structured object::" + subError; - } - } - } - - getCacheKey() { - let props = []; - for (const key in this.descriptor) { - props.push(key + "=" + this.descriptor[key].getCacheKey()); - } - return "structured[" + props.join(",") + "]"; - } -} +/* typehints:start */ +import { GameRoot } from "../game/root"; +import { BasicSerializableObject } from "./serialization"; +/* typehints:end */ + +import { Vector } from "../core/vector"; +import { round4Digits } from "../core/utils"; +export const globalJsonSchemaDefs = {}; + +/** + * + * @param {import("./serialization").Schema} schema + */ +export function schemaToJsonSchema(schema) { + const jsonSchema = { + type: "object", + additionalProperties: false, + required: [], + properties: {}, + }; + + for (const key in schema) { + const subSchema = schema[key].getAsJsonSchema(); + jsonSchema.required.push(key); + jsonSchema.properties[key] = subSchema; + } + + return jsonSchema; +} + +/** + * Helper function to create a json schema object + * @param {any} properties + */ +function schemaObject(properties) { + return { + type: "object", + required: Object.keys(properties).slice(), + additionalProperties: false, + properties, + }; +} + +/** + * Base serialization data type + */ +export class BaseDataType { + /** + * Serializes a given raw value + * @param {any} value + */ + serialize(value) { + abstract; + return {}; + } + + /** + * Verifies a given serialized value + * @param {any} value + * @returns {string|void} String error code or null on success + */ + verifySerializedValue(value) {} + + /** + * Deserializes a serialized value into the target object under the given key + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + abstract; + } + + /** + * Returns the json schema + */ + getAsJsonSchema() { + const key = this.getCacheKey(); + const schema = this.getAsJsonSchemaUncached(); + + if (!globalJsonSchemaDefs[key]) { + // schema.$id = key; + globalJsonSchemaDefs[key] = schema; + } + + return { + $ref: "#/definitions/" + key, + }; + } + + /** + * INTERNAL Should return the json schema representation + */ + getAsJsonSchemaUncached() { + abstract; + } + + /** + * Returns whether null values are okay + * @returns {boolean} + */ + allowNull() { + return false; + } + + // Helper methods + + /** + * Deserializes a serialized value, but performs integrity checks before + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserializeWithVerify(value, targetObject, targetKey, root) { + const errorCode = this.verifySerializedValue(value); + if (errorCode) { + return ( + "serialization verify failed: " + + errorCode + + " [value " + + (JSON.stringify(value) || "").substr(0, 100) + + "]" + ); + } + return this.deserialize(value, targetObject, targetKey, root); + } + + /** + * Should return a cacheable key + */ + getCacheKey() { + abstract; + return ""; + } +} + +export class TypeInteger extends BaseDataType { + serialize(value) { + assert(Number.isInteger(value), "Type integer got non integer for serialize: " + value); + return value; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = value; + } + + getAsJsonSchemaUncached() { + return { + type: "integer", + }; + } + + verifySerializedValue(value) { + if (!Number.isInteger(value)) { + return "Not a valid number"; + } + } + + getCacheKey() { + return "int"; + } +} + +export class TypePositiveInteger extends BaseDataType { + serialize(value) { + assert(Number.isInteger(value), "Type integer got non integer for serialize: " + value); + assert(value >= 0, "value < 0: " + value); + return value; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = value; + } + + getAsJsonSchemaUncached() { + return { + type: "integer", + minimum: 0, + }; + } + + verifySerializedValue(value) { + if (!Number.isInteger(value)) { + return "Not a valid number"; + } + if (value < 0) { + return "Negative value for positive integer"; + } + } + + getCacheKey() { + return "uint"; + } +} + +export class TypeBoolean extends BaseDataType { + serialize(value) { + assert(value === true || value === false, "Type bool got non bool for serialize: " + value); + return value; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = value; + } + + getAsJsonSchemaUncached() { + return { + type: "boolean", + }; + } + + verifySerializedValue(value) { + if (value !== true && value !== false) { + return "Not a boolean"; + } + } + + getCacheKey() { + return "bool"; + } +} + +export class TypeString extends BaseDataType { + serialize(value) { + assert(typeof value === "string", "Type string got non string for serialize: " + value); + return value; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = value; + } + getAsJsonSchemaUncached() { + return { + type: "string", + }; + } + + verifySerializedValue(value) { + if (typeof value !== "string") { + return "Not a valid string"; + } + } + + getCacheKey() { + return "string"; + } +} + +export class TypeVector extends BaseDataType { + serialize(value) { + assert(value instanceof Vector, "Type vector got non vector for serialize: " + value); + return { + x: round4Digits(value.x), + y: round4Digits(value.y), + }; + } + + getAsJsonSchemaUncached() { + return schemaObject({ + x: { + type: "number", + }, + y: { + type: "number", + }, + }); + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = new Vector(value.x, value.y); + } + + verifySerializedValue(value) { + if (!Number.isFinite(value.x) || !Number.isFinite(value.y)) { + return "Not a valid vector, missing x/y or bad data type"; + } + } + + getCacheKey() { + return "vector"; + } +} + +export class TypeTileVector extends BaseDataType { + serialize(value) { + assert(value instanceof Vector, "Type vector got non vector for serialize: " + value); + assert(Number.isInteger(value.x) && value.x > 0, "Invalid tile x:" + value.x); + assert(Number.isInteger(value.y) && value.y > 0, "Invalid tile x:" + value.y); + return { x: value.x, y: value.y }; + } + + getAsJsonSchemaUncached() { + return schemaObject({ + x: { + type: "integer", + minimum: 0, + maximum: 256, + }, + y: { + type: "integer", + minimum: 0, + maximum: 256, + }, + }); + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = new Vector(value.x, value.y); + } + + verifySerializedValue(value) { + if (!Number.isInteger(value.x) || !Number.isInteger(value.y)) { + return "Not a valid tile vector, missing x/y or bad data type"; + } + if (value.x < 0 || value.y < 0) { + return "Invalid tile vector, x or y < 0"; + } + } + + getCacheKey() { + return "tilevector"; + } +} + +export class TypeNumber extends BaseDataType { + serialize(value) { + assert(Number.isFinite(value), "Type number got non number for serialize: " + value); + assert(!Number.isNaN(value), "Value is nan: " + value); + return round4Digits(value); + } + + getAsJsonSchemaUncached() { + return { + type: "number", + }; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = value; + } + + verifySerializedValue(value) { + if (!Number.isFinite(value)) { + return "Not a valid number: " + value; + } + } + + getCacheKey() { + return "float"; + } +} + +export class TypePositiveNumber extends BaseDataType { + serialize(value) { + assert(Number.isFinite(value), "Type number got non number for serialize: " + value); + assert(value >= 0, "Postitive number got negative value: " + value); + return round4Digits(value); + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = value; + } + + getAsJsonSchemaUncached() { + return { + type: "number", + minimum: 0, + }; + } + + verifySerializedValue(value) { + if (!Number.isFinite(value)) { + return "Not a valid number: " + value; + } + if (value < 0) { + return "Positive number got negative value: " + value; + } + } + + getCacheKey() { + return "ufloat"; + } +} + +export class TypeEnum extends BaseDataType { + /** + * @param {Object.} enumeration + */ + constructor(enumeration = {}) { + super(); + this.availableValues = Object.values(enumeration); + } + + serialize(value) { + assert(this.availableValues.indexOf(value) >= 0, "Unknown value: " + value); + return value; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = value; + } + + getAsJsonSchemaUncached() { + return { + type: "string", + enum: this.availableValues, + }; + } + + verifySerializedValue(value) { + if (this.availableValues.indexOf(value) < 0) { + return "Unknown enum value: " + value; + } + } + + getCacheKey() { + return "enum." + this.availableValues.join(","); + } +} + +export class TypeEntity extends BaseDataType { + serialize(value) { + // assert(value instanceof Entity, "Not a valid entity ref: " + value); + assert(value.uid, "Entity has no uid yet"); + assert(!value.destroyed, "Entity already destroyed"); + assert(!value.queuedForDestroy, "Entity queued for destroy"); + + return value.uid; + } + + getAsJsonSchemaUncached() { + return { + type: "integer", + minimum: 0, + }; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + const entity = root.entityMgr.findByUid(value); + if (!entity) { + return "Entity not found by uid: " + value; + } + targetObject[targetKey] = entity; + } + + verifySerializedValue(value) { + if (!Number.isFinite(value)) { + return "Not a valid uuid: " + value; + } + } + + getCacheKey() { + return "entity"; + } +} + +export class TypeEntityWeakref extends BaseDataType { + serialize(value) { + if (value === null) { + return null; + } + + // assert(value instanceof Entity, "Not a valid entity ref (weak): " + value); + assert(value.uid, "Entity has no uid yet"); + if (value.destroyed || value.queuedForDestroy) { + return null; + } + return value.uid; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + if (value === null) { + targetObject[targetKey] = null; + return; + } + const entity = root.entityMgr.findByUid(value, false); + targetObject[targetKey] = entity; + } + + getAsJsonSchemaUncached() { + return { + type: ["null", "integer"], + minimum: 0, + }; + } + + allowNull() { + return true; + } + + verifySerializedValue(value) { + if (value !== null && !Number.isFinite(value)) { + return "Not a valid uuid: " + value; + } + } + + getCacheKey() { + return "entity-weakref"; + } +} + +export class TypeClass extends BaseDataType { + /** + * + * @param {FactoryTemplate<*>} registry + * @param {(GameRoot, object) => object} customResolver + */ + constructor(registry, customResolver = null) { + super(); + this.registry = registry; + this.customResolver = customResolver; + } + + serialize(value) { + assert(typeof value === "object", "Not a class instance: " + value); + return { + $: value.constructor.getId(), + data: value.serialize(), + }; + } + + getAsJsonSchemaUncached() { + const options = []; + const entries = this.registry.getEntries(); + for (let i = 0; i < entries.length; ++i) { + const entry = entries[i]; + + options.push( + schemaObject({ + $: { + type: "string", + // @ts-ignore + enum: [entry.getId()], + }, + // @ts-ignore + data: schemaToJsonSchema(entry.getCachedSchema()), + }) + ); + } + + return { oneOf: options }; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + let instance; + + if (this.customResolver) { + instance = this.customResolver(root, value); + if (!instance) { + return "Failed to call custom resolver"; + } + } else { + const instanceClass = this.registry.findById(value.$); + if (!instanceClass || !instanceClass.prototype) { + return "Invalid class id (runtime-err): " + value.$ + "->" + instanceClass; + } + instance = Object.create(instanceClass.prototype); + const errorState = instance.deserialize(value.data); + if (errorState) { + return errorState; + } + } + targetObject[targetKey] = instance; + } + + verifySerializedValue(value) { + if (!value) { + return "Got null data"; + } + + if (!this.registry.hasId(value.$)) { + return "Invalid class id: " + value.$ + " (factory is " + this.registry.getId() + ")"; + } + } + + getCacheKey() { + return "class." + this.registry.getId(); + } +} + +export class TypeClassData extends BaseDataType { + /** + * + * @param {FactoryTemplate<*>} registry + */ + constructor(registry) { + super(); + this.registry = registry; + } + + serialize(value) { + assert(typeof value === "object", "Not a class instance: " + value); + return value.serialize(); + } + + getAsJsonSchemaUncached() { + const options = []; + const entries = this.registry.getEntries(); + for (let i = 0; i < entries.length; ++i) { + const entry = entries[i]; + options.push( + schemaToJsonSchema(/** @type {typeof BasicSerializableObject} */ (entry).getCachedSchema()) + ); + } + return { oneOf: options }; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + assert(false, "can not deserialize class data of type " + this.registry.getId()); + } + + verifySerializedValue(value) { + if (!value) { + return "Got null data"; + } + } + + getCacheKey() { + return "class." + this.registry.getId(); + } +} + +export class TypeClassFromMetaclass extends BaseDataType { + /** + * + * @param {typeof BasicSerializableObject} classHandle + * @param {SingletonFactoryTemplate<*>} registry + */ + constructor(classHandle, registry) { + super(); + this.registry = registry; + this.classHandle = classHandle; + } + + serialize(value) { + assert(typeof value === "object", "Not a class instance: " + value); + return { + $: value.getMetaclass().getId(), + data: value.serialize(), + }; + } + + getAsJsonSchemaUncached() { + // const options = []; + const ids = this.registry.getAllIds(); + + return { + $: { + type: "string", + enum: ids, + }, + data: schemaToJsonSchema(this.classHandle.getCachedSchema()), + }; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + const metaClassInstance = this.registry.findById(value.$); + if (!metaClassInstance || !metaClassInstance.prototype) { + return "Invalid meta class id (runtime-err): " + value.$ + "->" + metaClassInstance; + } + + const instanceClass = metaClassInstance.getInstanceClass(); + const instance = Object.create(instanceClass.prototype); + const errorState = instance.deserialize(value.data); + if (errorState) { + return errorState; + } + targetObject[targetKey] = instance; + } + + verifySerializedValue(value) { + if (!value) { + return "Got null data"; + } + + if (!this.registry.hasId(value.$)) { + return "Invalid class id: " + value.$ + " (factory is " + this.registry.getId() + ")"; + } + } + + getCacheKey() { + return "classofmetaclass." + this.registry.getId(); + } +} + +export class TypeMetaClass extends BaseDataType { + /** + * + * @param {SingletonFactoryTemplate<*>} registry + */ + constructor(registry) { + super(); + this.registry = registry; + } + + serialize(value) { + return value.getId(); + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + const instanceClass = this.registry.findById(value); + if (!instanceClass) { + return "Invalid class id (runtime-err): " + value; + } + targetObject[targetKey] = instanceClass; + } + + getAsJsonSchemaUncached() { + return { + type: "string", + enum: this.registry.getAllIds(), + }; + } + + verifySerializedValue(value) { + if (!value) { + return "Got null data"; + } + + if (typeof value !== "string") { + return "Got non string data"; + } + + if (!this.registry.hasId(value)) { + return "Invalid class id: " + value + " (factory is " + this.registry.getId() + ")"; + } + } + + getCacheKey() { + return "metaclass." + this.registry.getId(); + } +} + +export class TypeArray extends BaseDataType { + /** + * @param {BaseDataType} innerType + */ + constructor(innerType, fixedSize = false) { + super(); + this.fixedSize = fixedSize; + this.innerType = innerType; + } + + serialize(value) { + assert(Array.isArray(value), "Not an array"); + const result = new Array(value.length); + for (let i = 0; i < value.length; ++i) { + result[i] = this.innerType.serialize(value[i]); + } + return result; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + let destination = targetObject[targetKey]; + if (!destination) { + targetObject[targetKey] = destination = new Array(value.length); + } + + const size = this.fixedSize ? Math.min(value.length, destination.length) : value.length; + + for (let i = 0; i < size; ++i) { + const errorStatus = this.innerType.deserializeWithVerify(value[i], destination, i, root); + if (errorStatus) { + return errorStatus; + } + } + } + + getAsJsonSchemaUncached() { + return { + type: "array", + items: this.innerType.getAsJsonSchema(), + }; + } + + verifySerializedValue(value) { + if (!Array.isArray(value)) { + return "Not an array: " + value; + } + } + + getCacheKey() { + return "array." + this.innerType.getCacheKey(); + } +} + +export class TypeFixedClass extends BaseDataType { + /** + * + * @param {typeof BasicSerializableObject} baseclass + */ + constructor(baseclass) { + super(); + this.baseclass = baseclass; + } + + serialize(value) { + assert(value instanceof this.baseclass, "Not a valid class instance"); + return value.serialize(); + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + const instance = Object.create(this.baseclass.prototype); + const errorState = instance.deserialize(value); + if (errorState) { + return "Failed to deserialize class: " + errorState; + } + targetObject[targetKey] = instance; + } + + getAsJsonSchemaUncached() { + this.baseclass.getSchema(); + this.baseclass.getCachedSchema(); + return schemaToJsonSchema(this.baseclass.getCachedSchema()); + } + + verifySerializedValue(value) { + if (!value) { + return "Got null data"; + } + } + + getCacheKey() { + return "fixedclass." + this.baseclass.getId(); + } +} + +export class TypeKeyValueMap extends BaseDataType { + /** + * @param {BaseDataType} valueType + * @param {boolean=} includeEmptyValues + */ + constructor(valueType, includeEmptyValues = true) { + super(); + this.valueType = valueType; + this.includeEmptyValues = includeEmptyValues; + } + + serialize(value) { + assert(typeof value === "object", "not an object"); + let result = {}; + for (const key in value) { + const serialized = this.valueType.serialize(value[key]); + if (!this.includeEmptyValues && typeof serialized === "object") { + if ( + serialized.$ && + typeof serialized.data === "object" && + Object.keys(serialized.data).length === 0 + ) { + continue; + } else if (Object.keys(serialized).length === 0) { + continue; + } + } + + result[key] = serialized; + } + return result; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + let result = {}; + for (const key in value) { + const errorCode = this.valueType.deserializeWithVerify(value[key], result, key, root); + if (errorCode) { + return errorCode; + } + } + targetObject[targetKey] = result; + } + + getAsJsonSchemaUncached() { + return { + type: "object", + additionalProperties: this.valueType.getAsJsonSchema(), + }; + } + + verifySerializedValue(value) { + if (typeof value !== "object") { + return "KV map is not an object"; + } + } + + getCacheKey() { + return "kvmap." + this.valueType.getCacheKey(); + } +} + +export class TypeClassId extends BaseDataType { + /** + * @param {FactoryTemplate<*>|SingletonFactoryTemplate<*>} registry + */ + constructor(registry) { + super(); + this.registry = registry; + } + + serialize(value) { + assert(typeof value === "string", "Not a valid string"); + assert(this.registry.hasId(value), "Id " + value + " not found in registry"); + return value; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + targetObject[targetKey] = value; + } + + getAsJsonSchemaUncached() { + return { + type: "string", + enum: this.registry.getAllIds(), + }; + } + + verifySerializedValue(value) { + if (typeof value !== "string") { + return "Not a valid registry id key: " + value; + } + if (!this.registry.hasId(value)) { + return "Id " + value + " not known to registry"; + } + } + + getCacheKey() { + return "classid." + this.registry.getId(); + } +} + +export class TypePair extends BaseDataType { + /** + * @param {BaseDataType} type1 + * @param {BaseDataType} type2 + */ + constructor(type1, type2) { + super(); + assert(type1 && type1 instanceof BaseDataType, "bad first type given for pair"); + assert(type2 && type2 instanceof BaseDataType, "bad second type given for pair"); + this.type1 = type1; + this.type2 = type2; + } + + serialize(value) { + assert(Array.isArray(value), "pair: not an array"); + assert(value.length === 2, "pair: length != 2"); + return [this.type1.serialize(value[0]), this.type2.serialize(value[1])]; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + const result = [undefined, undefined]; + + let errorCode = this.type1.deserialize(value[0], result, 0, root); + if (errorCode) { + return errorCode; + } + errorCode = this.type2.deserialize(value[1], result, 1, root); + if (errorCode) { + return errorCode; + } + + targetObject[targetKey] = result; + } + + getAsJsonSchemaUncached() { + return { + type: "array", + minLength: 2, + maxLength: 2, + items: [this.type1.getAsJsonSchema(), this.type2.getAsJsonSchema()], + }; + } + + verifySerializedValue(value) { + if (!Array.isArray(value)) { + return "Pair is not an array"; + } + if (value.length !== 2) { + return "Pair length != 2"; + } + let errorCode = this.type1.verifySerializedValue(value[0]); + if (errorCode) { + return errorCode; + } + errorCode = this.type2.verifySerializedValue(value[1]); + if (errorCode) { + return errorCode; + } + } + + getCacheKey() { + return "pair.(" + this.type1.getCacheKey() + "," + this.type2.getCacheKey + ")"; + } +} + +export class TypeNullable extends BaseDataType { + /** + * @param {BaseDataType} wrapped + */ + constructor(wrapped) { + super(); + this.wrapped = wrapped; + } + + serialize(value) { + if (value === null || value === undefined) { + return null; + } + return this.wrapped.serialize(value); + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + if (value === null || value === undefined) { + targetObject[targetKey] = null; + return; + } + return this.wrapped.deserialize(value, targetObject, targetKey, root); + } + + verifySerializedValue(value) { + if (value === null) { + return; + } + return this.wrapped.verifySerializedValue(value); + } + + getAsJsonSchemaUncached() { + return { + oneOf: [ + { + type: "null", + }, + this.wrapped.getAsJsonSchema(), + ], + }; + } + + allowNull() { + return true; + } + + getCacheKey() { + return "nullable." + this.wrapped.getCacheKey(); + } +} + +export class TypeStructuredObject extends BaseDataType { + /** + * @param {Object.} descriptor + */ + constructor(descriptor) { + super(); + this.descriptor = descriptor; + } + + serialize(value) { + assert(typeof value === "object", "not an object"); + let result = {}; + for (const key in this.descriptor) { + // assert(value.hasOwnProperty(key), "Serialization: Object does not have", key, "property!"); + result[key] = this.descriptor[key].serialize(value[key]); + } + return result; + } + + /** + * @see BaseDataType.deserialize + * @param {any} value + * @param {GameRoot} root + * @param {object} targetObject + * @param {string|number} targetKey + * @returns {string|void} String error code or null on success + */ + deserialize(value, targetObject, targetKey, root) { + let target = targetObject[targetKey]; + if (!target) { + targetObject[targetKey] = target = {}; + } + + for (const key in value) { + const valueType = this.descriptor[key]; + const errorCode = valueType.deserializeWithVerify(value[key], target, key, root); + if (errorCode) { + return errorCode; + } + } + } + + getAsJsonSchemaUncached() { + let properties = {}; + for (const key in this.descriptor) { + properties[key] = this.descriptor[key].getAsJsonSchema(); + } + + return { + type: "object", + required: Object.keys(this.descriptor), + properties, + }; + } + + verifySerializedValue(value) { + if (typeof value !== "object") { + return "structured object is not an object"; + } + for (const key in this.descriptor) { + if (!value.hasOwnProperty(key)) { + return "structured object is missing key " + key; + } + const subError = this.descriptor[key].verifySerializedValue(value[key]); + if (subError) { + return "structured object::" + subError; + } + } + } + + getCacheKey() { + let props = []; + for (const key in this.descriptor) { + props.push(key + "=" + this.descriptor[key].getCacheKey()); + } + return "structured[" + props.join(",") + "]"; + } +} diff --git a/src/js/savegame/serializer_internal.js b/src/js/savegame/serializer_internal.js index fa02a437..c75cebad 100644 --- a/src/js/savegame/serializer_internal.js +++ b/src/js/savegame/serializer_internal.js @@ -80,7 +80,10 @@ export class SerializerInternal { for (const componentId in data) { if (!entity.components[componentId]) { if (G_IS_DEV && !globalConfig.debug.disableSlowAsserts) { - logger.warn("Entity no longer has component:", componentId); + // @ts-ignore + if (++window.componentWarningsShown < 100) { + logger.warn("Entity no longer has component:", componentId); + } } continue; } diff --git a/src/js/states/ingame.js b/src/js/states/ingame.js index 2dd2db76..316c536c 100644 --- a/src/js/states/ingame.js +++ b/src/js/states/ingame.js @@ -285,14 +285,10 @@ export class InGameState extends GameState { */ stage7Warmup() { if (this.switchStage(stages.s7_warmup)) { - if (G_IS_DEV && globalConfig.debug.noArtificialDelays) { - this.warmupTimeSeconds = 0.05; + if (this.creationPayload.fastEnter) { + this.warmupTimeSeconds = globalConfig.warmupTimeSecondsFast; } else { - if (this.creationPayload.fastEnter) { - this.warmupTimeSeconds = globalConfig.warmupTimeSecondsFast; - } else { - this.warmupTimeSeconds = globalConfig.warmupTimeSecondsRegular; - } + this.warmupTimeSeconds = globalConfig.warmupTimeSecondsRegular; } } } diff --git a/src/js/states/main_menu.js b/src/js/states/main_menu.js index a3f06ca0..fa177874 100644 --- a/src/js/states/main_menu.js +++ b/src/js/states/main_menu.js @@ -320,20 +320,23 @@ export class MainMenuState extends GameState { }); optionSelected.add(value => { - this.app.settings.updateLanguage(value); - if (setting.restartRequired) { - if (this.app.platformWrapper.getSupportsRestart()) { - this.app.platformWrapper.performRestart(); - } else { - this.dialogs.showInfo(T.dialogs.restartRequired.title, T.dialogs.restartRequired.text, [ - "ok:good", - ]); + this.app.settings.updateLanguage(value).then(() => { + if (setting.restartRequired) { + if (this.app.platformWrapper.getSupportsRestart()) { + this.app.platformWrapper.performRestart(); + } else { + this.dialogs.showInfo( + T.dialogs.restartRequired.title, + T.dialogs.restartRequired.text, + ["ok:good"] + ); + } } - } - if (setting.changeCb) { - setting.changeCb(this.app, value); - } + if (setting.changeCb) { + setting.changeCb(this.app, value); + } + }); // Update current icon this.htmlElement.querySelector("button.languageChoose").setAttribute("data-languageIcon", value); diff --git a/src/js/states/preload.js b/src/js/states/preload.js index c1746da6..811b9419 100644 --- a/src/js/states/preload.js +++ b/src/js/states/preload.js @@ -21,10 +21,6 @@ export class PreloadState extends GameState {
Booting - - - 0% -
@@ -56,10 +52,6 @@ export class PreloadState extends GameState { /** @type {HTMLElement} */ this.statusText = this.htmlElement.querySelector(".loadingStatus > .desc"); - /** @type {HTMLElement} */ - this.statusBar = this.htmlElement.querySelector(".loadingStatus > .bar > .inner"); - /** @type {HTMLElement} */ - this.statusBarText = this.htmlElement.querySelector(".loadingStatus > .bar > .status"); /** @type {HTMLElement} */ this.hintsText = this.htmlElement.querySelector(".prefab_GameHint"); @@ -67,7 +59,6 @@ export class PreloadState extends GameState { this.nextHintDuration = 0; this.currentStatus = "booting"; - this.currentIndex = 0; this.startLoading(); } @@ -259,16 +250,8 @@ export class PreloadState extends GameState { */ setStatus(text) { logger.log("✅ " + text); - this.currentIndex += 1; this.currentStatus = text; this.statusText.innerText = text; - - const numSteps = 10; // FIXME - - const percentage = (this.currentIndex / numSteps) * 100.0; - this.statusBar.style.width = percentage + "%"; - this.statusBarText.innerText = findNiceValue(percentage) + "%"; - return Promise.resolve(); } diff --git a/sync-translations.js b/sync-translations.js index 649daf1e..356a4aba 100644 --- a/sync-translations.js +++ b/sync-translations.js @@ -36,7 +36,7 @@ function match(originalObj, translatedObj, path = "/") { if (typeof valueOriginal === "object") { match(valueOriginal, valueMatching, path + key + "/"); } else if (typeof valueOriginal === "string") { - // todo + // @todo const originalPlaceholders = matchAll(valueOriginal, placeholderRegexp).toArray(); const translatedPlaceholders = matchAll(valueMatching, placeholderRegexp).toArray(); diff --git a/translations/base-ar.yaml b/translations/base-ar.yaml index 3c76c1d5..7d93de52 100644 --- a/translations/base-ar.yaml +++ b/translations/base-ar.yaml @@ -196,6 +196,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Move @@ -304,6 +312,30 @@ ingame: and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 Miner n_miners: Miners @@ -694,7 +726,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -864,6 +897,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Keybindings diff --git a/translations/base-cat.yaml b/translations/base-cat.yaml index 1d105a5a..c852178b 100644 --- a/translations/base-cat.yaml +++ b/translations/base-cat.yaml @@ -93,9 +93,9 @@ mainMenu: discordLink: Servidor Discord oficial helpTranslate: Ajuda a traduir-lo! madeBy: Creat per - browserWarning: >- - - Disculpa, però el joc funcionarà lent al teu navegador! Aconsegueix el joc complet o descarrega't chrome per una millor experiència. + browserWarning: Disculpa, però el joc funcionarà lent al teu navegador! + Aconsegueix el joc complet o descarrega't chrome per una millor + experiència. savegameLevel: Nivell savegameLevelUnknown: Nivell desconegut savegameUnnamed: Unnamed @@ -205,6 +205,14 @@ dialogs: renameSavegame: title: Canviar el nom. desc: Canviar el nom de la partida guardada. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Moure @@ -315,6 +323,30 @@ ingame: ràpidament.

Pista: Manté pressionat SHIFT per a col·locar més extractors, i utilitza R per a rotar-los." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 Miner n_miners: Miners @@ -712,12 +744,13 @@ storyRewards: passar-ho bé! reward_wires_painter_and_levers: title: Cables i Pintador Quàdruple - desc: "\"Has desbloquejat la Capa de Cables: És una capa - separada damunt la capa normal i introdueix moltes mecàniques - noves!

Per començar t'he desbloquejat el Pintador - Quàdruple. Conecta les ranures que vols pintar a la capa de - Cables!

Per canviar a la capa de Cables, prem - E.\"" + desc: "You just unlocked the Wires Layer: It is a separate + layer on top of the regular layer and introduces a lot of new + mechanics!

For the beginning I unlocked you the Quad + Painter - Connect the slots you would like to paint with on + the wires layer!

To switch to the wires layer, press + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Filtre d'Ítems desc: Has desbloquejat el Filtre d'Ítems! Filtrarà els ítems a @@ -892,6 +925,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Combinacions de tecles diff --git a/translations/base-cz.yaml b/translations/base-cz.yaml index eae8d58d..a1f068b9 100644 --- a/translations/base-cz.yaml +++ b/translations/base-cz.yaml @@ -1,56 +1,53 @@ steamPage: - shortText: shapez.io je hra o stavbě továren pro automatizaci výroby a + shortText: shapez.io je hra o stavbě továren na automatizaci výroby a kombinování čím dál složitějších tvarů na nekonečné mapě. discordLinkShort: Oficiální Discord intro: >- - Shapez.io je relaxační hra, ve které musíte stavět továrny pro - automatizaci výroby geometrických tvarů. + Máte rádi automatizaci? Tak to jste na správném místě! - Jak se zvyšuje úroveň, tvary se stávají stále složitějšími a vy se musíte rozšířit po nekonečné mapě. + shapez.io je relaxační hra, ve které musíte stavět továrny na automatizaci výroby geometrických tvarů. Jak se zvyšuje úroveň, tvary se stávají stále složitějšími a vy se musíte rozšířit po nekonečné mapě. - A jako by to nestačilo, musíte také produkovat exponenciálně více, abyste uspokojili požadavky - jediná věc, která pomáhá, je škálování! + A jako by to nestačilo, musíte také produkovat exponenciálně více, abyste uspokojili požadavky - jediná věc, která pomáhá, je škálování! Zatímco na začátku tvary pouze zpracováváte, později je musíte obarvit - těžbou a mícháním barev! - Zatímco tvary zpracováváte pouze na začátku, musíte je později obarvit - k tomu musíte těžit a míchat barvy! - - Koupením hry na platformě Steam vám dá přístup k plné verzi hry, ale také můžete hrát demo verzi na shapez.io a potom se můžete rozhodnou jestli hru koupíte! + Koupením hry na platformě Steam získáte přístup k plné verzi hry, ale také můžete nejdříve hrát demo verzi na shapez.io a až potom se rozhodnout! title_advantages: Výhody samostatné verze hry advantages: - - 12 Nových úrovní celkem 26 úrovní + - 12 Nových úrovní z celkových 26 úrovní - 18 Nových budov pro plně automatizovanou továrnu! - - 20 vylepšení pro mnoho hodin zábavy! - - Wires Update pro zcela nové rozměry! - - Dark Mode! + - 20 Řad vylepšení pro mnoho hodin zábavy! + - Wires Update pro zcela novou dimenzi! + - Tmavý mód! - Neomezený počet uložených her - Neomezené značky - Podpořte mě! ❤️ - title_future: Plánovaný kontent + title_future: Plánovaný obsah planned: - Blueprintová knihovna - Steam Achievements - - Puzzle Mód + - Puzzle mód - Minimapa - Módy - - Sandbox Mód - - ... a o hodně víc! + - Sandbox mód + - ... a mnohem více! title_open_source: Tato hra je open source! + text_open_source: >- + Kdokoli může přispět, jsem aktivně zapojený do komunity, pokouším se + zkontrolovat všechny návrhy a vzít v úvahu zpětnou vazbu všude, kde je + to možné. + + Nezapomeňte se podívat na můj trello board pro kompletní plán! title_links: Odkazy links: discord: Oficiální Discord roadmap: Roadmap subreddit: Subreddit - source_code: Source code (GitHub) + source_code: Zdrojový kód (GitHub) translate: Pomozte přeložit hru! - text_open_source: >- - Kdokoli může přispět, jsem aktivně zapojený do komunity, - pokouším se zkontrolovat všechny návrhy a vzít v úvahu zpětnou vazbu všude, - kde je to možné. - - Nezapomeňte se podívat na můj trello board, kde najdete kompletní plán! global: - loading: Načítám + loading: Načítání error: Chyba thousandsDivider: " " - decimalSeparator: . + decimalSeparator: "," suffix: thousands: k millions: M @@ -79,23 +76,23 @@ global: space: SPACE demoBanners: title: Demo verze - intro: Získejte plnou verzi pro odemknutí všech funkcí! + intro: Získejte plnou verzi pro odemknutí všech funkcí a obsahu! mainMenu: play: Hrát - changelog: Změny + continue: Pokračovat + newGame: Nová hra + changelog: Seznam změn + subreddit: Reddit importSavegame: Importovat openSourceHint: Tato hra je open source! discordLink: Oficiální Discord Server helpTranslate: Pomozte přeložit hru! - browserWarning: Hrajete v nepodporovaném prohlížeči, je možné že hra poběží - pomalu! Pořiďte si samostatnou verzi nebo vyzkoušejte prohlížeč Chrome - pro plnohodnotný zážitek. + madeBy: Vytvořil + browserWarning: Promiňte, ale víme, že hra poběží pomalu ve vašem prohlížeči! + Pořiďte si samostatnou verzi nebo si stáhněte Google Chrome pro + plnohodnotný zážitek. savegameLevel: Úroveň savegameLevelUnknown: Neznámá úroveň - continue: Pokračovat - newGame: Nová hra - madeBy: Vytvořil - subreddit: Reddit savegameUnnamed: Nepojmenovaný dialogs: buttons: @@ -105,8 +102,8 @@ dialogs: later: Později restart: Restart reset: Reset - getStandalone: Získejte Plnou verzi - deleteGame: Vím co dělám + getStandalone: Získejte plnou verzi + deleteGame: Vím, co dělám viewUpdate: Zobrazit aktualizaci showUpgrades: Zobrazit vylepšení showKeybindings: Zobrazit klávesové zkratky @@ -132,73 +129,81 @@ dialogs: text: Pro aplikování nastavení musíte restartovat hru. editKeybinding: title: Změna klávesové zkratky - desc: Zmáčkněte klávesu nebo tlačítko na myši pro přiřazení nebo Escape pro + desc: Zmáčkněte klávesu nebo tlačítko myši pro přiřazení nebo Escape pro zrušení. resetKeybindingsConfirmation: title: Reset klávesových zkratek - desc: Opravdu chcete vrátit klávesové zkratky zpět do původního nastavení? + desc: Toto vrátí všechny klávesové zkratky do původního nastavení. Prosím + potvrďte. keybindingsResetOk: title: Reset klávesových zkratek - desc: Vaše klávesové zkratky byly resetovány do původního nastavení! + desc: Všechny klávesové zkratky byly vráceny do původního nastavení! featureRestriction: title: Demo verze - desc: Zkoušíte použít funkci (), která není v demo verzi. Pořiďte si - plnou verzi pro lepší zážitek! + desc: Zkoušíte použít funkci (), která není v demo verzi. Zvažte + pořízení plné verze pro kompletní zážitek! oneSavegameLimit: title: Omezené ukládání - desc: Ve zkušební verzi můžete mít pouze jednu uloženou hru. Odstraňte stávající + desc: Ve demo verzi můžete mít pouze jednu uloženou hru. Odstraňte stávající uloženou hru nebo si pořiďte plnou verzi! updateSummary: title: Nová aktualizace! - desc: "Tady jsou změny od posledně:" + desc: "Zde jsou změny od doby, kdy jste naposledy hráli:" upgradesIntroduction: title: Odemknout vylepšení desc: Všechny tvary, které vytvoříte, lze použít k odemčení vylepšení - - Neničte své staré továrny! Karta vylepšení se - nachází v pravém horním rohu obrazovky. + Neničte své staré továrny! Kartu vylepšení lze + najít v pravém horním rohu obrazovky. massDeleteConfirm: title: Potvrdit smazání desc: Odstraňujete spoustu budov (přesněji )! Opravdu je chcete smazat? + massCutConfirm: + title: Potvrdit vyjmutí + desc: Vyjímáte spoustu budov (přesněji )! Opravdu je chcete vyjmout? + massCutInsufficientConfirm: + title: Potvrdit vyjmutí + desc: Nemůžete si dovolit vložení této oblasti! Opravdu ji chcete vyjmout? blueprintsNotUnlocked: title: Zatím neodemčeno - desc: Plány ještě nebyly odemčeny! Chcete-li je odemknout, dokončete úroveň 12. + desc: Dokončete úroveň 12 pro odemčení Plánů! keybindingsIntroduction: title: Užitečné klávesové zkratky - desc: "Hra má spoustu klávesových zkratek, které usnadňují stavbu velkých + desc: "Tato hra má spoustu klávesových zkratek, které usnadňují stavbu velkých továren. Zde jsou některé, ale nezapomeňte se podívat i na ostatní klávesové zkratky!

CTRL + Táhnout: Vybrání oblasti.
SHIFT: Podržením můžete umístit více budov - za sebout.
ALT: Změnit orientaci + za sebou.
ALT: Změnit orientaci umístěných pásů.
" createMarker: title: Nová značka - desc: Použijte smysluplný název, můžete také zahrnout krátký - klíč tvaru (který můžete vygenerovat zde) titleEdit: Upravit značku - markerDemoLimit: - desc: V ukázce můžete vytvořit pouze dvě značky. Získejte plnou verzi pro - neomezený počet značek! - massCutConfirm: - title: Potvrdit vyjmutí - desc: Chceš vyjmout spoustu budov (přesněji řečeno )! Vážně to chceš - udělat? - exportScreenshotWarning: - title: Exportuj snímek obrazovky - desc: Zažádal jsi o exportování své základny jako obrázek. Měj prosím na paměti, - že to může zejména u větších základen dlouho trvat, nebo dokonce - shodit hru! - massCutInsufficientConfirm: - title: Potvrdit vyjmutí - desc: Nemůžeš si dovolit vložení této oblasti! Skutečně ji chceš vyjmout? + desc: Použijte smysluplný název, můžete také zahrnout krátký + klíč tvaru (Ten můžete vygenerovat zde) editSignal: title: Nastavte signál descItems: "Vyberte předdefinovanou položku:" - descShortKey: ... nebo zadejte krátký klíč tvaru (který můžete + descShortKey: ... nebo zadejte krátký klíč tvaru (Ten můžete vygenerovat zde) + markerDemoLimit: + desc: V demo verzi můžete vytvořit pouze dvě značky. Pořiďte si plnou verzi pro + neomezený počet značek! + exportScreenshotWarning: + title: Exportuj snímek obrazovky + desc: Chcete exportovat svou základnu jako snímek obrazovky. Mějte prosím na + paměti, že to bude docela pomalé u větších základen a může dokonce + dojít k pádu hry! renameSavegame: title: Přejmenovat uloženou hru - desc: Zde můžeš přejmenovat svoji uloženou hru. + desc: Zde můžete přejmenovat svoji uloženou hru. + tutorialVideoAvailable: + title: Dostupný tutoriál + desc: Pro tuto úroveň je k dispozici tutoriál! Chtěli byste se na + něj podívat? + tutorialVideoAvailableForeignLanguage: + title: Dostupný tutoriál + desc: Pro tuto úroveň je k dispozici tutoriál, ale je dostupný + pouze v angličtině. Chtěli byste se na něj podívat? ingame: keybindingsOverlay: moveMap: Posun mapy @@ -237,7 +242,7 @@ ingame: unlockText: "Odemčeno: !" buttonNextLevel: Další úroveň notifications: - newUpgrade: Nová aktualizace je k dispozici! + newUpgrade: Nové vylepšení je k dispozici! gameSaved: Hra byla uložena. freeplayLevelComplete: Level byl dokončen! shop: @@ -253,10 +258,10 @@ ingame: description: Tvary uložené ve vaší centrální budově. produced: title: Vyprodukováno - description: Tvary která vaše továrna produkuje, včetně meziproduktů. + description: Tvary, která vaše továrna produkuje, včetně meziproduktů. delivered: title: Dodáno - description: Tvary které jsou dodávány do vaší centrální budovy. + description: Tvary, které jsou dodávány do vaší centrální budovy. noShapesProduced: Žádné tvary zatím nebyly vyprodukovány. shapesDisplayUnits: second: / s @@ -289,10 +294,34 @@ ingame: 1_2_conveyor: "Připojte extraktor pomocí dopravníkového pásu k vašemu HUBu!

Tip: Klikněte a táhněte myší pro položení více pásů!" - 1_3_expand: "Toto NENÍ hra o čekání! Sestavte další extraktory + 1_3_expand: "Toto NENÍ hra o čekání! Postavte další extraktory a pásy, abyste dosáhli cíle rychleji.

Tip: Chcete-li umístit více extraktorů, podržte SHIFT. Pomocí R je můžete otočit." + 2_1_place_cutter: "Teď umístěte pilu k rozřezání kruhového tvaru na dvě + poloviny!

PS: Pila řeže tvary vždy svisle na + poloviny bez ohledu na její orientaci." + 2_2_place_trash: Pila se může zaseknout a zastavit vaši produkci!

Použijte + koš ke smazání (!) nepotřebných + částí tvarů. + 2_3_more_cutters: "Dobrá práce! Teď postavte více pil pro zrychlení + tohoto pomalého procesu!

PS: Použijte 0-9 + na klávesnici pro rychlejší přístup k budovám!" + 3_1_rectangles: "Teď vytěžte nějaké obdelníkové tvary! Postavte 4 + extraktory a připojte je k HUBu.

PS: + Podržením klávesy SHIFT a tažením pásu aktivujete + plánovač pásů!" + 21_1_place_quad_painter: Postavte čtyřnásobný barvič a získejte nějaké + kruhové tvary, bílou a + červenou barvu! + 21_2_switch_to_wires: Změňte vrstvy na vrstvu kabelů stisknutím klávesy + E!

Pak připojte všechny čtyři + vstupy barviče s pomocí kabelů! + 21_3_place_button: Úžasné! Teď postavte přepínač a připojte ho + pomocí kabelů! + 21_4_press_button: "Stiskněte přepínač pro změnu vysílaného logického + signálu a tím aktivujte barvič.

PS: Nemusíte + připojit veškeré vstupy! Zkuste spojit pouze dva." colors: red: Červená green: Zelená @@ -306,7 +335,7 @@ ingame: shapeViewer: title: Vrstvy empty: Prázdné - copyKey: Copy Key + copyKey: Zkopírovat klíč connectedMiners: one_miner: 1 Extraktor n_miners: Extraktorů @@ -316,7 +345,7 @@ ingame: desc: Kliknutím sem zobrazíte výhody Steam verze! get_on_steam: Získejte na steamu standaloneAdvantages: - title: Získejte plnou verzy! + title: Získejte plnou verzi! no_thanks: Ne, děkuji! points: levels: @@ -345,7 +374,7 @@ ingame: desc: Vyvíjím to ve svém volném čase! shopUpgrades: belt: - name: Pásy, distribuce & tunely + name: Pásy, distribuce a tunely description: Rychlost x → x miner: name: Extrakce @@ -370,10 +399,10 @@ buildings: miner: default: name: Extraktor - description: Umístěte na náleziště tvaru nebo barvy pro zahájení těžby. + description: Umístěte na naleziště tvaru nebo barvy pro zahájení těžby. chainable: name: Extraktor (Navazující) - description: Umístěte na náleziště tvaru nebo barvy pro zahájení těžby. Lze + description: Umístěte na naleziště tvaru nebo barvy pro zahájení těžby. Lze zapojit po skupinách. underground_belt: default: @@ -441,7 +470,7 @@ buildings: balancer: default: name: Vyvažovač - description: Multifunkční - Rozděluje vstupy do výstupy. + description: Multifunkční - Rovnoměrně rozděluje vstupy na výstupech. merger: name: Spojovač (kompaktní) description: Spojí dva pásy do jednoho. @@ -506,7 +535,7 @@ buildings: reader: default: name: Čtečka pásů - description: Umožňuje měřit průměrnou propustnost pásu. Výstup čte poslední + description: Umožňuje změřit průměrnou propustnost pásu. Výstup čte poslední položku ve vrstvě kabelů. analyzer: default: @@ -569,7 +598,7 @@ storyRewards: jde, oba tvary se slepí k sobě. Pokud ne, tvar vpravo se nalepí na tvar vlevo! reward_splitter: - title: Rozřazování/Spojování pásu + title: Kompaktní rozdělovač desc: Právě jste odemkli rozdělovací variantu vyvažovače - Přijímá jeden vstup a rozdělí ho na dva! @@ -633,9 +662,9 @@ storyRewards: desc: Gratuluji! Mimochodem, více obsahu najdete v plné verzi! reward_balancer: title: Vyvažovač - desc: The multifunctional balancer has been unlocked - It can - be used to build bigger factories by splitting and merging - items onto multiple belts! + desc: Multifunkční vyvažovač byl odemknut - Může + být použit ke zvětšení vašich továren rozdělováním a spojováním + předmětů na několik pásu! reward_merger: title: Kompaktní spojovač desc: Právě jste odemkli spojovací variantu @@ -681,13 +710,14 @@ storyRewards: kabelů.

- Pokračovat ve hře pravidelně.

Bez ohledu na tvou volbu, nezapomeň si svou hru užít! reward_wires_painter_and_levers: - title: Kabely a čtyřnásobný barvič + title: Kabely a 4x-barvič desc: "Právě jste odemkli vrstvu kabelů: Je to samostatná vrstva navíc oproti běžné vrstvě a představuje spoustu nových možností!

Do začátku jsem zpřístupnil čtyřnásobný - barvič - Připojte vstupy, které byste chtěli obarvit na - vrstvě kabelů!

Pro přepnutí mezi vrstvami stiskněte klávesu - E." + barvič - Připojte vstupy, které byste chtěli obarvit + na vrstvě kabelů!

Pro přepnutí mezi vrstvami stiskněte klávesu + E.

PS: Aktivujte nápovědy v + nastavení pro spuštění tutoriálu o kabelech!" reward_filter: title: Filtr předmětů desc: Právě jste odemkli filtr předmětů! Nasměruje předměty buď @@ -703,7 +733,7 @@ settings: general: Obecné userInterface: Uživatelské rozhraní advanced: Rozšířené - performance: Performance + performance: Výkon versionBadges: dev: Vývojová verze staging: Testovací verze @@ -713,7 +743,7 @@ settings: uiScale: title: Škálování UI description: Změní velikost uživatelského rozhraní. Rozhraní se bude stále - přizpůsobovoat rozlišení vaší obrazovky, toto nastavení pouze + přizpůsobovat rozlišení vaší obrazovky, toto nastavení pouze mění jeho škálu. scales: super_small: Velmi malé @@ -722,7 +752,7 @@ settings: large: Velké huge: Obrovské scrollWheelSensitivity: - title: Citlivost přibížení + title: Citlivost přiblížení description: Změní citlivost přiblížení (kolečkem myši nebo trackpadem). sensitivity: super_slow: Hodně pomalé @@ -757,7 +787,7 @@ settings: alwaysMultiplace: title: Několikanásobné pokládání description: Pokud bude zapnuté, zůstanou budovy vybrané i po postavení do té - doby než je zrušíte. Má to stejný efekt jako držení klávesy + doby, než je zrušíte. Má to stejný efekt jako držení klávesy SHIFT. offerHints: title: Tipy & Nápovědy @@ -772,8 +802,8 @@ settings: slow: Pomalá regular: Normální fast: Rychlá - super_fast: Hodně Rychlá - extremely_fast: Extrémně Rychlá + super_fast: Hodně rychlá + extremely_fast: Extrémně rychlá enableTunnelSmartplace: title: Chytré tunely description: Pokládání tunelů po zapnutí bude samo odstraňovat nepotřebné pásy. @@ -800,11 +830,11 @@ settings: koeficient. V opačném případě zobrazí popis a obrázek. disableCutDeleteWarnings: title: Zakázat upozornění o vyjmutí nebo odstranění - description: Deaktivujte varovná dialogová okna vyvolaná při vymutí/mazání více + description: Deaktivujte varovná dialogová okna vyvolaná při vyjmutí/mazání více než 100 entit. enableColorBlindHelper: title: Režim pro barvoslepé - description: Zapné různé nástroje, které vám umožní hrát hru i pokud jste + description: Zapne různé nástroje, které vám umožní hrát hru i pokud jste barvoslepí. rotationByBuilding: title: Rotace dle typu budov @@ -854,9 +884,13 @@ settings: description: Umožnuje posouvání po mapě, pokud myší přejedete na okraj obrazovky. Rychlost žáleží na nastavení rychlosti pohybu. zoomToCursor: - title: Zoom towards Cursor - description: If activated the zoom will happen in the direction of your mouse - position, otherwise in the middle of the screen. + title: Přiblížení ke kurzoru + description: Při zapnutí dojde k přibližování ve směru polohy + kurzoru, jinak ve středu obrazovky. + mapResourcesScale: + title: Velikost zdrojů na mapě + description: Určuje velikost ikon tvarů na náhledu mapy (při + oddálení). rangeSliderPercentage: % keybindings: title: Klávesové zkratky @@ -934,13 +968,13 @@ keybindings: about: title: O hře body: >- - Tato hra je open source a je vyvíjená Tobiasem Springerem - (česky neumí, ale je to fakt frajer :) ).

+ (česky neumí, ale je fakt frajer :) ).

Pokud se chceš na hře podílet, podívej se na shapez.io na githubu.

- Tato hra by nebyla ani možná bez skvělé Discord komunity okolo Tobiasových her - Vážně by ses měl přijít mrknout na Discord server!

+ Tato hra by nebyla možná ani bez skvělé Discord komunity okolo Tobiasových her - Vážně by ses měl přijít mrknout na Discord server!

Soundtrack udělal Peppsen - Je úžasnej.

diff --git a/translations/base-da.yaml b/translations/base-da.yaml index ecc01967..77063a0e 100644 --- a/translations/base-da.yaml +++ b/translations/base-da.yaml @@ -201,6 +201,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Bevæg dig @@ -309,6 +317,30 @@ ingame: bælter for at færdiggøre målet hurtigere.

Tip: Hold SKIFT for at sætte flere udvindere, og tryk R for at rotere dem." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 Miner n_miners: Miners @@ -699,7 +731,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -872,6 +905,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Keybindings diff --git a/translations/base-de.yaml b/translations/base-de.yaml index ae20b7c3..8a380343 100644 --- a/translations/base-de.yaml +++ b/translations/base-de.yaml @@ -2,17 +2,14 @@ steamPage: shortText: In shapez.io nutzt du die vorhandenen Ressourcen, um mit deinen Maschinen durch Kombination immer komplexere Formen zu erschaffen. discordLinkShort: Offizieller Discord - intro: Du magst Automatisierungsspiele? Dann bist du hier genau richtig! - shapez.io ist ein ruhiges Spiel, in dem du Fabriken zur automatisierten - Produktion von geometrischen Formen bauen musst. Mit steigendem Level - werden die Formen immer komplexer, und du musst dich auf der unendlich - großen Karte ausbreiten. Das ist noch nicht alles, denn du musst - exponentiell mehr produzieren, um die Anforderungen zu erfüllen - Da - hilft nur skalieren! Während du am Anfang nur Formen verarbeitest, musst - du diese später auch einfärben - Dafür musst du Farben extrahieren und - mischen! Der Kauf des Spiels auf Steam gibt dir Zugriff auf die - Vollversion, aber du kannst auch zuerst die Demo auf shapez.io spielen - und dich später entscheiden! + intro: >- + Du magst Automatisierungsspiele? Dann bist du hier genau richtig! + + shapez.io ist ein entspanntes Spiel, in dem du Fabriken zur automatisierten Produktion von geometrischen Formen bauen musst. + + Mit steigendem Level werden die Formen immer komplexer, und du musst dich auf der unendlich großen Karte ausbreiten. Das ist noch nicht alles, denn du musst exponentiell mehr produzieren, um die Anforderungen zu erfüllen - Da hilft nur skalieren! + + Während du am Anfang nur Formen verarbeitest, musst du diese später auch einfärben - Dafür musst du Farben extrahieren und mischen! Der Kauf des Spiels auf Steam gibt dir Zugriff auf die Vollversion, aber du kannst auch zuerst die Demo auf shapez.io spielen und dich später entscheiden! title_advantages: Vorteile der Vollversion advantages: - 12 Neue Level für insgesamt 26 Level @@ -88,7 +85,7 @@ mainMenu: discordLink: Offizieller Discord Server helpTranslate: Hilf beim Übersetzen! madeBy: Ein Spiel von - browserWarning: Sorry, aber das Spiel wird in deinem Browser langsam laufen! + browserWarning: Sorry, aber das Spiel wird in deinem Browser langsamer laufen! Kaufe die Vollversion oder verwende Google Chrome für die beste Erfahrung! savegameLevel: Level @@ -174,9 +171,9 @@ dialogs: vereinfachen und beschleunigen. Hier sind ein paar Beispiele, aber prüfe am besten die Tastenbelegung-Einstellungen!

- STRG + Ziehen: Wähle Areal aus.
+ STRG + Ziehen: Wähle Bereich aus.
UMSCH: Halten, um mehrere Gebäude zu platzieren.
- ALT: Invertiere die Platzierungsrichtung der Förderbänder.
+ ALT: Invertiere die Platzierungsrichtung der Fließbänder.
createMarker: title: Neuer Marker titleEdit: Marker bearbeiten @@ -199,6 +196,13 @@ dialogs: renameSavegame: title: Speicherstand umbenennen desc: Hier kannst du deinen Speicherstand umbenennen. + tutorialVideoAvailable: + title: Tutorial verfügbar + desc: Für dieses Level ist ein Tutorial-Video verfügbar. Willst du es anschauen? + tutorialVideoAvailableForeignLanguage: + title: Tutorial verfügbar + desc: Für dieses Level ist ein Tutorial-Video verfügbar, allerdings nur auf + Englisch. Willst du es trotzdem anschauen? ingame: keybindingsOverlay: moveMap: Bewegen @@ -275,7 +279,7 @@ ingame: settingsMenu: playtime: Spielzeit buildingsPlaced: Gebäude - beltsPlaced: Förderbänder + beltsPlaced: Fließbänder tutorialHints: title: Brauchst du Hilfe? showHint: Hinweis @@ -303,9 +307,35 @@ ingame: schließe ihn am Hub an!

Tipp: Drücke und ziehe das Fließband mit der Maus!" 1_3_expand: "Dies ist KEIN Idle-Game! Baue mehr Extrahierer und - Förderbänder, um das Ziel schneller zu erreichen.

Tipp: + Fließbänder, um das Ziel schneller zu erreichen.

Tipp: Halte UMSCH, um mehrere Gebäude zu platzieren und nutze R, um sie zu rotieren." + 2_1_place_cutter: "Platziere nun einen Schneider um die Kreise + in zwei Hälften zu zerteilen.

Übrigens: Der Schneider + schneidet immer von oben nach unten, unabhängig + seiner Orientierung!" + 2_2_place_trash: Der Schneider kann verstopfen!

Benutze + einen Mülleimer um den aktuell (!) nicht + benötigten Rest loszuwerden. + 2_3_more_cutters: "Gut gemacht! Platziere noch 2 mehr Schneider + um das ganze zu beschleunigen.

Übrigens: Benutze die + Tasten 0-9 um Gebäude schneller auszuwählen!" + 3_1_rectangles: "Lass uns ein paar Quadrate extrahieren! Baue 4 + Extrahierer und verbinde sie mit deinem HUB.

+ PS: Halte SHIFT während du ein Fließband + ziehst, um den Fließbandplaner zu aktivieren!" + 21_1_place_quad_painter: Platzier den Vierfach-Färber und + organisier ein paar Kreise, + weiße und rote Farbe! + 21_2_switch_to_wires: Wechsle in die Wires-Ebene indem du E + drückst!

Verbinde danach alle vier + Eingänge mit Signalkabeln! + 21_3_place_button: Perfekt! Platziere jetzt einen Schalter und + verbinde ihn mit Signalkabeln. + 21_4_press_button: "Drücke den Schalter damit er ein wahres + Signal ausgibt, und damit den Färber aktiviert.

+ PS: Du musst nicht alle Eingänge verbinden! Probiere mal nur 2 + aus." connectedMiners: one_miner: Ein Extrahierer n_miners: Extrahierer @@ -334,7 +364,7 @@ ingame: title: ∞ Marker desc: Verliere nie den Überblick! wires: - title: Wires + title: Wires-Ebene desc: Eine ganz neue Dimension! darkmode: title: Dark-Mode @@ -344,7 +374,7 @@ ingame: desc: Ich entwickle in meiner Freizeit! shopUpgrades: belt: - name: Förderbänder, Verteiler & Tunnel + name: Fließbänder, Verteiler & Tunnel description: Geschw. x → x miner: name: Extrahierer @@ -376,11 +406,11 @@ buildings: underground_belt: default: name: Tunnel - description: Erlaubt dir, Formen und Farbe unter Gebäuden und Förderbändern + description: Erlaubt dir, Formen und Farbe unter Gebäuden und Fließbändern durchzuleiten. tier2: name: Tunnel Stufe II - description: Erlaubt dir, Formen und Farbe unter Gebäuden und Förderbändern + description: Erlaubt dir, Formen und Farbe unter Gebäuden und Fließbändern durchzuleiten. Höhere Reichweite. balancer: default: @@ -389,16 +419,16 @@ buildings: Ausgänge. merger: name: Kombinierer (kompakt) - description: Kombiniert zwei Fließbänder zu einem. + description: Kombiniert zwei Eingänge gleichmäßig zu einem Ausgang. merger-inverse: name: Kombinierer (kompakt) - description: Kombiniert zwei Fließbänder zu einem. + description: Kombiniert zwei Eingänge gleichmäßig zu einem Ausgang. splitter: name: Aufteiler (kompakt) - description: Teilt ein Fließband in zwei. + description: Teilt einen Eingang gleichmäßig in zwei Ausgänge auf. splitter-inverse: name: Aufteiler (kompakt) - description: Teilt ein Fließband in zwei. + description: Teilt einen Eingang gleichmäßig in zwei Ausgänge auf. cutter: default: name: Schneider @@ -443,8 +473,8 @@ buildings: quad: name: Färber (vierfach) description: Erlaubt dir, jeden Quadranten der Form individuell zu färben. Nur - Quadranten mit einem wahren Signal auf der - Wires-Ebene werden angemalt! + Quadranten mit einem wahren Signal (Form, Farbe + oder "1") auf der Wires-Ebene werden angemalt! trash: default: name: Mülleimer @@ -474,8 +504,8 @@ buildings: constant_signal: default: name: Signalgeber - description: Sendet ein konstantes Signal. Du wählst zwischen Formen, Farben - oder Wahrheitswerten (1 oder 0). + description: Sendet ein konstantes Signal. Du wählst zwischen Formen, Farben und + Wahrheitswerten (1 oder 0). lever: default: name: Schalter @@ -484,36 +514,36 @@ buildings: Filters verwendet werden kann. logic_gate: default: - name: UND Gatter - description: Gibt eine "1" aus, wenn beide Eingänge wahr sind (wahr bedeutet - Form, Farbe oder "1"). + name: UND-Gatter + description: Gibt eine "1" aus, wenn beide Eingänge wahr (Form, Farbe oder "1") + sind. not: - name: NICHT Gatter - description: Gibt eine "1" aus, wenn der Eingang nicht wahr ist (wahr bedeutet - Form, Farbe oder "1"). + name: NICHT-Gatter + description: Gibt eine "1" aus, wenn beide Eingänge nicht wahr (kein Signal oder + "0") sind. xor: - name: XOR Gatter - description: Gibt eine "1" aus, wenn einer der Eingänge wahr ist, aber nicht - beide (wahr bedeutet Form, Farbe oder "1"). + name: XODER-Gatter + description: Gibt eine "1" aus, wenn genau einer der Eingänge wahr (Form, Farbe + oder "1") ist. or: - name: ODER Gatter - description: Gibt eine "1" aus, wenn einer der Eingänge wahr ist (wahr bedeutet - Form, Farbe oder "1"). + name: ODER-Gatter + description: Gibt eine "1" aus, wenn mindestens einer der Eingänge wahr (Form, + Farbe oder "1") ist. transistor: default: name: Transistor - description: Leitet den unteren Eingang weiter, wenn der seitliche Eingang wahr - ist (eine Form, Farbe oder "1"). + description: Lässt den unteren Eingang passieren, wenn der seitliche Eingang + wahr (Form, Farbe oder "1") ist. mirrored: name: Transistor - description: Leitet den unteren Eingang weiter, wenn der seitliche Eingang wahr - ist (eine Form, Farbe oder "1"). + description: Lässt den unteren Eingang passieren, wenn der seitliche Eingang + wahr (Form, Farbe oder "1") ist. filter: default: - name: Filter - description: Verbinde ein Signal, um alle passenden Gegenstände nach oben zu - leiten und die restlichen nach rechts. Kann auch mit - Wahrheitswerten gesteuert werden. + name: Itemfilter + description: Lässt nur die Items durch, die dem eingespeisten Signal entsprechen + und sortiert die restlichen aus. Mit Wahrheitswerten + konfiguriert fungiert er als Schranke. display: default: name: Anzeige @@ -522,14 +552,14 @@ buildings: reader: default: name: Fließbandkontrolle - description: Ermöglicht es, den durchschnittlichen Durchsatz des Fließbandes zu - messen. Gibt den letzten Gegenstand auf der Wires-Ebene aus - (sobald freigeschaltet). + description: Misst den gemittelten Durchsatz des Fließbandes. Gibt zuätzlich den + zuletzt passierten Gegenstand auf der Wires-Ebene aus (sobald + freigeschaltet). analyzer: default: name: Formanalyse - description: Analysiert den oberen rechten Quadranten der untersten Schicht der - Form und gibt seine Form und Farbe zurück. + description: Analysiert den oberen rechten Quadranten der untersten Schicht + einer Form und gibt sowohl Form als auch Farbe aus. comparator: default: name: Vergleich @@ -541,11 +571,10 @@ buildings: description: Schneidet die Form virtuell in zwei Hälften. rotater: name: Virtueller Rotierer - description: Dreht die Form virtuell, sowohl im als auch gegen den - Uhrzeigersinn. + description: Dreht die Form virtuell im Uhrzeigersinn. unstacker: name: Virtueller Entstapler - description: Extrahiert virtuell die oberste Ebene nach rechts und die die + description: Extrahiert virtuell die oberste Ebene nach rechts und die restlichen Ebenen nach links. stacker: name: Virtueller Stapler @@ -558,7 +587,7 @@ buildings: default: name: Item-Produzent description: Nur im Sandkastenmodus verfügbar. Gibt das Signal aus der - Wires-Ebene auf der regulären Ebene aus. + Wires-Ebene als Item aus. storyRewards: reward_cutter_and_trash: title: Formen zerschneiden @@ -574,9 +603,9 @@ storyRewards: Uhrzeigersinn um 90 Grad. reward_painter: title: Färben - desc: "Der Färber wurde freigeschaltet. Extrahiere ein paar - Farben (genauso wie bei Formen) und färbe damit eine Form im - Färber.

PS: Falls du Farbenblind bist, gibt es einen + desc: "Der Färber wurde freigeschaltet! Extrahiere ein paar + Farben (genauso wie bei Formen) und lasse damit eine Form im Färber + bemalen.

PS: Falls du farbenblind bist, gibt es einen Modus für Farbenblinde in den Einstellungen!" reward_mixer: title: Farben mischen @@ -591,13 +620,13 @@ storyRewards: gestapelt. reward_balancer: title: Verteiler - desc: The multifunctional balancer has been unlocked - It can - be used to build bigger factories by splitting and merging - items onto multiple belts! + desc: Der multifunktionale Verteiler wurde freigeschaltet! Er + kann benutzt werden, um größere Fabriken zu bauen, indem Fließbänder + aufgeteilt oder zusammengelegt werden! reward_tunnel: title: Tunnel desc: Der Tunnel wurde freigeschaltet! Du kannst Items nun - unter Gebäuden oder Förderbändern hindurchleiten. + unter Gebäuden oder Fließbändern hindurchleiten. reward_rotater_ccw: title: Gegen UZS Rotieren desc: Du hast eine zweite Variante des Rotierers @@ -607,9 +636,9 @@ storyRewards: reward_miner_chainable: title: Extrahierer (Kette) desc: "Du hast den Kettenextrahierer freigeschaltet! Er kann - seine Resourcen an andere Extrahierer weiterleiten! -

PS: Die alten Extrahierer wurde jetzt in deiner - Symbolleiste ersetzt!" + seine Ressourcen an andere Extrahierer + weiterleiten.

PS: Der alte Extrahierer + wurde jetzt in deiner Symbolleiste ersetzt!" reward_underground_belt_tier_2: title: Tunnel Stufe II desc: Du hast eine neue Variante des Tunnels freigeschaltet! @@ -619,7 +648,7 @@ storyRewards: title: Kompakter Kombinierer desc: Du hast eine kompakte Variante des Verteilers freigeschaltet! Der Kombinierer vereint - zwei Eingäge zu einem Ausgang. + zwei Eingänge zu einem Ausgang. reward_splitter: title: Kompakter Aufteiler desc: Du hast eine kompakte Variante des @@ -632,12 +661,12 @@ storyRewards: lassen.

Wenn du Stromkabel freischaltest, wird er um eine sehr nützliche Funktion ergänzt! reward_cutter_quad: - title: Schneider (4-fach) + title: Schneider (vierfach) desc: Du hast eine neue Variante des Schneiders freigeschaltet! Damit kannst du Formen in alle vier Teile zerschneiden. reward_painter_double: - title: Färber (2-fach) + title: Färber (zweifach) desc: Du hast eine neue Variante des Färbers freigeschaltet! Hiermit kannst du zwei Formen auf einmal färben und verbrauchst nur eine Farbe. @@ -650,59 +679,69 @@ storyRewards: reward_blueprints: title: Blaupausen desc: Jetzt kannst du Teile deiner Fabrik kopieren und - einfügen! Wähle ein Areal aus (Halte STRG und ziehe mit + einfügen! Wähle einen Bereich aus (Halte STRG und ziehe mit deiner Maus) und drücke 'C', um zu kopieren.

Einfügen ist nicht kostenlos! Du musst Blaupausenformen produzieren, um die Kopierkosten - zu decken (Welche du gerade produziert hast)! + zu decken (Welche du gerade produziert hast). reward_rotater_180: title: Rotierer (180°) desc: Du hast eine weitere Variante des Rotierers freigeschaltet! Mit ihm kannst du Formen um 180° drehen (Überraschung! :D). reward_wires_painter_and_levers: - title: Wires & Quad Painter - desc: "You just unlocked the Wires Layer: It is a separate - layer on top of the regular layer and introduces a lot of new - mechanics!

For the beginning I unlocked you the Quad - Painter - Connect the slots you would like to paint with on - the wires layer!

To switch to the wires layer, press - E." + title: Wires-Ebene & vierfacher Färber + desc: "Du hast soeben die Wires-Ebene freigeschaltet! Diese + separate Ebene befindet sich unter deinen Gebäuden und gibt dir + viele neue Möglichkeiten.

Für den Anfang bekommst du einen + vierfachen Färber. Schließe die Eingänge, mit denen + du die Quadranten färben möchtest, an ein Signalkabel auf der + Wires-Ebene an!

Mit E wechselst du zwischen + den Ebenen.

PS: Aktiviere Hinweise in den + Einstellungen um das Tutorial anzuzeigen!" reward_filter: - title: Item Filter - desc: You unlocked the Item Filter! It will route items either - to the top or the right output depending on whether they match the - signal from the wires layer or not.

You can also pass in a - boolean signal (1 / 0) to entirely activate or disable it. + title: Itemfilter + desc: Du hast den Itemfilter freigeschaltet! Items, die dem + eingespeisten Signal entsprechen, lässt er passieren. Den Rest + zweigt er nach rechts ab.

Du kannst z.B. nach Farbe und Form + sortieren oder mit Wahrheitswerten (1 oder 0) Items nur auf + Knopfdruck passieren lassen. reward_display: - title: Display - desc: "You have unlocked the Display - Connect a signal on the - wires layer to visualize it!

PS: Did you notice the belt - reader and storage output their last read item? Try showing it on a - display!" + title: Anzeige + desc: Du hast die Anzeige freigeschaltet! Jedes eingespeiste + Signal kann damit dargestellt werden.

Apropos, ist dir schon + aufgefallen, dass Fließbandkontrolle und Lager das zuletzt passierte + Item ausgeben können? Lasse es dir doch gleich mal anzeigen! reward_constant_signal: - title: Constant Signal - desc: You unlocked the constant signal building on the wires - layer! This is useful to connect it to item filters - for example.

The constant signal can emit a - shape, color or - boolean (1 / 0). + title: Signalgeber + desc: Du hast den Signalgeber freigeschaltet! Du kannst das + Gebäude auf der Wires-Ebene platzieren und z.B. mit einem + Itemfilter verbinden.

Der Signalgeber kann + dir Formen, Farben oder + Wahrheitswerte (1 oder 0) zur Verfügung stellen. reward_logic_gates: - title: Logic Gates - desc: You unlocked logic gates! You don't have to be excited - about this, but it's actually super cool!

With those gates - you can now compute AND, OR, XOR and NOT operations.

As a - bonus on top I also just gave you a transistor! + title: Logikgatter + desc: Du hast nun eine Reihe an Logikgattern freigeschaltet! + Das muss dich jetzt nicht nervös machen, die Funktionsweise ist + simpel und ziemlich cool.

Mit Logikgattern kannst du UND-, + ODER-, XODER- und NICHT-Operationen ausführen.

Als + Sahnehäubchen obendrauf stelle ich dir noch einen + Transistor zur Verfügung. Houston, wir sind + Turing-vollständig! reward_virtual_processing: - title: Virtual Processing - desc: I just gave a whole bunch of new buildings which allow you to - simulate the processing of shapes!

You can - now simulate a cutter, rotater, stacker and more on the wires layer! - With this you now have three options to continue the game:

- - Build an automated machine to create any possible - shape requested by the HUB (I recommend to try it!).

- Build - something cool with wires.

- Continue to play - regulary.

Whatever you choose, remember to have fun! + title: Virtuelle Verarbeitung + desc: "Du hast gerade eine Menge neue Gebäude freigeschaltet! Mit ihnen kannst + du die Verarbeitung von Formen komplett + simulieren.

Das beinhaltet einen Schneider, + Rotierer, Stapler und mehr für die Wires-Ebene! Damit bleiben dir ab + jetzt drei Optionen offen:

- Ich empfehle dir, eine + automatisierte Maschine zu bauen, die jede + beliebige Form am Hub abgreift und herstellt. (Probiere es + wenigstens!)

- Werde kreativ und lasse dir etwas Cooles + einfallen, das du auf der Wires-Ebene umsetzen kannst. (Und teile es + auf dem Discord!)

- Spiele dich weiter durch die Level. Auf + deine Art!

Das Wichstigste an deiner Entscheidung ist: + Vergiss nicht, dabei Spaß zu haben!" no_reward: title: Nächstes Level desc: "Dieses Level hat dir keine Belohnung gegeben, aber im Nächsten gibt es @@ -714,8 +753,8 @@ storyRewards: desc: Du hast das nächste Level freigeschaltet! reward_freeplay: title: Freies Spiel - desc: Du hast es geschafft! Du hast den Freispiel-Modus - freigeschaltet! Das bedeutet, dass die abzuliefernden Formen jetzt + desc: Du hast es geschafft! Du bist im Freispiel-Modus + angekommen! Das bedeutet, dass die abzuliefernden Formen jetzt zufällig erzeugt werden!

Da der Hub ab jetzt einen bestimmten Durchsatz benötigt, empfehle ich dringend, eine Maschine zu bauen, die automatisch die gewünschte @@ -830,10 +869,9 @@ settings: die den Einstieg erleichtern sollen. enableTunnelSmartplace: title: Intelligente Tunnel - description: Aktiviert das automatische Entfernen von überflüssigen - Förderbändern bei der Platzierung von Tunneln. Außerdem - funktioniert das Ziehen von Tunneln und überschüssige werden - ebenfalls entfernt. + description: Aktiviert das automatische Entfernen von überflüssigen Fließbändern + bei der Platzierung von Tunneln. Außerdem funktioniert das + Ziehen von Tunneln und überschüssige werden ebenfalls entfernt. vignette: title: Vignette description: Aktiviert den Vignetteneffekt, der den Rand des Bildschirms @@ -881,9 +919,9 @@ settings: description: Standardmäßig eingeschaltet, wählst du automatisch den Extrahierer, wenn du mit der Pipette auf einen Ressourcenfleck zeigst simplifiedBelts: - title: Minimalistische Förderbänder (Unschön) - description: Zur Verbesserung der Leistung werden die Items auf Förderbändern - nur angezeigt, wenn du deine Maus darüber bewegst. Hier leidet + title: Minimalistische Fließbänder (Unschön) + description: Zur Verbesserung der Leistung werden die Items auf Fließbändern nur + angezeigt, wenn du deine Maus darüber bewegst. Hier leidet sowohl die Grafik, also auch dein Spielerlebnis. Benutze die Funktion nur, wenn du auf die Leistung wirklich angewiesen bist! enableMousePan: @@ -895,6 +933,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). keybindings: title: Tastenbelegung hint: "Tipp: Benutze STRG, UMSCH and ALT! Sie aktivieren verschiedene @@ -1001,7 +1043,7 @@ tips: - Wenn der Stapler nicht die richtige Form ausspuckt, wechsle doch mal die Eingänge. - Du kannst mit R die Richtung des Bandplaners umkehren. - - Halte STRG, um die Förderbänder ohne automatische Orientierung zu + - Halte STRG, um die Fließbänder ohne automatische Orientierung zu platzieren. - Die Verhältnisse der Maschinen bleiben gleich, wenn du die Upgrades gleichmäßig kaufst. @@ -1020,13 +1062,13 @@ tips: - Vergiss die Tunnel nicht! - Für maximale Effizienz musst du die Items nicht gleichmässig aufteilen. - Das Halten von UMSCH aktiviert den Bandplaner, der lange - Förderbänder ganz einfach platziert. + Fließbänder ganz einfach platziert. - Schneider teilen die Form immer vertikal, unabhängig von der Orientierung. - Weiß erhälst du aus der Kombination aller 3 Grundfarben. - Das Lager gibt Items immer zuerst am linken Ausgang ab. - Es lohnt sich, Zeit in den Bau von wiederverwendbaren Designs zu stecken! - Das Halten von STRG ermöglicht dir, mehrere Gebäude zu platzieren. - - Du kanst ALT gedrückt halten, um die Richtung der Förderbänder + - Du kanst ALT gedrückt halten, um die Richtung der Fließbänder umzukehren. - Effizienz ist entscheidend! - Abbaubare Formen werden komplexer, je weiter sie vom Hub entfernt sind. @@ -1034,7 +1076,7 @@ tips: mehreren auf. - Benutze Aufteiler, um deine Effizienz zu maximieren. - Organisation ist wichtig! Verheddere dich nicht in einem Gewirr aus - Förderbändern. + Fließbändern. - Plane vorher und lasse dir Platz für Reserven, oder es gibt ein riesiges Chaos! - Lösche deine alten Fabriken nicht! Du benötigst sie um Upgrades @@ -1065,7 +1107,7 @@ tips: - Dieses Spiel hat eine Menge Einstellungen, schaue sie dir einmal an! - Die Richtung zu deinem Hub ist oben rechts mit einer kleinen Kompassnadel markiert! - - Um alle Förderbänder zu leeren, schneide den Bereich aus und füge ihn auf + - Um alle Fließbänder zu leeren, schneide den Bereich aus und füge ihn auf der selben Position wieder ein. - Drücke F4 um deine FPS und Tickrate anzuzeigen. - Drücke doppelt F4 um den Standort des Mauszeigers und der Kamera zu diff --git a/translations/base-el.yaml b/translations/base-el.yaml index 900760cf..76622e61 100644 --- a/translations/base-el.yaml +++ b/translations/base-el.yaml @@ -209,6 +209,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Κίνηση @@ -306,6 +314,30 @@ ingame: SHIFT για να τοποθετήσεις πολλούς αποσπαστές και χρησιμοποιήστε το R για να τους περιστρέψεις." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." colors: red: Κόκκινο green: Πράσινο @@ -721,7 +753,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -896,6 +929,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Συνδιασμοί πλήκτρων diff --git a/translations/base-en.yaml b/translations/base-en.yaml index 2f7da146..8ba0c9ad 100644 --- a/translations/base-en.yaml +++ b/translations/base-en.yaml @@ -28,7 +28,7 @@ steamPage: discordLinkShort: Official Discord intro: >- - You like automation games? Then you are in the right place! + Do you like automation games? Then you are in the right place! shapez.io is a relaxed game in which you have to build factories for the automated production of geometric shapes. As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map. @@ -272,6 +272,14 @@ dialogs: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to watch it? + + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only available in English. Would you like to watch it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -414,6 +422,36 @@ ingame: 1_3_expand: >- This is NOT an idle game! Build more extractors and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them. + 2_1_place_cutter: >- + Now place a Cutter to cut the circles in two halves!

+ PS: The cutter always cuts from top to bottom regardless of its orientation. + + 2_2_place_trash: >- + The cutter can clog and stall!

+ Use a trash to get rid of the currently (!) not needed waste. + + 2_3_more_cutters: >- + Good job! Now place 2 more cutters to speed up this slow process!

+ PS: Use the 0-9 hotkeys to access buildings faster! + + 3_1_rectangles: >- + Now let's extract some rectangles! Build 4 extractors and connect them to the hub.

+ PS: Hold SHIFT while dragging a belt to activate the belt planner! + + 21_1_place_quad_painter: >- + Place the quad painter and get some circles, white and red color! + + 21_2_switch_to_wires: >- + Switch to the wires layer by pressing E!

+ Then connect all four inputs of the painter with cables! + + 21_3_place_button: >- + Awesome! Now place a Switch and connect it with wires! + + 21_4_press_button: >- + Press the switch to make it emit a truthy signal and thus activate the painter.

+ PS: You don't have to connect all inputs! Try wiring only two. + # Connected miners connectedMiners: one_miner: 1 Extractor @@ -668,7 +706,7 @@ buildings: rotater: name: Virtual Rotater - description: Virtually rotates the shape, both clockwise and counter-clockwise. + description: Virtually rotates the shape clockwise. unstacker: name: Virtual Unstacker @@ -775,7 +813,8 @@ storyRewards: desc: >- You just unlocked the Wires Layer: It is a separate layer on top of the regular layer and introduces a lot of new mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

- To switch to the wires layer, press E. + To switch to the wires layer, press E.

+ PS: Enable hints in the settings to activate the wires tutorial! reward_filter: title: >- @@ -1030,6 +1069,11 @@ settings: description: >- If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: >- + Controls the size of the shapes on the map overview (when zooming out). + keybindings: title: Keybindings hint: >- @@ -1145,9 +1189,9 @@ demo: settingNotAvailable: Not available in the demo. tips: - - The hub accepts input of any kind, not just the current shape! + - The hub will accept any input, not just the current shape! - Make sure your factories are modular - it will pay out! - - Don't build too close to the hub, or it will be a huge chaos! + - Don't build too close to the hub, or it will be a mess! - If stacking does not work, try switching the inputs. - You can toggle the belt planner direction by pressing R. - Holding CTRL allows dragging of belts without auto-orientation. @@ -1165,21 +1209,20 @@ tips: - You don't need to divide up items evenly for full efficiency. - Holding SHIFT will activate the belt planner, letting you place long lines of belts easily. - Cutters always cut vertically, regardless of their orientation. - - To get white mix all three colors. - The storage buffer prioritises the left output. - Invest time to build repeatable designs - it's worth it! - - Holding CTRL allows to place multiple buildings. + - Holding SHIFT lets you place multiple buildings in one click. - You can hold ALT to invert the direction of placed belts. - Efficiency is key! - Shape patches that are further away from the hub are more complex. - Machines have a limited speed, divide them up for maximum efficiency. - Use balancers to maximize your efficiency. - Organization is important. Try not to cross conveyors too much. - - Plan in advance, or it will be a huge chaos! + - Plan in advance, or it will be a mess! - Don't remove your old factories! You'll need them to unlock upgrades. - - Try beating level 20 on your own before seeking for help! + - Try beating level 20 or 26 on your own before seeking for help! - Don't complicate things, try to stay simple and you'll go far. - - You may need to re-use factories later in the game. Plan your factories to be re-usable. + - You may need to reuse factories later in the game. Build your factories to be reusable. - Sometimes, you can find a needed shape in the map without creating it with stackers. - Full windmills/pinwheels can never spawn naturally. - Color your shapes before cutting for maximum efficiency. @@ -1190,13 +1233,13 @@ tips: - Building too close to the hub can get in the way of later projects. - The pin icon next to each shape in the upgrade list pins it to the screen. - Mix all three primary colors to make white! - - You have an infinite map, don't cramp your factory, expand! + - You have an infinite map. Don't cramp your factory, expand! - Also try Factorio! It's my favorite game. - - The quad cutter cuts clockwise starting from the top right! + - The quad cutter cuts clockwise, starting from the top right. - You can download your savegames in the main menu! - This game has a lot of useful keybindings! Be sure to check out the settings page. - This game has a lot of settings, be sure to check them out! - - The marker to your hub has a small compass to indicate its direction! + - Your hub marker has a small compass that shows which direction it is in! - To clear belts, cut the area and then paste it at the same location. - Press F4 to show your FPS and Tick Rate. - Press F4 twice to show the tile of your mouse and camera. diff --git a/translations/base-es.yaml b/translations/base-es.yaml index 6480cf61..8bb4cdc1 100644 --- a/translations/base-es.yaml +++ b/translations/base-es.yaml @@ -23,30 +23,30 @@ steamPage: - Modo oscuro! - Partidad guardadas ilimitadas - Marcadores ilimitados - - Support me! ❤️ + - Me apoyarás! ❤️ title_future: Contenido futuro planned: - - Blueprint Library (Standalone Exclusive) - - Steam Achievements - - Puzzle Mode - - Minimap + - Librería de planos (Exclusivo de Standalone) + - Logros de Steam + - Modo Puzzle + - Minimapa - Mods - - Sandbox mode - - ... and a lot more! - title_open_source: This game is open source! + - Modo libre + - ... y mucho más! + title_open_source: Este juego es de código abierto! title_links: Links links: - discord: Official Discord + discord: Discord oficial roadmap: Roadmap subreddit: Subreddit - source_code: Source code (GitHub) - translate: Help translate + source_code: Código fuente (GitHub) + translate: Ayuda a traducír text_open_source: >- - Anybody can contribute, I'm actively involved in the community and - attempt to review all suggestions and take feedback into consideration - where possible. + Cualquiera puede contribuír, Estoy activamete involucrado en la comunidad y + trato de revisar todas las sugerencias además de tomar en cuenta los consejos + siempre que sea posible. - Be sure to check out my trello board for the full roadmap! + Asegurate de revisar mi página de Trello donde podrás encontrar el Roadmap! global: loading: Cargando error: Error @@ -96,7 +96,7 @@ mainMenu: Obtén el juego completo o descarga Chrome para la experiencia completa. savegameLevel: Nivel savegameLevelUnknown: Nivel desconocido - savegameUnnamed: Unnamed + savegameUnnamed: Sin nombre dialogs: buttons: ok: OK @@ -121,9 +121,8 @@ dialogs: text: "No se ha podido cargar la partida guardada:" confirmSavegameDelete: title: Confirmar borrado - text: Are you sure you want to delete the following game?

- '' at level

This can not be - undone! + text: Estás seguro de querér borrar el siguiente guardado?

+ '' que está en el nivel

Esto no se puede deshacer! savegameDeletionError: title: Fallo al borrar text: "Fallo al borrar la partida guardada:" @@ -186,8 +185,7 @@ dialogs: createMarker: title: Nuevo marcador titleEdit: Editar marcador - desc: Give it a meaningful name, you can also include a short - key of a shape (Which you can generate here) + desc: Dale un nombre significativo, tambien puedes incluir la clave de una forma (La cual puedes generar aquí) markerDemoLimit: desc: Solo puedes crear dos marcadores en la versión de prueba. ¡Obtén el juego completo para marcadores ilimitados! @@ -197,13 +195,19 @@ dialogs: cuenta que puede tardar bastante en las bases grandes. ¡E incluso crashear tu juego! editSignal: - title: Set Signal - descItems: "Choose a pre-defined item:" - descShortKey: ... or enter the short key of a shape (Which you - can generate here) + title: Establecer señal + descItems: "Elige un item pre-definido:" + descShortKey: ... o escribe la calve de una forma (La cual + puedes generar aquí) renameSavegame: - title: Rename Savegame - desc: You can rename your savegame here. + title: Renombrar archivo de guardado + desc: Aquí puedes cambiarle el nombre a tu archivo de guardado. + tutorialVideoAvailable: + title: Tutorial disponible + desc: ¡Hay un video tutorial disponible para este nivel! ¿Te gustaría verlo? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Disponible + desc: Hay un video tutorial disponible para este nivel, pero solo está disponible en inglés ¿Te gustaría verlo? ingame: keybindingsOverlay: moveMap: Mover @@ -314,42 +318,66 @@ ingame: más rápido.

Pista: Mantén pulsado SHIFT para colocar varios extractores y usa R para rotarlos.' + 2_1_place_cutter: "¡Ahora pon un Cortador para dividir los circulos en dos + mitades!

PD: El cortador siempre corta de de arriba a + abajo independientemente de su orientación." + 2_2_place_trash: ¡El cortador se puede tabar y atorar!

Usa un + basurero para deshacerse de la actualmente (!) no + necesitada basura. + 2_3_more_cutters: "¡Buen trabajo! ¡Ahora pon 2 cortadores más para acelerar + este lento proceso!

PD: Usa las teclas 0-9 + para acceder a los edificios más rápido!" + 3_1_rectangles: "¡Ahora consigamos unos rectangulos! construye 4 + extractores y conectalos a el edificio central.

PD: + Manten apretado SHIFT mientrás pones cintas transportadoras para activar + el planeador de cintas!" + 21_1_place_quad_painter: ¡Pon el pintaor cuadruple y consigue unos + circulos, el color blanco y el color + rojo! + 21_2_switch_to_wires: ¡Cambia a la capa de cables apretando la técla + E!

Luego conecta las cuatro + entradas de el pintador con cables! + 21_3_place_button: ¡Genial! ¡Ahora pon un Interruptor y conectalo + con cables! + 21_4_press_button: "Presioa el interruptor para hacer que emita una señal + verdadera lo cual activa el piintador.

PD: ¡No necesitas + conectar todas las entradas! Intenta conectando solo dos." connectedMiners: - one_miner: 1 Miner - n_miners: Miners - limited_items: Limited to + one_miner: 1 Minero + n_miners: Mineros + limited_items: Limitado a watermark: - title: Demo version - desc: Click here to see the Steam version advantages! - get_on_steam: Get on steam + title: Versión demo + desc: Presiona aquí para ver que tiene la versión de Steam! + get_on_steam: Consiguelo en Steam standaloneAdvantages: - title: Get the full version! - no_thanks: No, thanks! + title: ¡Consigue la versión completa! + no_thanks: ¡No grácias! points: levels: - title: 12 New Levels - desc: For a total of 26 levels! + title: 12 nuevos niveles + desc: ¡Para un total de 26 niveles! buildings: - title: 18 New Buildings - desc: Fully automate your factory! + title: 18 nuevos edificios + desc: ¡Automatiza completamente tu fabrica! savegames: - title: ∞ Savegames - desc: As many as your heart desires! + title: Archivos de guardado infinitos + desc: ¡Tantos como desees! upgrades: - title: 20 Upgrade Tiers - desc: This demo version has only 5! + title: 20 niveles de mejoras + desc: ¡Esta demo solo tiene 5! markers: - title: ∞ Markers - desc: Never get lost in your factory! + title: Marcadores infinitos + desc: ¡Nunca te pierdas en tu propia fabrica! wires: - title: Wires - desc: An entirely new dimension! + title: Cables + desc: ¡Una dimension completamente nueva! darkmode: - title: Dark Mode - desc: Stop hurting your eyes! + title: Modo oscuro + desc: ¡Deja de lastimar tus ojos! support: - title: Support me - desc: I develop it in my spare time! + title: Apoyame + desc: ¡Desarrollo este juego en mi tiempo libre! shopUpgrades: belt: name: Cintas transportadoras, Distribuidores y Túneles @@ -379,9 +407,9 @@ buildings: name: Cable description: Te permite transportar energía second: - name: Wire - description: Transfers signals, which can be items, colors or booleans (1 / 0). - Different colored wires do not connect. + name: Cable + description: Transfiere señales, que pueden ser items, colores o valores booleanos (1 / 0). + Cables de diferentes colores no se conectan. miner: default: name: Extractor @@ -417,8 +445,8 @@ buildings: name: Rotador (Inverso) description: Rota las figuras en sentido antihorario 90 grados. rotate180: - name: Rotate (180) - description: Rotates shapes by 180 degrees. + name: Rotador (180) + description: Rota formas en 180 grados. stacker: default: name: Apilador @@ -443,132 +471,131 @@ buildings: la entrada de arriba. quad: name: Pintor (Cuádruple) - description: Allows you to color each quadrant of the shape individually. Only - slots with a truthy signal on the wires layer - will be painted! + description: Te permite colorear cada cuadrante de la forma individualemte. ¡Solo las + ranuras con una señal verdadera en la capa de cables + seran pintadas! trash: default: name: Basurero description: Acepta formas desde todos los lados y las destruye. Para siempre. balancer: default: - name: Balancer - description: Multifunctional - Evenly distributes all inputs onto all outputs. + name: Balanceador + description: Multifuncional - Distribuye igualmente todas las entradas en las salidas. merger: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Unión (compacta) + description: Junta dos cintas transportadoras en una. merger-inverse: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Unión (compacta) + description: Junta dos cintas transportadoras en una. splitter: - name: Splitter (compact) - description: Splits one conveyor belt into two. + name: Separador (compacto) + description: Separa una cinta trasportadora en dos. splitter-inverse: - name: Splitter (compact) - description: Splits one conveyor belt into two. + name: Separador (compacto) + description: Separa una cinta trasportadora en dos. storage: default: - name: Storage - description: Stores excess items, up to a given capacity. Prioritizes the left - output and can be used as an overflow gate. + name: Almacén + description: Guarda items en exceso, hasta una dada capacidad. Prioritiza la salida + de la izquierda y puede ser usada como una puerta de desbordamiento. wire_tunnel: default: - name: Wire Crossing - description: Allows to cross two wires without connecting them. + name: Cruze de cables + description: Permite que dos cables se cruzen sin conectarse. constant_signal: default: - name: Constant Signal - description: Emits a constant signal, which can be either a shape, color or - boolean (1 / 0). + name: Señal costante + description: Emite una señal constante, que puede ser una forma, color o valor booleano (1 / 0). lever: default: - name: Switch - description: Can be toggled to emit a boolean signal (1 / 0) on the wires layer, - which can then be used to control for example an item filter. + name: Interruptor + description: Puede ser activado para emitir una señal booleana (1 / 0) en la capa de cables, + la cual puede ser usada por ejemplo para un filtro de items. logic_gate: default: - name: AND Gate - description: Emits a boolean "1" if both inputs are truthy. (Truthy means shape, - color or boolean "1") + name: Puerta AND + description: Emite el valor booleano "1" si ambas entradas son verdaderas. (Verdadeas significa una forma, + color o valor booleano "1") not: - name: NOT Gate - description: Emits a boolean "1" if the input is not truthy. (Truthy means - shape, color or boolean "1") + name: Puerta NOT + description: Emite el valor booleano "1" si ambas entradas no son verdaderas. (Verdadeas significa una forma, + color o valor booleano "1") xor: - name: XOR Gate - description: Emits a boolean "1" if one of the inputs is truthy, but not both. - (Truthy means shape, color or boolean "1") + name: Puerta XOR + description: Emite el valor booleano "1" si una de las entradas es verdadera, pero no si ambas lo son. + (Verdadeas significa una forma, + color o valor booleano "1") or: - name: OR Gate - description: Emits a boolean "1" if one of the inputs is truthy. (Truthy means - shape, color or boolean "1") + name: Puerta OR + description: Emite el valor booleano "1" Si una de las entradas es verdadera. (Verdadeas significa una forma, + color o valor booleano "1") transistor: default: name: Transistor - description: Forwards the bottom input if the side input is truthy (a shape, - color or "1"). + description: Envia la señal de abajo si la señal del costado es verdadera (Verdadeas significa una forma, + color o valor booleano "1"). mirrored: name: Transistor - description: Forwards the bottom input if the side input is truthy (a shape, - color or "1"). + description: Envia la señal de abajo si la señal del costado es verdadera (Verdadeas significa una forma, + color o valor booleano "1"). filter: default: - name: Filter - description: Connect a signal to route all matching items to the top and the - remaining to the right. Can be controlled with boolean signals - too. + name: Filtro + description: Conecta una señal para enviar todas las que coincidan hacia arriba y las demás + hacia la derecha. También puede ser controlada por señales booleanas. display: default: - name: Display - description: Connect a signal to show it on the display - It can be a shape, - color or boolean. + name: Monitor + description: Conecta una señal para mostrarla en el monitor - Puede ser una forma, + color o valor booleano. reader: default: - name: Belt Reader - description: Allows to measure the average belt throughput. Outputs the last - read item on the wires layer (once unlocked). + name: Lector de cinta + description: Te permite medir la cantidad media de items que pasan por la cinta. Emite el último + item leído en la capa de cables (una vez desbloquada). analyzer: default: - name: Shape Analyzer - description: Analyzes the top right quadrant of the lowest layer of the shape - and returns its shape and color. + name: Analizador de formas + description: analiza el cuadrante de arriba a la derecha de la capa más baja de la forma + y devuelve su figura y color. comparator: default: - name: Compare - description: Returns boolean "1" if both signals are exactly equal. Can compare - shapes, items and booleans. + name: Comparador + description: Devuelve el valor booleano "1" Si ambas señales son exactamente iguales. Puede comparar + formas, items y valores booleanos. virtual_processor: default: - name: Virtual Cutter - description: Virtually cuts the shape into two halves. + name: Cortador virtual + description: Corta virtualmente la forma en dos. rotater: - name: Virtual Rotater - description: Virtually rotates the shape, both clockwise and counter-clockwise. + name: Rotador virtual + description: Rota virtualmente la forma, tanto en sentido del horario como sentido anti-horario. unstacker: - name: Virtual Unstacker - description: Virtually extracts the topmost layer to the right output and the - remaining ones to the left. + name: Desapilador virtual + description: Extrae virtualmente la capa más alta en la salida a la derecha y + las que quedan en la izquierda. stacker: - name: Virtual Stacker - description: Virtually stacks the right shape onto the left. + name: Apilador virtual + description: Apila virtualmente la forma de la derecha en la de la izquierda. painter: - name: Virtual Painter - description: Virtually paints the shape from the bottom input with the shape on - the right input. + name: Pintor virtual + description: Pinta virtualmente la forma de la entrada de abajo con la forma de + la entrada de la derecha. item_producer: default: - name: Item Producer - description: Available in sandbox mode only, outputs the given signal from the - wires layer on the regular layer. + name: Productor de items + description: Solo disponible en modo libre, envía la señal recivida de la + capa de cables en la capa regular. storyRewards: reward_cutter_and_trash: title: Cortador de figuras - desc: You just unlocked the cutter, which cuts shapes in half - from top to bottom regardless of its - orientation!

Be sure to get rid of the waste, or - otherwise it will clog and stall - For this purpose - I have given you the trash, which destroys - everything you put into it! + desc: ¡Acabas de desbloquear el cortador, el cual corta formas por la mitad + de arriba a abajo independientemente de su + orientacion!

Asegurate de deshacerte de la basura, o + sino se trabará y parará - Por este proposite + Te he dado el basurero, el cual destruye + todo lo que pongas dentro de él! reward_rotater: title: Rotador desc: ¡El rotador se ha desbloqueado! Rota figuras en sentido @@ -592,9 +619,9 @@ storyRewards: será apilada encima de la entrada izquierda! reward_splitter: title: Separador/Fusionador - desc: You have unlocked a splitter variant of the - balancer - It accepts one input and splits them - into two! + desc: Has desbloqueado el separador , una variante de el + balanceador - Acepta una entrada y la separa + en dos! reward_tunnel: title: Túnel desc: El túnel se ha desbloqueado - ¡Ahora puedes transportar @@ -606,10 +633,10 @@ storyRewards: y pulsa 'T' para ciclar por sus variantes reward_miner_chainable: title: Extractor en cadena - desc: "You have unlocked the chained extractor! It can - forward its resources to other extractors so you - can more efficiently extract resources!

PS: The old - extractor has been replaced in your toolbar now!" + desc: "¡Has desbloqueado el extractor en cadena! ¡Este puede + enviar sus recursos a otros extractores así puedes + extraer recursos más eficientemente!

PD: ¡El extractor + viejo ha sido reemplazado en tu barra de herramientas!" reward_underground_belt_tier_2: title: Túnel nivel II desc: Has desbloqueado una nueva variante del túnel - ¡Tiene un @@ -626,13 +653,13 @@ storyRewards: consumiendo solo un color en vez de dos! reward_storage: title: Almacenamiento intermedio - desc: You have unlocked the storage building - It allows you to - store items up to a given capacity!

It priorities the left - output, so you can also use it as an overflow gate! + desc: Haz desbloquado el edificio de almacenamiento - ¡Te permite + guardar items hasta una capacidad determinada!

Prioriza la salida + de la izquierda, por lo que tambien puedes suarlo como una puerta de desbordamiento! reward_freeplay: title: Juego libre - desc: You did it! You unlocked the free-play mode! This means - that shapes are now randomly generated!

+ desc: ¡Lo hiciste! Haz desbloqueado el modo de juego libre! ¡Esto significa + que las formas ahora son aleatoriamente generadas!

Since the hub will require a throughput from now on, I highly recommend to build a machine which automatically delivers the requested shape!

The HUB outputs the requested @@ -657,77 +684,78 @@ storyRewards: desc: ¡Felicidades! ¡Por cierto, hay más contenido planeado para el juego completo! reward_balancer: - title: Balancer - desc: The multifunctional balancer has been unlocked - It can - be used to build bigger factories by splitting and merging - items onto multiple belts! + title: Balanceador + desc: El balanceador multifuncional ha sido desbloqueado - ¡Este puede + ser usado para construir fabricas más grandes al separar y mezclar + items hacia múltiples cintas! reward_merger: - title: Compact Merger - desc: You have unlocked a merger variant of the - balancer - It accepts two inputs and merges them - into one belt! + title: Unión compacta + desc: Has desbloqueado la variante unión de el + balanceador - ¡Acepta dos entradas y las une en + una sola cinta! reward_belt_reader: - title: Belt reader - desc: You have now unlocked the belt reader! It allows you to - measure the throughput of a belt.

And wait until you unlock - wires - then it gets really useful! + title: Lector de cinta + desc: ¡Has desbloqueado el lector de cinta! Este te permite + medir la cantidad de items que pasan por esta.
rotater! - It allows - you to rotate a shape by 180 degress (Surprise! :D) + title: Rotador (180 grados) + desc: ¡Has desbloqueado el rotador de 180 grados! - Te permite + rotar una forma en 180 grados (¡Sorpresa! :D) reward_display: - title: Display - desc: "You have unlocked the Display - Connect a signal on the - wires layer to visualize it!

PS: Did you notice the belt - reader and storage output their last read item? Try showing it on a - display!" + title: Monitor + desc: "Has desbloqueado el Monitor - ¡Conecta una señal dentro de + la capa de cables para visualizarla!

PD: ¿Te has dado cuenta que el lector + de cinta y el almacenador emiten su último item leído? ¡Trata de conectarlo + al monitor!" reward_constant_signal: - title: Constant Signal - desc: You unlocked the constant signal building on the wires - layer! This is useful to connect it to item filters - for example.

The constant signal can emit a - shape, color or - boolean (1 / 0). + title: Señal constante + desc: ¡Has desbloqueado la señal constante en la capa de + cables! Esto es muy útil para conectar a el filtro de items + por ejemplo.

La señal constante puede emitir + formas, colores o + valores booleanos (1 / 0). reward_logic_gates: - title: Logic Gates - desc: You unlocked logic gates! You don't have to be excited - about this, but it's actually super cool!

With those gates - you can now compute AND, OR, XOR and NOT operations.

As a - bonus on top I also just gave you a transistor! + title: Puertas lógicas + desc: ¡Has desbloqueado las puertas lógicas! No es necesario que te emociones + por esto ¡Pero en realidad es super geniall!

Con estas puertas + ahora puedes computar operaciones AND, OR, XOR y NOT.

Como bonus + también te he dado el transistor! reward_virtual_processing: - title: Virtual Processing - desc: I just gave a whole bunch of new buildings which allow you to - simulate the processing of shapes!

You can - now simulate a cutter, rotater, stacker and more on the wires layer! - With this you now have three options to continue the game:

- - Build an automated machine to create any possible - shape requested by the HUB (I recommend to try it!).

- Build - something cool with wires.

- Continue to play - regulary.

Whatever you choose, remember to have fun! + title: Procesamiento virtual + desc: ¡Acabo de darte un monton de nuevos edificios los cuales te permiten + simular el procesamiento de las formas!

¡Ahora puedes + simular un cortador, rotador, apilador y más dentro de la capa de cables! + Con esto ahora tienes tres opciones para continuar el juego:

- + Construir una maquina automatizada para crear cualquier + forma que te pida el HUB (¡Te recomiendo que lo intentes!).

- Construir + algo genial con los cables.

- Continuar jugando de + la manera regular.

¡Cualquiera que eligas, recuerda divertirte! reward_wires_painter_and_levers: - title: Wires & Quad Painter - desc: "You just unlocked the Wires Layer: It is a separate - layer on top of the regular layer and introduces a lot of new - mechanics!

For the beginning I unlocked you the Quad - Painter - Connect the slots you would like to paint with on - the wires layer!

To switch to the wires layer, press - E." + title: Cables y pintor cuádruple + desc: "Has desbloqueado la Capa de cables: ¡Es una capa + separada a la capa regular e introduce un montón de mecanicas + nuevas!

Para empezar te he dado el Pintor + Cuádruple - ¡Conecta las ranuras que quieras pintar usando + la capa de cables!

Para cambiar a la capa de cables, presiona la tecla + E.

PD: ¡Activa las pistas en + las opciones para activar el tutorial de cables!" reward_filter: - title: Item Filter - desc: You unlocked the Item Filter! It will route items either - to the top or the right output depending on whether they match the - signal from the wires layer or not.

You can also pass in a - boolean signal (1 / 0) to entirely activate or disable it. + title: Filtro de items + desc: Has desbloqueado el Filtro de Items! Este enviará los items tanto + arriaba como a la derecha dependiendo en si coinciden con la + señal de la capa de cables o no.

Tambien puedes enviar una señal + booleana (1 / 0) para activarlo o desactivarlo completamente. reward_demo_end: - title: End of Demo - desc: You have reached the end of the demo version! + title: Fin de la demo + desc: ¡Has llegado al final de la demo! settings: title: Opciones categories: general: General - userInterface: User Interface + userInterface: Interfaz de Usuario advanced: Avanzado - performance: Performance + performance: Rendimiento versionBadges: dev: Desarrollo staging: Escenificación @@ -839,51 +867,54 @@ settings: description: Deshabilita los diálogos de advertencia que se muestran cuando se cortan/eliminan más de 100 elementos. soundVolume: - title: Sound Volume - description: Set the volume for sound effects + title: Volumen de efectos + description: Establece el volumen para los efectos de sonido musicVolume: - title: Music Volume - description: Set the volume for music + title: Volumen de música + description: Establece el volumen para la música lowQualityMapResources: - title: Low Quality Map Resources - description: Simplifies the rendering of resources on the map when zoomed in to - improve performance. It even looks cleaner, so be sure to try it - out! + title: Recursos del mapa de baja calidad + description: Simplifica el renderizado de los recusos en el mapa al ser vistos desde cerca, + mejorando el rendimiento. ¡Incluso se ve más limpio, asi que asegurate de probarlo! disableTileGrid: - title: Disable Grid - description: Disabling the tile grid can help with the performance. This also - makes the game look cleaner! + title: Deshabilitar grilla + description: Deshabilitar la grilla puede ayudar con el rendimiento. ¡También hace + que el juego se vea más limpio! clearCursorOnDeleteWhilePlacing: - title: Clear Cursor on Right Click - description: Enabled by default, clears the cursor whenever you right click - while you have a building selected for placement. If disabled, - you can delete buildings by right-clicking while placing a - building. + title: Limpiar el cursos al apretar click derecho + description: Activado por defecto, Limpia el cursor al hacer click derecho + mientras tengas un un edificio seleccionado. Si se deshabilita, + puedes eliminar edificios al hacer click derecho mientras pones + un edificio. lowQualityTextures: - title: Low quality textures (Ugly) - description: Uses low quality textures to save performance. This will make the - game look very ugly! + title: Texturas de baja calidad (Feo) + description: Usa texturas de baja calidad para mejorar el rendimiento. ¡Esto hará que el + juego se vea muy feo! displayChunkBorders: - title: Display Chunk Borders - description: The game is divided into chunks of 16x16 tiles, if this setting is - enabled the borders of each chunk are displayed. + title: Mostrar bordes de chunk + description: Este juego está dividido en chunks de 16x16 cuadrados, si esta opción es + habilitada los bordes de cada chunk serán mostrados. pickMinerOnPatch: - title: Pick miner on resource patch - description: Enabled by default, selects the miner if you use the pipette when - hovering a resource patch. + title: Elegír el minero en la veta de recursos + description: Activado pir defecto, selecciona el minero si usas el cuentagotas sobre + una veta de recursos. simplifiedBelts: - title: Simplified Belts (Ugly) - description: Does not render belt items except when hovering the belt to save - performance. I do not recommend to play with this setting if you - do not absolutely need the performance. + title: Cintas trasportadoras simplificadas (Feo) + description: No rederiza los items en las cintas trasportadoras exceptuando al pasar el cursor sobre la cinta para mejorar + el rendimiento. No recomiendo jugar con esta opcion activada + a menos que necesites fuertemente mejorar el rendimiento. enableMousePan: - title: Enable Mouse Pan - description: Allows to move the map by moving the cursor to the edges of the - screen. The speed depends on the Movement Speed setting. + title: Habilitar movimiento con mouse + description: Te permite mover el mapa moviendo el cursor hacia los bordes de la + pantalla. La velocidad depende de la opción de velocidad de movimiento. zoomToCursor: - title: Zoom towards Cursor - description: If activated the zoom will happen in the direction of your mouse - position, otherwise in the middle of the screen. + title: Hacer zoom donde está el cursor + description: Si se activa, se hará zoom en al dirección donde esté tu cursor, + a diferencia de hacer zoom en el centro de la pantalla. + mapResourcesScale: + title: Tamaño de recursos en el mapa + description: Controla el tamaño de los recursos en la vista de aerea del mapa (Al hacer zoom + minimo). rangeSliderPercentage: % keybindings: title: Atajos de teclado @@ -942,21 +973,21 @@ keybindings: placementDisableAutoOrientation: Desactivar orientación automática placeMultiple: Permanecer en modo de construcción placeInverse: Invierte automáticamente la orientación de las cintas transportadoras - balancer: Balancer - storage: Storage - constant_signal: Constant Signal - logic_gate: Logic Gate - lever: Switch (regular) - filter: Filter - wire_tunnel: Wire Crossing - display: Display - reader: Belt Reader - virtual_processor: Virtual Cutter + balancer: Balanceador + storage: Almacenamiento + constant_signal: Señal constante + logic_gate: Puerta lógica + lever: Interruptor (regular) + filter: Filtro + wire_tunnel: Cruze de cables + display: Monitor + reader: Lector de cinta + virtual_processor: Cortador virtual transistor: Transistor - analyzer: Shape Analyzer - comparator: Compare - item_producer: Item Producer (Sandbox) - copyWireValue: "Wires: Copy value below cursor" + analyzer: Analizador de formas + comparator: Comparador + item_producer: Productor de items (Sandbox) + copyWireValue: "Cables: Copiar valor bajo el cursos" backwardsModifier: "Modifier: Cycle backwards" about: title: Sobre el juego diff --git a/translations/base-fi.yaml b/translations/base-fi.yaml index 1d08f181..30c88e7d 100644 --- a/translations/base-fi.yaml +++ b/translations/base-fi.yaml @@ -2,51 +2,51 @@ steamPage: shortText: shapez.io on peli tehtaiden rakentamisesta, joiden avulla automatisoidaan yhä monimutkaisempien muotojen luonti and yhdisteleminen loputtomassa maailmassa. - discordLinkShort: Official Discord + discordLinkShort: Virallinen Discord intro: >- - Shapez.io is a relaxed game in which you have to build factories for the - automated production of geometric shapes. + Shapez.io on rento peli, jossa sinun täytyy rakentaa tehtaita geometristen muotojen + automatisoituun tuotantoon. - As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map. + Kun taso kasvaa, muodot tulevat entistä vaikeammaksi sekä sinun täytyy laajentua loputtomassa kartassa. - And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling! + Ja jos tämä ei ollut tarpeeksi, niin sinun täytyy tuottaa eksponentiaalisesti enemmän täyttääksesi tarpeet - ainut asia mikä auttaa on skaalautuminen! - While you only process shapes at the beginning, you have to color them later - for this you have to extract and mix colors! + Vaikka alussa vain prosessoit muotoja, myöhemmin niitä pitää maalata - tätä varten täytyy sinun kaivaa ja sekoittaa värejä - Buying the game on Steam gives you access to the full version, but you can also play a demo on shapez.io first and decide later! - title_advantages: Standalone Advantages + Pelin ostaminen Steamista antaa sinulle pääsyn pelin kokoversioon, mutta voit myös pelata kokeiluversiota esin sivuillamme shapez.io ja päättää myöhemmin! + title_advantages: Kokoversion hyödyt advantages: - - 12 New Level for a total of 26 levels - - 18 New Buildings for a fully automated factory! - - 20 Upgrade Tiers for many hours of fun! - - Wires Update for an entirely new dimension! - - Dark Mode! - - Unlimited Savegames - - Unlimited Markers - - Support me! ❤️ - title_future: Planned Content + - 12 uutta tasoa nostaen tasojen määrän 26 tasoon! + - 18 uutta rakennusta täysin automatisoidulle tehtaalle! + - 20 päivitystasoa monelle hauskalle pelitunnille! + - Johdot -päivitys tuoden täyden uuden ulottuvuuden! + - Tumma teema! + - Rajattomat tallennukset + - Rajattomat merkit + - Tue minua! ❤️ + title_future: Suunniteltu sisältö planned: - - Blueprint Library (Standalone Exclusive) + - Pohjapiirustus kirjasto (Standalone Exclusive) - Steam Achievements - - Puzzle Mode - - Minimap - - Mods - - Sandbox mode - - ... and a lot more! - title_open_source: This game is open source! - title_links: Links + - Palapelitila + - Minikartta + - Modit + - Hiekkalaatikko -tila + - ... ja paljon muuta! + title_open_source: Tämä peli on avointa lähdekoodia! + title_links: Linkit links: - discord: Official Discord + discord: Virallinen Discord roadmap: Roadmap subreddit: Subreddit - source_code: Source code (GitHub) - translate: Help translate + source_code: Lähdekoodi (GitHub) + translate: Auta kääntämään text_open_source: >- - Anybody can contribute, I'm actively involved in the community and - attempt to review all suggestions and take feedback into consideration - where possible. + Kuka tahansa voi osallistua. Olen aktiivisesti mukana yhteisössä ja + yritän tarkistaa kaikki ehdotukset ja ottaa palautteen huomioon missä + mahdollista. - Be sure to check out my trello board for the full roadmap! + Muista tarkistaa Trello -lautani, jossa löytyy koko roadmap! global: loading: Ladataan error: Virhe @@ -60,7 +60,7 @@ global: infinite: ∞ time: oneSecondAgo: yksi sekunti sitten - xSecondsAgo: sekunttia sitten + xSecondsAgo: sekuntia sitten oneMinuteAgo: yksi minuutti sitten xMinutesAgo: minuuttia sitten oneHourAgo: yksi tunti sitten @@ -76,11 +76,11 @@ global: control: CTRL alt: ALT escape: ESC - shift: VAIHTO + shift: SHIFT space: VÄLILYÖNTI demoBanners: title: Demoversio - intro: Hanki itsenäinen peli avataksesi kaikki omunaisuudet! + intro: Hanki pelin kokoversio avataksesi kaikki ominaisuudet! mainMenu: play: Pelaa continue: Jatka @@ -89,13 +89,13 @@ mainMenu: subreddit: Reddit importSavegame: Tuo peli openSourceHint: Tämä on avoimen lähdekoodin peli! - discordLink: Virallinen Discord Palvelin + discordLink: Virallinen Discord -palvelin helpTranslate: Auta kääntämään! madeBy: Pelin on tehnyt browserWarning: Anteeksi, mutta pelin tiedetään toimivan huonosti selaimellasi! - Hanki itsenäinen versio tai lataa Chrome täyttä tukea varten. + Hanki pelin kokoversio tai lataa Google Chrome täyttä tukea varten. savegameLevel: Taso - savegameLevelUnknown: Tuntematon Taso + savegameLevelUnknown: Tuntematon taso savegameUnnamed: Unnamed dialogs: buttons: @@ -105,13 +105,13 @@ dialogs: later: Myöhemmin restart: Käynnistä uudelleen reset: Nollaa - getStandalone: Hanki itsenäinen peli + getStandalone: Hanki kokoversio deleteGame: Tiedän mitä olen tekemässä viewUpdate: Näytä päivitys - showUpgrades: Näytä Päivitykset + showUpgrades: Näytä päivitykset showKeybindings: Näytä pikanäppäimet importSavegameError: - title: Tuonti Virhe + title: Tuontivirhe text: "Tallennuksen tuonti epäonnistui:" importSavegameSuccess: title: Tallennus tuotiin @@ -121,9 +121,9 @@ dialogs: text: "Tallennuksen lataus epäonnistui:" confirmSavegameDelete: title: Varmista poisto - text: Are you sure you want to delete the following game?

- '' at level

This can not be - undone! + text: Oletko varma, että haluat poistaa valitun pelin?

+ '' tasossa

Tätä toimintoa ei + voida peruuttaa! savegameDeletionError: title: Poisto epäonnistui text: "Tallennuksen poisto epäonnistui:" @@ -132,8 +132,8 @@ dialogs: text: Käynnistä peli uudelleen ottaaksesi asetukset käyttöön. editKeybinding: title: Vaihda pikanäppäin - desc: Paina näppäintä tai hiiren nappia jonka haluat asettaa tai paina escape - peruuttaaksesi. + desc: Paina näppäintä tai hiiren nappia, jonka haluat asettaa tai paina + escape peruuttaaksesi. resetKeybindingsConfirmation: title: Nollaa pikanäppäimet desc: Tämä nollaa kaikki pikanäppäimet oletusarvoihin. Vahvista. @@ -142,32 +142,32 @@ dialogs: desc: Pikanäppäimet nollattiin oletusarvoihin! featureRestriction: title: Demoversio - desc: Yritit käyttää ominaisuutta () joka ei ole saatavilla - demoversiossa. Harkitse itsenäisen version hankkimista avataksesi + desc: Yritit käyttää ominaisuutta (), joka ei ole saatavilla + demoversiossa. Harkitse kokoversio avataksesi kaikki ominaisuudet! oneSavegameLimit: title: Rajoitetut tallennukset desc: Sinulla voi olla vain yksi tallennus kerrallaan demoversiossa. Poista - vanha tallennus tai hanki itsenäinen versio! + vanha tallennus tai hanki kokoversio pelistä! updateSummary: title: Uusi päivitys! - desc: "Tässä on tulleet muutokset sen jälkeen kun viimeksi pelasit:" + desc: "Tässä uudet muutokset sen jälkeen kun viimeksi pelasit:" upgradesIntroduction: - title: Avaa Päivitykset - desc: Kaikkia muodoja joita tuotat voi käyttää päivitysten avaamiseen - + title: Avaa päivitykset + desc: Kaikkia muotoja joita tuotat voidaan käyttää päivitysten avaamiseen - Älä tuhoa vanhoja tehtaitasi! Löydät päivitysikkunan näytön oikeasta yläkulmasta. massDeleteConfirm: title: Vahvista poisto - desc: Olet poistamassa paljon rakennuksia (tasan )! Oletko varma että + desc: Olet poistamassa paljon rakennuksia ( tarkalleen)! Oletko varma, että haluat jatkaa? massCutConfirm: - title: Vahtista leikkaus - desc: Olet leikkaamassa paljon rakennuksia (tasan )! Oletko varma että + title: Vahvista leikkaus + desc: Olet leikkaamassa paljon rakennuksia ( tarkalleen)! Oletko varma, että haluat jatkaa? blueprintsNotUnlocked: title: Ei vielä avattu - desc: Suorita taso 12 avataksesi Piirustukset! + desc: Suorita taso 12 avataksesi piirustukset! keybindingsIntroduction: title: Hyödyllisiä pikanäppäimiä desc: "Tässä pelissä on paljon pikanäppäimiä, jotka tekevät isojen tehtaiden @@ -178,13 +178,13 @@ dialogs: useita samoja rakennuksia.
ALT: Käännä sijoitettavien hihnojen suunta.
" createMarker: - title: Uusi Merkki - desc: Give it a meaningful name, you can also include a short - key of a shape (Which you can generate here) + title: Uusi merkki + desc: Anna merkille merkitsevä nimi. Voit myös liittää lyhyen koodin + muodosta. (Jonka voit luoda täällä.) titleEdit: Muokkaa merkkiä markerDemoLimit: - desc: Voit tehdä vain kaksi mukautettua merkkiä demoversiossa. Hanki itsenäinen - versio saadaksesi loputtoman määrän merkkejä! + desc: Voit tehdä vain kaksi mukautettua merkkiä demoversiossa. Hanki kokoversio + saadaksesi loputtoman määrän merkkejä! exportScreenshotWarning: title: Vie kuvakaappaus desc: Pyysit tukikohtasi viemistä kuvakaappauksena. Huomaa, että tämä voi olla @@ -199,8 +199,14 @@ dialogs: descShortKey: ... or enter the short key of a shape (Which you can generate here) renameSavegame: - title: Rename Savegame - desc: You can rename your savegame here. + title: Nimeä tallennus uudelleen + desc: Voit nimetä tallennuksesi uudelleen täällä. + tutorialVideoAvailable: + title: Ohjevideo saatavilla + desc: Tästä tasosta on saatavilla ohjevideo! Haluaisitko katsoa sen? + tutorialVideoAvailableForeignLanguage: + title: Ohjevideo saatavilla + desc: Tästä tasosta on saatavilla ohjevideo! Haluaisitko katsoa sen? ingame: keybindingsOverlay: moveMap: Liiku @@ -219,9 +225,9 @@ ingame: plannerSwitchSide: Käännä suunnittelijan puoli cutSelection: Leikkaa copySelection: Kopioi - clearSelection: Tyhjennä Valinta + clearSelection: Tyhjennä valinta pipette: Pipetti - switchLayers: Vaihda Tasoa + switchLayers: Vaihda tasoa colors: red: Punainen green: Vihreä @@ -233,7 +239,7 @@ ingame: uncolored: Väritön black: Musta buildingPlacement: - cycleBuildingVariants: Paina kiertääksesi muunnoksia. + cycleBuildingVariants: Paina selataksesi vaihtoehtoja. hotkeyLabel: "Pikanäppäin: " infoTexts: speed: Nopeus @@ -251,7 +257,7 @@ ingame: notifications: newUpgrade: Uusi päivitys on saatavilla! gameSaved: Peli on tallennettu. - freeplayLevelComplete: Level has been completed! + freeplayLevelComplete: Taso on saavutettu! shop: title: Päivitykset buttonUnlock: Päivitä @@ -269,7 +275,7 @@ ingame: välituotteet. delivered: title: Toimitettu - description: Näyttää muodot jotka on toimitettu keskusrakennukseen. + description: Näyttää muodot, jotka on toimitettu keskusrakennukseen. noShapesProduced: Toistaiseksi ei muotoja tuotettu. shapesDisplayUnits: second: / s @@ -288,9 +294,9 @@ ingame: waypoints: waypoints: Merkit hub: Keskusrakennus - description: Paina merkkia hiiren vasemmalla mennäksesi siihen, paina oikeaa + description: Paina merkkiä hiiren vasemmalla mennäksesi siihen, paina oikeaa nappia poistaaksesi sen.

Paina luodaksesi merkin - nykyisestä näkymästä tai varen nappi luodaksesi + nykyisestä näkymästä tai vasen nappi luodaksesi merkin valittuun paikkaan. creationSuccessNotification: Merkki luotiin onnistuneesti. shapeViewer: @@ -310,73 +316,97 @@ ingame: valmiiksi.

Vihje: Pidä pohjassa VAIHTO laittaaksesi useampia kaivajia ja käytä R kääntääksesi niitä." + 2_1_place_cutter: "Nyt aseta Leikkuri leikataksesi ympyrä + puoliksi!

PS: Leikkuri aina leikkaa ylhäältä alaspäin + riippumatta sen asennosta." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: - one_miner: 1 Miner - n_miners: Miners - limited_items: Limited to + one_miner: 1 kaivaja + n_miners: kaivajaa + limited_items: Rajoitettu watermark: - title: Demo version - desc: Click here to see the Steam version advantages! - get_on_steam: Get on steam + title: Kokeiluversio + desc: Napsauta tästä nähdäksesi Steam version edut! + get_on_steam: Hanki Steamista standaloneAdvantages: - title: Get the full version! - no_thanks: No, thanks! + title: Hanki kokoversio! + no_thanks: Ei kiitos! points: levels: - title: 12 New Levels - desc: For a total of 26 levels! + title: 12 Uutta tasoa + desc: Yhteensä 26 tasoa! buildings: - title: 18 New Buildings - desc: Fully automate your factory! + title: 18 Uutta rakennusta + desc: Automatisoi tehtaasi täysin! savegames: - title: ∞ Savegames - desc: As many as your heart desires! + title: ∞ Tallennukset + desc: Niin paljon kuin sielusi kaipaa! upgrades: - title: 20 Upgrade Tiers - desc: This demo version has only 5! + title: 20 päivitystasoa + desc: Kokeiluversiossa on vain viisi! markers: - title: ∞ Markers - desc: Never get lost in your factory! + title: ∞ Merkit + desc: Älä koskaan eksy tehtaassasi! wires: - title: Wires - desc: An entirely new dimension! + title: Johdot + desc: Täysin uusi ulottuvuus! darkmode: - title: Dark Mode - desc: Stop hurting your eyes! + title: Tumma teema + desc: Jotta silmiisi ei sattuisi! support: - title: Support me - desc: I develop it in my spare time! + title: Tue minua + desc: Kehitän peliä vapaa-ajallani! shopUpgrades: belt: - name: Hihnat, Jakelija & Tunneli + name: Hihnat, jakelija & tunneli description: Nopeus x → x miner: name: Kaivuu description: Nopeus x → x processors: - name: Leikkaus, Kääntö & Pinoaminen + name: Leikkaus, kääntö & pinoaminen description: Nopeus x → x painting: - name: Sekoitus & Värjäys + name: Sekoitus & värjäys description: Nopeus x → x buildings: hub: deliver: Toimita toUnlock: avataksesi levelShortcut: LVL - endOfDemo: End of Demo + endOfDemo: Kokeiluversion loppu! belt: default: name: Liukuhihna - description: Kuljettaa esineitä, pidä pohjassa ja raahaa laittaaksesi useampia. + description: Kuljettaa esineitä. Pidä pohjassa ja raahaa laittaaksesi useampia. wire: default: name: Johto - description: Sallii sähkön kuljetuksen + description: Sallii sähkönkuljetuksen second: - name: Wire - description: Transfers signals, which can be items, colors or booleans (1 / 0). - Different colored wires do not connect. + name: Johto + description: Siirtää signaaleja, jotka voivat olla muotoja, värejä, taikka binääriarvoja (1 / 0). + Eriväriset johdot eivät yhdisty toisiinsa. miner: default: name: Kaivaja @@ -390,7 +420,7 @@ buildings: name: Tunneli description: Sallii resurssien kuljetuksen rakennuksien ja hihnojen alta. tier2: - name: Tunneli Taso II + name: Tunneli taso II description: Sallii resurssien kuljetuksen rakennuksien ja hihnojen alta pidemmältä kantamalta. cutter: @@ -409,11 +439,11 @@ buildings: name: Kääntäjä description: Kääntää muotoja 90 astetta myötäpäivään. ccw: - name: Kääntäjä (Vastapäivään) + name: Kääntäjä (vastapäivään) description: Kääntää muotoja 90 astetta vastapäivään. rotate180: - name: Rotate (180) - description: Rotates shapes by 180 degrees. + name: Kääntäjä (180) + description: Kääntää muotoja 180 astetta. stacker: default: name: Pinoaja @@ -425,19 +455,19 @@ buildings: description: Sekoittaa kaksi väriä lisäaineiden avulla. painter: default: - name: Värjääjä - description: Värjää vasemmasta sisääntulosta tulevan muodon ylemmästä + name: Maalari + description: Maalaa vasemmasta sisääntulosta tulevan muodon ylemmästä sisääntulosta tulevalla värillä. mirrored: - name: Värjääjä - description: Värjää vasemmasta sisääntulosta tulevan muodon ylemmästä + name: Maalari + description: Maalaa vasemmasta sisääntulosta tulevan muodon alemmasta sisääntulosta tulevalla värillä. double: - name: Värjääjä (Kaksinkertainen) - description: Värjää vasemmasta sisääntulosta tulevan muodon ylemmästä + name: Maalari (kaksinkertainen) + description: Värjää vasemmasta sisääntulosta tulevat muodot ylemmästä sisääntulosta tulevalla värillä. quad: - name: Painter (Neljännes) + name: Maalari (neljännes) description: Allows you to color each quadrant of the shape individually. Only slots with a truthy signal on the wires layer will be painted! @@ -447,114 +477,111 @@ buildings: description: Sallii sisääntulot kaikilta sivuilta ja tuhoaa ne. Lopullisesti. balancer: default: - name: Balancer - description: Multifunctional - Evenly distributes all inputs onto all outputs. + name: Tasaaja + description: Monikäyttöinen - Jaa sisääntulot tasaisesti kaikkiin ulostuloihin. merger: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Yhdistäjä (compact) + description: Yhdistää kaksi hihnaa yhteen. merger-inverse: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Yhdistäjä (compact) + description: Yhdistää kaksi hihnaa yhteen. splitter: - name: Splitter (compact) - description: Splits one conveyor belt into two. + name: Erottaja (compact) + description: Erottaa hihnan kahteen hihnaan. splitter-inverse: - name: Splitter (compact) - description: Splits one conveyor belt into two. + name: Erottaja (compact) + description: Erottaa hihnan kahteen hihnaan. storage: default: - name: Storage - description: Stores excess items, up to a given capacity. Prioritizes the left - output and can be used as an overflow gate. + name: Varasto + description: Varasotoi ylijäämätavarat tiettyyn kapasiteettiin asti. Priorisoi vasemman ulostulon + ja voidaan käyttää ylivuotoporttina. wire_tunnel: default: - name: Wire Crossing - description: Allows to cross two wires without connecting them. + name: Johdon ylitys + description: Antaa johdon ylittää toisen liittämättä niitä. constant_signal: default: - name: Constant Signal - description: Emits a constant signal, which can be either a shape, color or - boolean (1 / 0). + name: Jatkuva signaali + description: Lähettää vakiosignaalin, joka voi olla muoto, väri, taikka binääriarvo (1 / 0). lever: default: - name: Switch - description: Can be toggled to emit a boolean signal (1 / 0) on the wires layer, - which can then be used to control for example an item filter. + name: Kytkin + description: Voidaan kytkeä lähettämään binääriarvoa (1 / 0) johtotasolla, + jota voidaan sitten käyttää esimerkiksi tavarasuodattimen ohjaukseen. logic_gate: default: - name: AND Gate - description: Emits a boolean "1" if both inputs are truthy. (Truthy means shape, - color or boolean "1") + name: AND portti + description: Lähettää totuusarvon "1", jos molemmat sisääntulot ovat totta. (Totuus tarkoittaa, + että muoto, väri tai totuusarvo "1") not: - name: NOT Gate - description: Emits a boolean "1" if the input is not truthy. (Truthy means - shape, color or boolean "1") + name: NOT portti + description: Lähettää totuusarvon "1", jos sisääntulot eivät ole totta. + (Totuus tarkoittaa, että muoto, väri tai totuusarvo "1") xor: - name: XOR Gate - description: Emits a boolean "1" if one of the inputs is truthy, but not both. - (Truthy means shape, color or boolean "1") + name: XOR portti + description: Lähettää totuusarvon "1", jos yksi sisääntuloista on totta, mutta kaikki eivät. + (Totuus tarkoittaa, että muoto, väri tai totuusarvo "1") or: - name: OR Gate - description: Emits a boolean "1" if one of the inputs is truthy. (Truthy means - shape, color or boolean "1") + name: OR portti + description: Lähettää totuusarvon "1", jos yksi sisääntuloista on totta. + (Totuus tarkoittaa, että muoto, väri tai totuusarvo "1") transistor: default: - name: Transistor - description: Forwards the bottom input if the side input is truthy (a shape, - color or "1"). + name: Transistori + description: Lähettää pohjasignaalin eteenpäin, jos sivusisääntulo on totta. + (Totuus tarkoittaa, että muoto, väri tai totuusarvo "1") mirrored: - name: Transistor - description: Forwards the bottom input if the side input is truthy (a shape, - color or "1"). + name: Transistori + description: Lähettää pohjasignaalin eteenpäin, jos sivusisääntulo on totta. + (Totuus tarkoittaa, että muoto, väri tai totuusarvo "1") filter: default: - name: Filter - description: Connect a signal to route all matching items to the top and the - remaining to the right. Can be controlled with boolean signals - too. + name: Suodatin + description: Yhdistä signaali reitittääksesi kaikki vastaavat tavarat ylös, + ja jäljelle jäämät vasemmalle. Voidaan ohjata myös binääriarvoilla. display: default: - name: Display - description: Connect a signal to show it on the display - It can be a shape, - color or boolean. + name: Näyttö + description: Yhdistö signaali näyttääksesi sen näytöllä. Voi olla muoto, + väri tai binääriarvo. reader: default: - name: Belt Reader - description: Allows to measure the average belt throughput. Outputs the last - read item on the wires layer (once unlocked). + name: Hihnanlukija + description: Mittaa hihnan keskiarvosuorituskyky. Antaa viimeksi luetun + tavaran signaalin johtotasolla (kun saavutettu). analyzer: default: - name: Shape Analyzer - description: Analyzes the top right quadrant of the lowest layer of the shape - and returns its shape and color. + name: Tutkija + description: Analysoi ylä oikean neljänneksen alimmasta tavaran tasosta ja + palauttaa sen muodon ja värin. comparator: default: - name: Compare - description: Returns boolean "1" if both signals are exactly equal. Can compare - shapes, items and booleans. + name: Vertain + description: Palauttaa binääriarvon "1", jos molemmat signaalit ovat täysin samat. + Voi verrata värejä, tavaroita, ja binääriarvoja. virtual_processor: default: - name: Virtual Cutter - description: Virtually cuts the shape into two halves. + name: Virtuaalileikkuri + description: Virtuaalisesti leikkaa tavara kahteen puoliskoon. rotater: - name: Virtual Rotater - description: Virtually rotates the shape, both clockwise and counter-clockwise. + name: Virtuaalikääntäjä Rotater + description: Virtuaalisesti käännä tavara, sekä myötäpäivään että vastapäivään. unstacker: - name: Virtual Unstacker - description: Virtually extracts the topmost layer to the right output and the - remaining ones to the left. + name: Virtuaalierottaja + description: Virtuaalisesti erota ylin taso oikeaan ulostuloon ja jäljelle jäävät + vasempaan ulostuloon. stacker: - name: Virtual Stacker - description: Virtually stacks the right shape onto the left. + name: Virtuaaliyhdistäjä + description: Virtuaalisesti yhdistä oikea tavara vasempaan. painter: - name: Virtual Painter - description: Virtually paints the shape from the bottom input with the shape on - the right input. + name: Virtuaalimaalaaja + description: Virtuaalisesti maalaa tavara alhaalta sisääntulosta oikean sisääntulon värillä. item_producer: default: name: Item Producer - description: Available in sandbox mode only, outputs the given signal from the - wires layer on the regular layer. + description: Saatavilla vain hiekkalaatikkotilassa. Palauttaa + johtotasolla annetun signaalin normaaliin tasoon. storyRewards: reward_cutter_and_trash: title: Muotojen Leikkaus @@ -703,7 +730,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -711,26 +739,25 @@ storyRewards: signal from the wires layer or not.

You can also pass in a boolean signal (1 / 0) to entirely activate or disable it. reward_demo_end: - title: End of Demo - desc: You have reached the end of the demo version! + title: Kokeiluversion loppu! + desc: Olet läpäissyt kokeiluversion! settings: title: Asetukset categories: general: Yleinen - userInterface: Käyttöliittyma - advanced: Kehittynyt - performance: Performance + userInterface: Käyttöliittymä + advanced: Lisäasetukset + performance: Suorityskyky versionBadges: dev: Kehitys - staging: Näyttämö + staging: Testaus prod: Tuotanto - buildDate: Rakennettu + buildDate: Koottu labels: uiScale: - title: Käyttöliittymän Koko + title: Käyttöliittymän koko description: Muuttaa käyttöliittymän kokoa. Käyttöliittymä skaalataan silti - laitteen resoluution perusteella based on your device - resolution, mutta tämä asetus määrittää skaalauksen määrän. + laitteen resoluution perusteella, mutta tämä asetus määrittää skaalauksen määrän. scales: super_small: Erittäin pieni small: Pieni @@ -738,7 +765,7 @@ settings: large: Iso huge: Valtava autosaveInterval: - title: Automaattitallennuksen Aikaväli + title: Automaattitallennuksen aikaväli description: Määrittää kuinka usein peli tallentaa automaattisesti. Voit myös poistaa automaattisen tallennuksen kokonaan käytöstä täällä. intervals: @@ -749,8 +776,8 @@ settings: twenty_minutes: 20 Minuutin välein disabled: Pois käytöstä scrollWheelSensitivity: - title: Zoomausherkkyys - description: Vaihtaa kuinka herkkä zoomi on (Joko hiiren rulla tai ohjauslevy). + title: Suurennusherkkyys + description: Vaihtaa kuinka herkkä suurennus on (Joko hiiren rulla tai ohjauslevy). sensitivity: super_slow: Erittäin hidas slow: Hidas @@ -758,7 +785,7 @@ settings: fast: Nopea super_fast: Erittäin nopea movementSpeed: - title: Liikkumis nopeus + title: Liikkumisnopeus description: Muuttaa kuinka nopeasti näkymä liikkuu kun käytetään näppäimistöä. speeds: super_slow: Erittäin hidas @@ -766,7 +793,7 @@ settings: regular: Normaali fast: Nopea super_fast: Erittäin nopea - extremely_fast: Hyper nopea + extremely_fast: Supernopea language: title: Kieli description: Vaihda kieltä. Kaikki käännökset ovat käyttäjien tekemiä ja @@ -780,19 +807,19 @@ settings: description: On suositeltava pelata tätä peliä kokonäytön tilassa saadaksesi parhaan kokemuksen. Saatavilla vain itsenäisessä versiossa. soundsMuted: - title: Mykistä Äänet + title: Mykistä äänet description: Jos käytössä, mykistää kaikki ääniefektit. musicMuted: - title: Mykistä Musiikki + title: Mykistä musiikki description: Jos käytössä, mykistää musiikin. theme: - title: Pelin Teema + title: Pelin teema description: Valitse pelin teema (vaalea / tumma). themes: dark: Tumma - light: Kirkas + light: Vaalea refreshRate: - title: Simulaatiotavoite + title: Virkistystaajuus description: Jos sinulla on 144hz näyttö, muuta virkistystaajuus täällä jotta pelin simulaatio toimii oikein isommilla virkistystaajuuksilla. Tämä voi laskea FPS nopeutta, jos tietokoneesi on liian hidas. @@ -802,18 +829,18 @@ settings: jälkeen kunnes peruutat sen. Tämä vastaa SHIFT:in pitämistä pohjassa ikuisesti. offerHints: - title: Vihjeet & Oppaat + title: Vihjeet & oppaat description: Tarjoaa pelaamisen aikana vihjeitä ja oppaita. Myös piilottaa tietyt käyttöliittymäelementit tietyn tason mukaan, jotta alkuunpääseminen olisi helpompaa. enableTunnelSmartplace: - title: Älykkäät Tunnelit + title: Älykkäät tunnelit description: Kun käytössä, tunnelin sijoittaminen automaattisesti poistaa tarpeettomat liukuhihnat. Tämä myös ottaa käyttöön tunnelien raahaamisen ja ylimääräiset tunnelit poistetaan. vignette: - title: Vignetti - description: Ottaa käyttöön vignetin, joka tummentaa näytön kulmia ja tekee + title: Vinjetointi + description: Ottaa käyttöön vinjetoinnin, joka tummentaa näytön kulmia ja tekee tekstin lukemisesta helpompaa. rotationByBuilding: title: Kiertäminen rakennustyypin mukaan @@ -821,26 +848,26 @@ settings: yksilöllisesti. Tämä voi olla mukavampi vaihtoehto jos usein sijoitat eri rakennustyyppejä. compactBuildingInfo: - title: Kompaktit Rakennusten Tiedot + title: Kompaktit rakennusten tiedot description: Lyhentää rakennusten tietolaatikoita näyttämällä vain niiden suhteet. Muuten rakennuksen kuvaus ja kuva näytetään. disableCutDeleteWarnings: - title: Poista Leikkaus/Poisto Varoitukset + title: Poista leikkaus/poisto -varoitukset description: Poista varoitusikkunat jotka ilmestyy kun leikkaat/poistat enemmän kuin 100 entiteettiä soundVolume: - title: Sound Volume - description: Set the volume for sound effects + title: Efektien äänenvoimakkuus + description: Aseta äänenvoimakkuus efekteille musicVolume: - title: Music Volume - description: Set the volume for music + title: Musiikin äänenvoimakkuus + description: Aseta äänenvoimakkuus musiikille lowQualityMapResources: title: Low Quality Map Resources description: Simplifies the rendering of resources on the map when zoomed in to improve performance. It even looks cleaner, so be sure to try it out! disableTileGrid: - title: Disable Grid + title: Poista ruudukko description: Disabling the tile grid can help with the performance. This also makes the game look cleaner! clearCursorOnDeleteWhilePlacing: @@ -850,13 +877,13 @@ settings: you can delete buildings by right-clicking while placing a building. lowQualityTextures: - title: Low quality textures (Ugly) - description: Uses low quality textures to save performance. This will make the - game look very ugly! + title: Alhaisen tason tekstuurit (ruma) + description: Käyttää alhaisen tason tekstuureja tehojen säästämiseksi. Tämä + muutta pelin rumaksi! displayChunkBorders: - title: Display Chunk Borders - description: The game is divided into chunks of 16x16 tiles, if this setting is - enabled the borders of each chunk are displayed. + title: Näytä kimpaleiden reunus Display Chunk Borders + description: Pel on jaettu 16x16 kimpaleisiin. Jos tämä asetus on käytössä, + reunat jokaiselle kimpaleelle näytetään. pickMinerOnPatch: title: Pick miner on resource patch description: Enabled by default, selects the miner if you use the pipette when @@ -874,18 +901,22 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Pikanäppäimet - hint: "Tip: Muista käyttää CTRL, VAIHTO ja ALT! Ne ottavat käyttöön erilaisia + hint: "Tip: Muista käyttää CTRL, SHIFT ja ALT! Ne ottavat käyttöön erilaisia sijoitteluvaihtoehtoja." - resetKeybindings: Nollaa Pikanäppäimet + resetKeybindings: Nollaa pikanäppäimet categoryLabels: general: Sovellus ingame: Peli navigation: Navigointi placement: Sijoitus - massSelect: Massa Valinta + massSelect: Massavalinta buildings: Rakennus Pikanäppäimet placementModifiers: Sijoittelu Muokkaajat mappings: @@ -955,9 +986,9 @@ about: href="https://github.com/tobspr" target="_blank">Tobias Springer (tämä on minä).

- Jos haluat osallistua, tarkista shapez.io githubissa.

+ Jos haluat osallistua, tarkista shapez.io GitHubissa.

- Tämä peli ei olisi ollut mahdollinen ilman suurta Discord yhteisöä pelini ympärillä - Sinun kannattaisi liittyä Discord palvelimelleni!

+ Tämä peli ei olisi ollut mahdollista ilman suurta Discord -yhteisöä pelini ympärillä - Sinun kannattaisi liittyä Discord palvelimelleni!

Ääniraidan on tehnyt Peppsen - Hän on mahtava.

@@ -983,7 +1014,7 @@ tips: - Serial execution is more efficient than parallel. - You will unlock more variants of buildings later in the game! - You can use T to switch between different variants. - - Symmetry is key! + - Symmetria on keskeistä! - You can weave different tiers of tunnels. - Try to build compact factories - it will pay out! - The painter has a mirrored variant which you can select with T @@ -994,12 +1025,12 @@ tips: - Holding SHIFT will activate the belt planner, letting you place long lines of belts easily. - Cutters always cut vertically, regardless of their orientation. - - To get white mix all three colors. + - Sekoita kolmea väriä saadaksesi valkoista. - The storage buffer priorities the first output. - Invest time to build repeatable designs - it's worth it! - Holding CTRL allows to place multiple buildings. - You can hold ALT to invert the direction of placed belts. - - Efficiency is key! + - Tehokkuus on keskeistä! - Shape patches that are further away from the hub are more complex. - Machines have a limited speed, divide them up for maximum efficiency. - Use balancers to maximize your efficiency. @@ -1030,6 +1061,6 @@ tips: - This game has a lot of settings, be sure to check them out! - The marker to your hub has a small compass to indicate its direction! - To clear belts, cut the area and then paste it at the same location. - - Press F4 to show your FPS and Tick Rate. + - Paina F4 nähdäksesi FPS laskurin ja virkistystaajuuden. - Press F4 twice to show the tile of your mouse and camera. - You can click a pinned shape on the left side to unpin it. diff --git a/translations/base-hr.yaml b/translations/base-hr.yaml index 633e0f29..568838dd 100644 --- a/translations/base-hr.yaml +++ b/translations/base-hr.yaml @@ -198,6 +198,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Kretanje @@ -306,6 +314,30 @@ ingame: traka će ubrzati napredak do cilja.

Savjet: Drži SHIFT za postavljanje više rudara istovremeno, a pritisni R za rotaciju." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 Miner n_miners: Miners @@ -691,7 +723,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -859,6 +892,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Tipka diff --git a/translations/base-hu.yaml b/translations/base-hu.yaml index 8888452e..4fcf6bae 100644 --- a/translations/base-hu.yaml +++ b/translations/base-hu.yaml @@ -204,6 +204,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Mozgatás @@ -312,6 +320,30 @@ ingame: futószalagot, hogy hamarabb elérd a célt.

Tipp: Tartsd lenyomva a SHIFT-et, hogy egyszerre több bányát helyezz le, és nyomj R-t a forgatáshoz." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 Miner n_miners: Miners @@ -705,7 +737,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -875,6 +908,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Keybindings diff --git a/translations/base-ind.yaml b/translations/base-ind.yaml index 6ed9cf32..fe617737 100644 --- a/translations/base-ind.yaml +++ b/translations/base-ind.yaml @@ -1,60 +1,57 @@ steamPage: - shortText: Shapez.io adalah game tentang membangun pabrik untuk mengotomatiskan - pembuatan dan pemrosesan bentuk-bentuk yang semakin kompleks di peta - yang meluas tanpa batas. - discordLinkShort: Official Discord + shortText: shapez.io adalah game tentang membangun pabrik untuk mengotomatiskan + pembuatan dan pemrosesan bentuk-bentuk yang semakin lama semakin kompleks + di dalam peta yang meluas tanpa batas. + discordLinkShort: Server Discord Resmi intro: >- - Shapez.io adalah game santai dimana anda harus membuat pabrik untuk - mengotomatiskan produksi bentuk-bentuk geometris. + Kamu suka game otomasi? Maka kamu berada di tempat yang tepat! - Semakin meningkatnya level, bentuk-bentuknya menjadi lebih kompleks, dan anda perlu meluas di peta yang tak terbatas. + shapez.io adalah game santai dimana kamu harus membuat pabrik untuk mengotomatiskan produksi bentuk-bentuk geometris. Semakin meningkatnya level, bentuk-bentuknya menjadi lebih kompleks, dan kamu perlu meluaskan pabrikmu semakin jauh lagi. - Dan jita itu tidak cukup, anda juga perlu untuk memproduksi secara ekxponensial untuk memenuhkan kebutuhan - hal yang membantu hanyalah memperbesar pabrik! + Dan jita itu tidak cukup, kamu juga perlu memproduksi bentuk secara eksponensial untuk memenuhkan kebutuhan - hal yang membantu hanyalah memperbesar pabrik! Walaupun kamu hanya perlu memproses bentuk di awal, nantinya kamu harus memberinya warna - dengan mengekstrak dan mencampur warna! - Walaupun anda hanya memproses bentuk di awal, anda perlu mewarnainya untuk nanti - untuk ini, anda perlu untuk mengekstrak dan mencampur warna! - - Membeli game ini di Steam memberikan anda akses ke versi lengkap, namun anda juga dapat mencoba demo dan memutuskan nanti! - title_advantages: Keuntungan versi penuh + Membeli game ini di Steam memberikan kamu akses ke versi lengkap, namun kamu juga dapat mencoba demo dan memutuskan nanti! + title_advantages: Keuntungan Versi Lengkap advantages: - - 12 New Level for a total of 26 levels - - 18 New Buildings for a fully automated factory! - - 20 Upgrade Tiers for many hours of fun! - - Wires Update for an entirely new dimension! - - Dark Mode! - - Unlimited Savegames - - Unlimited Markers - - Support me! ❤️ - title_future: Planned Content + - 12 Level Baru dengan total 26 level + - 18 Bangunan Baru untuk membuat pabrik yang otomatis sepenuhnya! + - 20 Tingkatan Upgrade untuk keseruan berjam-jam! + - Update Kabel untuk dimensi yang benar-benar baru! + - Mode Gelap! + - Data Simpanan Tidak Terbatas + - Penanda Tidak Terbatas + - Dukung saya! ❤️ + title_future: Konten Terencana planned: - - Blueprint Library (Standalone Exclusive) - - Steam Achievements - - Puzzle Mode - - Minimap - - Mods - - Sandbox mode - - ... and a lot more! - title_open_source: This game is open source! - title_links: Links + - Penyimpanan Cetak Biru (Eksklusif Versi Lengkap) + - Achievement Steam + - Mode Puzzle + - Peta Kecil + - Modifikasi + - Mode Sandbox + - ... dan masih banyak lagi! + title_open_source: Game ini open source! + title_links: Tautan (Links) links: - discord: Official Discord - roadmap: Roadmap + discord: Server Discord Resmi + roadmap: Peta Jalan subreddit: Subreddit source_code: Source code (GitHub) - translate: Help translate + translate: Bantu menterjemahkan text_open_source: >- - Anybody can contribute, I'm actively involved in the community and - attempt to review all suggestions and take feedback into consideration - where possible. + Semua orang bisa berpartisipasi, saya aktif terlibat dalam komunitas dan + mencoba untuk meninjau semua saran dan mempertimbangkan segala umpan + balik jika memungkinkan. - Be sure to check out my trello board for the full roadmap! + Pastikan untuk memeriksa papan trello saya untuk peta jalan selengkapnya! global: - loading: Sedang memuat + loading: Memuat error: Terjadi kesalahan - thousandsDivider: "," - decimalSeparator: . + thousandsDivider: "." + decimalSeparator: "," suffix: - thousands: K - millions: J + thousands: rb + millions: Jt billions: M trillions: T infinite: tak terhingga @@ -67,8 +64,8 @@ global: xHoursAgo: jam yang lalu oneDayAgo: sehari yang lalu xDaysAgo: hari yang lalu - secondsShort: det - minutesAndSecondsShort: m det + secondsShort: dtk + minutesAndSecondsShort: m dtk hoursAndMinutesShort: j m xMinutes: menit keys: @@ -80,24 +77,24 @@ global: space: SPACE demoBanners: title: Versi Demo - intro: Dapatkan versi penuh untuk membuka semua fitur! + intro: Dapatkan versi lengkap untuk membuka semua fitur! mainMenu: play: Mulai Permainan - continue: Lanjutkan Permainan + continue: Lanjutkan newGame: Permainan Baru changelog: Catatan Perubahan subreddit: Reddit importSavegame: Impor Data Simpanan - openSourceHint: Permainan ini bekerja secara open source! + openSourceHint: Game ini open source! discordLink: Server Discord Resmi helpTranslate: Bantu Terjemahkan! madeBy: Dibuat oleh - browserWarning: Maaf, tetapi permainan ini biasanya lambat pada perambah - (browser) Anda! Dapatkan versi penuh atau unduh Chrome untuk pengalaman - sepenuhnya. + browserWarning: Maaf, tetapi permainan ini biasanya lambat pada + browser kamu! Dapatkan versi lengkap atau unduh Chrome untuk + pengalaman sepenuhnya. savegameLevel: Level savegameLevelUnknown: Level tidak diketahui - savegameUnnamed: Unnamed + savegameUnnamed: Tidak Dinamai dialogs: buttons: ok: OK @@ -106,37 +103,36 @@ dialogs: later: Nanti restart: Mulai Ulang reset: Setel Ulang - getStandalone: Dapatkan Versi Penuh - deleteGame: Saya tahu apa yang saya lakukan - viewUpdate: Tampilkan Pembaruan + getStandalone: Dapatkan Versi Lengkap + deleteGame: Aku tahu apa yang aku lakukan + viewUpdate: Tampilkan Update showUpgrades: Tunjukkan Tingkatan - showKeybindings: Tunjukan Tombol Pintas + showKeybindings: Tunjukkan Tombol Pintas importSavegameError: title: Kesalahan pada Impor - text: "Gagal memasukkan data simpanan Anda:" + text: "Gagal memasukkan data simpanan kamu:" importSavegameSuccess: title: Impor Berhasil - text: Data simpanan Anda berhasil dimasukkan. + text: Data simpanan kamu berhasil dimasukkan. gameLoadFailure: title: Permainan Rusak - text: "Gagal memuat data simpanan Anda:" + text: "Gagal memuat data simpanan kamu:" confirmSavegameDelete: title: Konfirmasi Penghapusan - text: Are you sure you want to delete the following game?

- '' at level

This can not be - undone! + text: Apakah kamu yakin ingin menghapus game berikut?

'' + pada level

Hal ini tak dapat diulang! savegameDeletionError: title: Gagal Menghapus text: "Gagal untuk menghapus data simpanan:" restartRequired: - title: Diperlukan untuk Memulai Kembali - text: Anda harus memulai kembali permainan untuk menerapkan pengaturan. + title: Diperlukan untuk Restart + text: kamu harus memulai kembali permainan untuk menerapkan pengaturan. editKeybinding: - title: Ganti Tombol Pintas - desc: Tekan tombol pada papan ketik atau tetikus yang ingin anda tetapkan, atau + title: Ganti Tombol Pintas (Keybinding) + desc: Tekan tombol pada keyboard atau mouse yang ingin kamu ganti, atau tekan escape untuk membatalkan. resetKeybindingsConfirmation: - title: Setel Ulang Tombol-tombol Pintas + title: Setel Ulang Tombol-tombol Pintas (Keybinding) desc: Ini akan menyetel ulang semua tombol pintas kepada pengaturan awalnya. Harap konfirmasi. keybindingsResetOk: @@ -144,87 +140,95 @@ dialogs: desc: Tombol-tombol pintas sudah disetel ulang ke pengaturan awalnya! featureRestriction: title: Versi Demo - desc: Anda mencoba untuk mengakses fitur () yang tidak tersedia pada - versi demo. Pertimbangkan untuk mendapatkan versi penuh untuk + desc: Kamu mencoba untuk mengakses fitur () yang tidak tersedia pada + versi demo. Pertimbangkan untuk mendapatkan versi lengkap untuk pengalaman sepenuhnya! oneSavegameLimit: title: Penyimpanan Permainan Terbatas - desc: Anda hanya dapat memiliki satu simpanan permainan dalam versi demo. Harap - hapus yang telah ada atau dapatkan versi penuh! + desc: Kamu hanya dapat memiliki satu data simpanan dalam versi demo. Harap + hapus yang telah ada atau dapatkan versi lengkap! updateSummary: - title: Pembaruan Baru! - desc: "Berikut perubahan-perubahan yang telah dibuat sejak Anda main terakhir + title: Update Baru! + desc: "Berikut perubahan-perubahan yang telah dibuat sejak kamu main terakhir kali:" upgradesIntroduction: title: Buka Tingkatan-tingkatan - desc: Semua bentuk yang anda produksi dapat digunakan untuk membuka tingkatan - baru - Jangan hancurkan pabrik-pabrik lama Anda! - Tab tingkatan dapat ditemukan di sudut atas kanan layar Anda. + desc: Semua bentuk yang kamu produksi dapat digunakan untuk membuka tingkatan + baru - Jangan hancurkan pabrik-pabrik lama kamu! + Tab tingkatan dapat ditemukan di sudut kanan atas layar kamu. massDeleteConfirm: title: Konfirmasi Penghapusan - desc: Anda akan menghapus banyak bangunan (tepatnya )! Apakah Anda yakin + desc: Kamu akan menghapus banyak bangunan (tepatnya )! Apakah kamu yakin untuk melakukannya? massCutConfirm: - title: Pastikan Pemindahan - desc: Anda akan memindahkan banyak bangunan (tepatnya )! Apakah Anda + title: Konfirmasi Pemindahan (Cut) + desc: Kamu akan memindahkan (cut) banyak bangunan (tepatnya )! Apakah kamu yakin untuk melakukannya? massCutInsufficientConfirm: title: Tidak Mampu Memindahkan - desc: Anda tidak mampu menanggung biaya pemindahan area ini! Apakah Anda yakin + desc: Kamu tidak mampu menanggung biaya pemindahan area ini! Apakah kamu yakin untuk memindahkannya? blueprintsNotUnlocked: title: Belum Terbuka - desc: Selesaikan level 12 untuk membuka cetak biru! + desc: Selesaikan level 12 untuk membuka Cetak Biru! keybindingsIntroduction: - title: Tombol Pintas Berguna + title: Tombol Pintas (Keybindings) Berguna desc: "Permainan ini memiliki banyak tombol pintas yang membuatnya lebih mudah untuk membangun pabrik-pabrik besar. Berikut adalah beberapa, namun - pastikan Anda perhatikan tombol-tombol + pastikan kamu perhatikan tombol-tombol pintasnya!

CTRL + Tarik: Pilih sebuah area.
SHIFT: - Tahan untuk meletakkan beberapa kali bangunan yang.
ALT: Ganti orientasi sabuk konveyor yang telah diletakkan.
" createMarker: title: Penanda Baru titleEdit: Sunting Penanda - desc: Give it a meaningful name, you can also include a short - key of a shape (Which you can generate here) + desc: Berikan nama yang berguna, kamu juga bisa memasukkan short key + dari sebuah bentuk (Yang bisa kamu buat sendiri + disini) markerDemoLimit: - desc: Anda hanya dapat memuat dua penanda pada versi demo. Dapatkan versi penuh - untuk penanda-penanda tak terhingga! + desc: Kamu hanya dapat membuat dua penanda pada versi demo. Dapatkan versi + lengkap untuk penanda-penanda tak terhingga! exportScreenshotWarning: - title: Ekspor Tangkapan Layar - desc: Anda meminta untuk mengekspor pangkalan pusat Anda sebagai tangkapan - layar. Harap ketahui bahwa ini bisa menjadi lambat untuk pangkalan - pusat yang besar dan bahkan dapat membuat permainan Anda mogok! + title: Ekspor Screenshot + desc: Kamu meminta untuk mengekspor pabrikmu sebagai screenshot. + Harap ketahui bahwa ini bisa menjadi lambat untuk pabrik + yang besar dan bahkan dapat membuat permainanmu berhenti! editSignal: - title: Set Signal - descItems: "Choose a pre-defined item:" - descShortKey: ... or enter the short key of a shape (Which you - can generate here) + title: Atur Tanda + descItems: "Pilih item yang telah ditentukan sebelumnya:" + descShortKey: ... atau masukkan shortkey dari bentuk (Yang + bisa Kamu buat sendiri disini) renameSavegame: - title: Rename Savegame - desc: You can rename your savegame here. + title: Ganti Nama Data Simpanan + desc: Kamu bisa mengganti nama data simpanan di sini. + tutorialVideoAvailable: + title: Tutorial Tersedia + desc: Ada video tutorial yang tersedia untuk level ini! Apakah kamu ingin menontonnya? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Tersedia + desc: Ada video tutorial yang tersedia untuk level ini, tetapi hanya dalam Bahasa Inggris. + Apakaha kamu ingin menontonnya? ingame: keybindingsOverlay: - moveMap: Pindahkan + moveMap: Geser selectBuildings: Pilih area stopPlacement: Hentikan peletakan rotateBuilding: Putar bangunan placeMultiple: Letakkan beberapa - reverseOrientation: Balik orientasi + reverseOrientation: Balikkan orientasi disableAutoOrientation: Nonaktifkan orientasi otomatis. toggleHud: Ganti HUD placeBuilding: Letakan bangunan - createMarker: Ciptakan penanda + createMarker: Buat penanda delete: Hapus - pasteLastBlueprint: Sisipkan cetak biru terakhir + pasteLastBlueprint: Tempel (paste) cetak biru terakhir lockBeltDirection: Aktifkan perencana sabuk konveyor - plannerSwitchSide: Balik sisi perencana - cutSelection: Pindahkan - copySelection: Gandakan - clearSelection: Hapus seleksi + plannerSwitchSide: Balikkan sisi perencana + cutSelection: Pindahkan (Cut) + copySelection: Salin (Copy) + clearSelection: Hapus pilihan pipette: Pipet switchLayers: Ganti lapisan colors: @@ -242,46 +246,44 @@ ingame: hotkeyLabel: "Hotkey: " infoTexts: speed: Kecepatan - range: Rentang + range: Jangkauan storage: Penyimpanan - oneItemPerSecond: satu artikel / detik - itemsPerSecond: artikel / detik + oneItemPerSecond: 1 item/dtk + itemsPerSecond: item/dtk itemsPerSecondDouble: (x2) tiles: ubin levelCompleteNotification: levelTitle: Level completed: Selesai - unlockText: Membuka ! + unlockText: terbuka! buttonNextLevel: Level Selanjutnya notifications: newUpgrade: Tingkatan baru tersedia! - gameSaved: Permainan Anda telah disimpan. - freeplayLevelComplete: Level has been completed! + gameSaved: Permainan kamu telah disimpan. + freeplayLevelComplete: Level telah selesai! shop: title: Tingkatan-tingkatan buttonUnlock: Tingkatkan tier: Tingkat maximumLevel: LEVEL MAKSIMUM (Kecepatan x) statistics: - title: Statistika + title: Statistik dataSources: stored: title: Tersimpan - description: Menunjukan jumlah bentuk-bentuk yang tersimpan pada bangunan pusat - Anda. + description: Menunjukan semua bentuk yang tersimpan pada bangunan pusatmu. produced: title: Terproduksi - description: Menunjukkan semua bentuk yang diproduksi seluruh pabrik Anda, + description: Menunjukkan semua bentuk yang diproduksi pabrikmu, termasuk produk-produk antara. delivered: title: Terkirim - description: Menunjukkan bentuk-bentuk yang telah terkirim ke bangunan pusat - Anda. + description: Menunjukkan bentuk-bentuk yang sedang dikirim ke bangunan pusatmu. noShapesProduced: Sejauh ini belum diproduksi. shapesDisplayUnits: - second: / s - minute: / m - hour: / h + second: /dtk + minute: /m + hour: /j settingsMenu: playtime: Waktu bermain buildingsPlaced: Bangunan @@ -295,66 +297,88 @@ ingame: waypoints: waypoints: Penanda hub: PUSAT - description: Klik tombol kiri tetikus pada penanda untuk melompat kepadanya, - klik tombol kanan untuk menghapusnya.

Tekan - untuk membuat penanda dari sudut pandang saat ini, atau klik + description: Klik tombol kiri mouse pada penanda untuk melompat ke penanda, klik + tombol kanan untuk menghapusnya.

Tekan untuk + membuat penanda dari sudut pandang saat ini, atau klik tombol kanan untuk membuat penanda pada lokasi yang dipilih. creationSuccessNotification: Penanda telah dibuat. shapeViewer: title: Lapisan-lapisan empty: Kosong - copyKey: Gandakan tombol + copyKey: Tombol Salin (Copy) interactiveTutorial: - title: Penuntun + title: Tutorial hints: 1_1_extractor: Letakkan ekstraktor diatas bentuk lingkaran untuk mengekstrak bentuk tersebut! 1_2_conveyor: "Hubungkan ekstraktor dengan sabuk konveyor ke - pusat pangkalan Anda!

Kiat: Klik dan - seret sabuk konveyor dengan tetikus!" + bangunan pusatmu!

Tip: Klik dan + seret sabuk konveyor dengan mouse!" 1_3_expand: "Ini BUKAN permainan menganggur! Bangun lebih banyak ekstraktor dan sabuk konveyor untuk menyelesaikan - obyektif dengan lebih cepat.

Kiat: Tahan - tombolSHIFT untuk meletakkan beberapa - ekstraktor, dan gunakan tombol R untuk - memutar." + objektif dengan lebih cepat.

Tip: Tahan tombol + SHIFT untuk meletakkan beberapa ekstraktor sekaligus, dan + gunakan tombol R untuk memutar." + 2_1_place_cutter: "Sekarang letakkan Pemotong untuk memotong lingkaran + menjadi 2 bagian!

NB: Pemotong akan selalu memotong dari atas ke + bawah apapun orientasinya." + 2_2_place_trash: Pemotong dapat tersumbat dan macet!

Gunakan + tong sampah untuk membuang sisa (!) yang saat ini tidak diperlukan. + 2_3_more_cutters: "Kerja yang bagus! Sekarang letakkan 2 pemotong lagi untuk mempercepat + proses ini!

NB: Gunakan tombol 0-9 + untuk mengakses bangunan lebih cepat!" + 3_1_rectangles: "Sekarang ekstrak beberapa persegi! Bangun 4 + ekstraktor dan hubungkan mereka ke bangunan pusat.

NB: + Tahan SHIFT saat meletakkan konveyor untuk mengaktifkan + perencana sabuk konveyor!" + 21_1_place_quad_painter: Letakkan pemotong empat bagian dan ekstrak beberapa + lingkaran, warna putih dan + merah! + 21_2_switch_to_wires: Pindah ke lapisan kabel dengan menekan tombol + E!

Lalu hubungkan keempat + input dari pengecat dengan menggunakan kabel! + 21_3_place_button: Mantap! Sekarang letakkan saklar dan hubungkan + dengan menggunakan kabel! + 21_4_press_button: "Tekan saklar untuk memancarkan sinyal yang + benar dan mengaktifkan pengecat.

NB: Kamu + tidak perlu menghubungkan semua input! Cobalah hanya menghubungkan dua." connectedMiners: - one_miner: 1 Miner - n_miners: Miners - limited_items: Limited to + one_miner: 1 Ekstraktor + n_miners: Ekstraktor + limited_items: Terbatas hingga watermark: - title: Demo version - desc: Click here to see the Steam version advantages! - get_on_steam: Get on steam + title: Versi Demo + desc: Klik disini untuk melihat keunggulan pada versi Steam! + get_on_steam: Dapatkan di Steam standaloneAdvantages: - title: Get the full version! - no_thanks: No, thanks! + title: Dapatkan versi lengkap! + no_thanks: Tidak, terima kasih! points: levels: - title: 12 New Levels - desc: For a total of 26 levels! + title: 12 Level Baru + desc: Dengan total 26 level! buildings: - title: 18 New Buildings - desc: Fully automate your factory! + title: 18 Bangunan Baru + desc: Untuk membuat pabrik yang otomatis sepenuhnya! savegames: - title: ∞ Savegames - desc: As many as your heart desires! + title: ∞ Data Simpanan + desc: Sebanyak yang kamu mau! upgrades: - title: 20 Upgrade Tiers - desc: This demo version has only 5! + title: 20 Tingkatan Upgrade + desc: Versi demo ini hanya punya 5! markers: - title: ∞ Markers - desc: Never get lost in your factory! + title: ∞ Penanda + desc: Kamu tidak akan tersesat di pabrikmu sendiri! wires: - title: Wires - desc: An entirely new dimension! + title: Kabel + desc: Sebuah dimensi yang benar-benar berbeda! darkmode: - title: Dark Mode - desc: Stop hurting your eyes! + title: Mode Gelap + desc: Berhenti merusak matamu! support: - title: Support me - desc: I develop it in my spare time! + title: Dukung saya + desc: Saya membuat game ini di waktu luang! shopUpgrades: belt: name: Sabuk konveyor, Pembagi Arus & Terowongan @@ -363,30 +387,30 @@ shopUpgrades: name: Ekstraksi description: Kecepatan x → x processors: - name: Memotong, Memutar & Menyusun - description: Speed x → x + name: Memotong, Memutar & Menumpuk + description: Kecepatan x → x painting: - name: Mencampur & Mencat + name: Mencampur & Mengecat description: Kecepatan x → x buildings: hub: deliver: Kirim toUnlock: untuk membuka levelShortcut: LVL - endOfDemo: End of Demo + endOfDemo: Akhir dari Demo belt: default: name: Sabuk Konveyor - description: Mengangkut artikel-artikel, tahan dan seret untuk meletakkan - beberapa. + description: Mengangkut sumber daya, tahan dan seret untuk meletakkan beberapa sekaligus. wire: default: name: Kabel - description: Memungkinkan anda untuk mengangkut Energi. + description: Mentransfer sinyal, dapat berupa bentuk, warna, atau boolean (1 + atau 0). Kabel dengan warna berbeda tidak akan menyambung. second: name: Kabel - description: Mentransfer sinyal, dapat berupa bentuk, warna, atau boolean (1 / - 0). Kabel dengan warna berbeda tidak akan menyambung. + description: Mentransfer sinyal, dapat berupa bentuk, warna, atau boolean (1 + atau 0). Kabel dengan warna berbeda tidak akan menyambung. miner: default: name: Ekstraktor @@ -399,24 +423,24 @@ buildings: underground_belt: default: name: Terowongan - description: Memungkinkan Anda untuk mengangkut sumber-sumber daya dibawah + description: Memungkinkan kamu untuk mengangkut sumber-sumber daya dibawah bangunan-bangunan atau sabuk konveyor. tier2: name: Terowongan Tingkat II - description: Memungkinkan Anda untuk mengangkut sumber-sumber daya dibawah + description: Memungkinkan kamu untuk mengangkut sumber-sumber daya dibawah bangunan-bangunan atau sabuk konveyor. cutter: default: name: Pemotong description: Memotong bentuk-bentuk secara vertikal dan mengeluarkan kedua - bagian. Apabila Anda hanya menggunakan satu bagian, - pastikan Anda lenyapkan bagian lain atau mesin akan + bagian. Apabila kamu hanya menggunakan satu bagian, + pastikan kamu lenyapkan bagian lain atau mesin akan tersumbat macet! quad: name: Pemotong (Empat Bagian) - description: Memotong bentuk-bentuk menjadi empat bagian. Apabila Anda - hanya menggunakan satu bagian, pastikan Anda lenyapkan - bagian-bagian lain atau mesin akan macet! + description: Memotong bentuk-bentuk menjadi empat bagian. Apabila kamu + hanya menggunakan satu bagian, pastikan kamu lenyapkan + bagian-bagian lain atau mesin akan tersumbat dan macet! rotater: default: name: Pemutar @@ -425,74 +449,76 @@ buildings: name: Pemutar (Berlawanan Arah Jarum Jam) description: Memutar bentuk berlawanan arah jarum jam sebesar 90 derajat. rotate180: - name: Pemutar (180) + name: Pemutar (180 derajat) description: Memutar bentuk searah jarum jam sebesar 180 derajat. stacker: default: name: Penumpuk - description: Menumpukkan kedua bentuk. Apabila mereka tidak dapat digabungkan, + description: Menggabungkan kedua input. Apabila mereka tidak dapat digabungkan, bentuk kanan akan diletakkan diatas bentuk kiri. mixer: default: name: Pencampur Warna - description: Mencampurkan dua warna menggunakan campuran aditif. + description: Mencampurkan dua warna. painter: default: - name: Pencat - description: Mencat keseluruhan bentuk dari input kiri dengan warna dari input + name: Pengecat + description: Mengecat keseluruhan bentuk dari input kiri dengan warna dari input atas. mirrored: - name: Pencat - description: Mencat keseluruhan bentuk dari input kiri dengan warna dari input - atas. + name: Pengecat + description: Mengecat keseluruhan bentuk dari input kiri dengan warna dari input + bawah. double: - name: Pencat (Ganda) - description: Mencat bentuk-bentuk dari input kiri dengan warna dari input atas. + name: Pengecat (Ganda) + description: Mengecat bentuk-bentuk dari input kiri dengan warna dari input + atas. quad: - name: Pencat (Empat Bagian) - description: Allows you to color each quadrant of the shape individually. Only - slots with a truthy signal on the wires layer - will be painted! + name: Pengecat (Empat Bagian) + description: Memungkinkan kamu untuk mengecat tiap kuadrannya masing - masing + pada bentuk. Hanya menyambung dengan sinyal yang + benar pada lapisan kabel yang akan dicat! trash: default: name: Tong Sampah - description: Menerima input dari semua sisi dan menghancurkannya. Selamanya. + description: Menerima input dari segala sisi dan menghancurkannya. Selamanya. balancer: default: - name: Pengimbang + name: Penyeimbang description: Multifungsional - Mendistribusikan seluruh input secara merata ke seluruh output. merger: - name: Penggabung (Kompak) + name: Penggabung Kompak description: Menggabungkan dua sabuk konveyor menjadi satu. merger-inverse: - name: Penggabung (Kompak) + name: Penggabung Kompak description: Menggabungkan dua sabuk konveyor menjadi satu. splitter: - name: Pemisah (Kompak) + name: Pemisah Kompak description: Memisahkan satu sabuk konveyor menjadi dua. splitter-inverse: - name: Pemisah (Kompak) + name: Pemisah Kompak description: Memisahkan satu sabuk konveyor menjadi dua. storage: default: name: Tempat Penyimpanan - description: Menyumpan bentuk yang berlebuhan, hingga kapasitas yang tertentu. - Memprioritaskan output dari kiri + description: Menyimpan bentuk yang berlebihan, hingga kapasitas tertentu. + Memprioritaskan output dari kiri dan dapat digunakan sebagai gerbang luapan. wire_tunnel: default: - name: Penyebrangan Kabel + name: Terowongan Kabel description: Memungkinkan untuk menyebrangkan 2 kabel tanpa menyambungkannya. constant_signal: default: name: Sinyal Konstan - description: Mengeluarkan sinyal yang konstan, dapat berupa bentuk, warna atau - boolean (1 / 0). + description: Memancarkan sinyal yang konstan, dapat berupa bentuk, warna atau + boolean (1 atau 0). lever: default: name: Saklar - description: Dapat diubah untuk mengeluarkan sinyal boolean (1 / 0) pada lapisan - kabel, yang bisa digunakan untuk mengontrol seperti penyaring. + description: Dapat digunakan untuk mengeluarkan sinyal boolean (1 atau 0) pada + lapisan kabel, yang bisa digunakan untuk mengontrol komponen, seperti + filter item. logic_gate: default: name: Gerbang AND @@ -504,7 +530,7 @@ buildings: berarti sebuah bentuk, warna atau boolean "1") xor: name: Gerbang XOR - description: Mengeluarkan boolean "1" jika kedua input adalah benar, namun bukan + description: Mengeluarkan boolean "1" jika salah satu input adalah benar, namun bukan keduanya. (Benar berarti sebuah bentuk, warna atau boolean "1") or: name: Gerbang OR @@ -524,11 +550,11 @@ buildings: name: Filter description: Hubungkan sebuah sinyal untuk merutekan semua benda yang cocok ke atas dan sisanya ke kanan. Dapat juga dikontrol dengan sinyal - boolean + boolean. display: default: name: Layar - description: Hubungkan dengan sebuah sinyal untuk ditunjukkan pada layar - Dapat + description: Hubungkan sebuah sinyal untuk ditunjukkan pada layar - Dapat berupa bentuk, warna atau boolean. reader: default: @@ -539,35 +565,34 @@ buildings: analyzer: default: name: Penganalisa bentuk - description: Menganalisa perempat bentuk pada kanan atas dan lapisan terbawah + description: Menganalisa bentuk bagian kanan atas pada lapisan paling bawah lalu mengeluarkan bentuk dan warnanya. comparator: default: name: Pembanding - description: Mengeluarkan boolean "1" jika kedua sinya adalah sama. Dapat - membandingkan Bentuk, warna dan boolean. + description: Mengeluarkan boolean "1" jika kedua sinyalnya adalah sama. Dapat + membandingkan bentuk, warna dan boolean. virtual_processor: default: name: Pemotong Virtual - description: Memotong bentuk secara virtual menjadi dua bagian. + description: Memotong bentuk menjadi dua bagian secara virtual. rotater: name: Pemutar Virtual - description: Memutar bentuk secara virtual, searah jarum jam dan tidak searah - jarum jam. + description: Memutar bentuk searah jarum jam secara virtual. unstacker: name: Pemisah Tumpukan Virtual - description: Memisahkan lapisan teratas secara virtual ke output kanan dan - sisanya ke output kiri. + description: Memisahkan lapisan paling atas ke output kanan dan + sisanya ke output kiri secara virtual. stacker: name: Penumpuk Virtual description: Menumpuk bentuk kanan ke bentuk kiri secara virtual. painter: - name: Pencat Virtual - description: Mengecat bentuk dari input bawah dengan warna dari input kanan. + name: Pengecat Virtual + description: Mengecat bentuk dari input bawah dengan warna dari input kanan secara virtual. item_producer: default: - name: Pembuat Artikel - description: Hanya tersedia di dalam mode sandbox , Mengeluarkan sinyal yang + name: Pembuat Bentuk + description: Hanya tersedia di dalam mode sandbox, mengeluarkan sinyal yang diberikan dari lapisan kabel ke lapisan biasa. storyRewards: reward_cutter_and_trash: @@ -575,183 +600,188 @@ storyRewards: desc: Pemotong telah dibuka, yang dapat memotong bentuk menjadi dua secara vertikal apapun orientasinya!

Pastikan untuk membuang sisanya, jika - tidak ini dapat menghambat dan memperlambat - - karena ini anda diberikan Tong sampah, yang - menghapus semua yang anda masukkan! + tidak ini dapat tersumbat dan macet - + Oleh karena itu kamu diberikan tong sampah, yang + menghapus semua yang kamu masukkan! reward_rotater: title: Memutar desc: Pemutar telah dibuka! Ia memutar bentuk-bentuk searah jarum jam sebesar 90 derajat. reward_painter: - title: Pengecatan - desc: "Pencat telah dibuka – Ekstraksi beberapa warna (seperti - yang Anda lakukan dengan bentuk) dan kemudian kombinasikan dengan - bentuk di dalam pencat untuk mewarnai mereka!

Catatan: - Apabila Anda buta warna, terdapat mode buta warna - di dalam pengaturan!" + title: Mengecat + desc: "Pengecat telah dibuka – Ekstrak beberapa warna + (seperti yang kamu lakukan dengan bentuk) dan kemudian kombinasikan + dengan bentuk di dalam pengecat untuk mewarnai mereka!

+ NB: Apabila kamu buta warna, terdapat mode buta + warna di dalam pengaturan!" reward_mixer: - title: Pencampuran Warna - desc: Pencampur telah dibuka – Kombinasikan dua warna - menggunakan pencampuran aditif dengan bangunan ini! + title: Mencampur Warna + desc: Pencampur Warna telah dibuka – Ia mencampur dua warna menjadi satu! reward_stacker: - title: Penyusun - desc: Anda sekarang dapat mengombinasikan bentuk-bentuk dengan - penyusun! Kedua input akan dikombinasikan, dan + title: Penumpuk + desc: Kamu sekarang dapat mengombinasikan bentuk-bentuk dengan + penumpuk! Kedua input akan dikombinasikan, dan apabila mereka dapat diletakan disebelah satu sama lain, mereka - akan terpadukan. Apabila tidak dapat, input kanan + akan terpadukan. Apabila tidak bisa, maka input kanan akan diletakkan diatas input kiri! reward_splitter: - title: Pembagi/Penggabung - desc: You have unlocked a splitter variant of the - balancer - It accepts one input and splits them - into two! + title: Pembagi Sederhana + desc: Kamu telah membuka varian pembagi dari + penyeimbang - Menerima satu input dan membaginya + menjadi dua! reward_tunnel: title: Terowongan - desc: Terowongan telah dibuka – Sekarang Anda dapat memindahkan - artikel-artikel melalui terowongan di bawah sabuk-sabuk konveyor dan + desc: Terowongan telah dibuka – Sekarang kamu dapat memindahkan + bentuk-bentuk melalui terowongan di bawah sabuk-sabuk konveyor dan bangungan-bangunan dengannya! reward_rotater_ccw: title: Memutar Berlawanan Arah Jarum Jam - desc: Anda telah membuka varian dari Pemutar - Ia memungkinkan - Anda untuk memutar bentuk-bentuk berlawanan arah jarum jam! Untuk + desc: Kamu telah membuka varian dari Pemutar - Bangunan ini memungkinkan + kamu untuk memutar bentuk-bentuk berlawanan arah jarum jam! Untuk membangunnya, pilih pemutar dan tekan 'T' to memilih varian! reward_miner_chainable: - title: Merantai Ekstraktor - desc: "You have unlocked the chained extractor! It can - forward its resources to other extractors so you - can more efficiently extract resources!

PS: The old - extractor has been replaced in your toolbar now!" + title: Ekstraktor Merantai + desc: "Kamu telah membuka Ekstraktor (Berantai)! Bangunan ini dapat + mengoper sumber daya ke ekstraktor depannya + sehingga kamu dapat mengekstrak sumber daya dengan lebih + efisien!

NB: Ekstraktor yang lama sudah diganti pada toolbar + kamu sekarang!" reward_underground_belt_tier_2: title: Terowongan Tingkat II - desc: Anda telah membuka varian baru terowongan - Ia memiliki - jangkauan yang lebih panjang, dan sekarang Anda + desc: Kamu telah membuka varian baru terowongan - Bangunan ini memiliki + jangkauan yang lebih panjang, dan sekarang kamu juga dapat memadukan terowongan-terowongan tersebut! reward_cutter_quad: title: Pemotongan Empat Bagian - desc: Anda telah membuka varian dari pemotong - Ia memungkinkan - Anda memotong bentuk-bentuk ke dalam empat bagian + desc: Kamu telah membuka varian dari pemotong - Bangunan ini memungkinkan + kamu untuk memotong bentuk-bentuk menjadi empat bagian daripada hanya dua bagian! reward_painter_double: title: Pengecatan Ganda - desc: Anda telah membuka varian dari pencat - Ia bekerja - seperti pencat biasa namun dapat memproses dua bentuk - sekaligus mengonsumsi hanya satu warna daripada dua! + desc: Kamu telah membuka varian dari pengecat - Bangunan ini bekerja + seperti pengecat biasa namun dapat memproses dua bentuk + sekaligus, dan mengonsumsi hanya satu warna daripada dua! reward_storage: - title: Penyangga Penyimpanan - desc: You have unlocked the storage building - It allows you to - store items up to a given capacity!

It priorities the left - output, so you can also use it as an overflow gate! + title: Tempat Penyimpanan + desc: Kamu telah membuka Tempat Penyimpanan - Bangunan ini memungkinkan + kamu untuk menyimpan item hingga kapasitas tertentu!

Bangunan ini + mengutamakan output kiri, sehingga kamu dapat menggunakannya sebagai + gerbang luapan (overflow gate)! reward_freeplay: title: Permainan Bebas - desc: You did it! You unlocked the free-play mode! This means - that shapes are now randomly generated!

- Since the hub will require a throughput from now - on, I highly recommend to build a machine which automatically - delivers the requested shape!

The HUB outputs the requested - shape on the wires layer, so all you have to do is to analyze it and - automatically configure your factory based on that. + desc: Kamu berhasil! Kamu telah membuka mode permainan bebas! + Ini artinya bentuk-bentuk akan dibuat secara + acak!

Karena bangunan pusat akan + membutuhkan penghasilan dari sekarang, Saya sangat + menyarankan untuk membangun mesin yang secara otomatis mengirim + bentuk yang diminta!

Bangunan pusat mengeluarkan bentuk + yang diminta pada lapisan kabel, jadi yang harus kamu lakukan adalah + menganalisa dan membangun pabrik secara otomatis berdasarkan itu. reward_blueprints: title: Cetak Biru - desc: Anda sekarang dapat menyalin dan meletakkan bagian dari - pabrik Anda! Pilih sebuah area (tahan CTRL, lalu seret dengan - tetikus), dan tekan 'C' untuk menggandakannya.

Untuk - meletakannya tidak gratis, Anda harus memproduksi + desc: Kamu sekarang dapat menyalin (copy) dan menempel (paste) bagian dari + pabrikmu! Pilih sebuah area (tahan CTRL, lalu seret dengan + mouse), dan tekan 'C' untuk menyalinnya.

Untuk + menempelnya tidak gratis, Kamu harus memproduksi bentuk cetak biru untuk dapat melakukannya! (Bentuk - yang baru saja anda kirim). + yang baru saja kamu kirim). no_reward: title: Level Selanjutnya desc: "Level ini tidak memiliki hadiah, namun yang selanjutnya akan!

- Catatan: Sebaiknya Anda jangan hancurkan pabrik yang telah ada – - Anda membutuhkan semua bentuk-bentuk tersebut lagi + NB: Sebaiknya kamu jangan hancurkan pabrik yang telah ada – + Kamu akan membutuhkan semua bentuk-bentuk tersebut lagi nanti untuk membuka tingkatan-tingkatan selanjutnya!" no_reward_freeplay: title: Level Selanjutnya desc: Selamat! Omong-omong, lebih banyak konten telah direncanakan untuk versi - penuh! + lengkap! reward_balancer: - title: Balancer - desc: The multifunctional balancer has been unlocked - It can - be used to build bigger factories by splitting and merging - items onto multiple belts! + title: Penyeimbang + desc: Penyeimbang multifungsional telah terbuka - Bangunan ini dapat + digunakan untuk membuat pabrik yang lebih besar lagi dengan memisahkan + dan menggabungkan item ke beberapa sabuk konveyor! reward_merger: - title: Compact Merger - desc: You have unlocked a merger variant of the - balancer - It accepts two inputs and merges them - into one belt! + title: Penggabung Sederhana + desc: Kamu telah membuka varianpenggabung dari + penyeimbang - Bangunan ini menerima dua input dan + menggabungkannya dalam satu sabuk konveyor! reward_belt_reader: - title: Belt reader - desc: You have now unlocked the belt reader! It allows you to - measure the throughput of a belt.

And wait until you unlock - wires - then it gets really useful! + title: Pembaca Sabuk Konveyor + desc: Kamu telah membuka pembaca sabuk konveyor! Bangunan ini + memungkinkan kamu untuk mengukur penghasilan dalam sebuah sabuk + konveyor.

Dan tunggu sampai kamu membuka kabel - maka bangunan ini + akan sangat berguna! reward_rotater_180: - title: Rotater (180 degrees) - desc: You just unlocked the 180 degress rotater! - It allows - you to rotate a shape by 180 degress (Surprise! :D) + title: Pemutar (180 derajat) + desc: Kamu telah membuka pemutar 180 derajat! - Bangunan ini + memungkinkan kamu untuk memutar bentuk dalam 180 derajat (Kejutan! + :D) reward_display: - title: Display - desc: "You have unlocked the Display - Connect a signal on the - wires layer to visualize it!

PS: Did you notice the belt - reader and storage output their last read item? Try showing it on a - display!" + title: Layar + desc: "Kamu baru saja membuka Layar - Hubungkan sebuah sinyal + dalam lapisan kabel untuk memvisualisasikannya!

NB: Apakah + kamu memperhatikan pembaca sabuk dan penyimpanan mengeluarkan item + bacaan terakhir? Coba tampilkan pada layar!" reward_constant_signal: - title: Constant Signal - desc: You unlocked the constant signal building on the wires - layer! This is useful to connect it to item filters - for example.

The constant signal can emit a - shape, color or - boolean (1 / 0). + title: Sinyal Konstan + desc: Kamu telah membuka bangunan sinyal konstan pada lapisan + kabel! Bangunan ini berguna untuk menyambungkannya ke filter item + contohnya.

Sinyal konstannya dapat memancarkan + bentuk, warna atau + boolean (1 atau 0). reward_logic_gates: - title: Logic Gates - desc: You unlocked logic gates! You don't have to be excited - about this, but it's actually super cool!

With those gates - you can now compute AND, OR, XOR and NOT operations.

As a - bonus on top I also just gave you a transistor! + title: Gerbang Logis + desc: Kamu telah membuka gerbang logis! Kamu tidak perlu bersemangat + tentang ini, tetapi sebenarnya ini sangat keren!

Dengan gerbang-gerbang tersebut + kamu sekarang dapat mengkalkulasi operasi AND, OR, XOR dan NOT.

Sebagai bonus + kamu juga telah mendapatkan transistor! reward_virtual_processing: - title: Virtual Processing - desc: I just gave a whole bunch of new buildings which allow you to - simulate the processing of shapes!

You can - now simulate a cutter, rotater, stacker and more on the wires layer! - With this you now have three options to continue the game:

- - Build an automated machine to create any possible - shape requested by the HUB (I recommend to try it!).

- Build - something cool with wires.

- Continue to play - regulary.

Whatever you choose, remember to have fun! + title: Prosesi Virtual + desc: Kamu baru saja mendapatkan banyak bangunan yang memungkinkan kamu untuk + menstimulasi prosesi pembuatan bentuk!

Kamu sekarang + dapat menstimulasi pemotongan, pemutaran, penumpukan dan masih banyak lagi pada lapisan kabel! + Dengan ini kamu sekarang memiliki tiga opsi untuk melanjutkan permainan:

- + Membuat sebuah mesin otomatis untuk membuat segala bentuk + yang diminta oleh PUSAT (Saya sarankan kamu untuk mencobanya!).

- Membuat + sesuatu yang keren dengan kabel.

- Melanjutkan permainan seperti + biasa.

Apapun yang kamu pilih, ingatlah untuk bersenang-senang! reward_wires_painter_and_levers: - title: Wires & Quad Painter - desc: "You just unlocked the Wires Layer: It is a separate - layer on top of the regular layer and introduces a lot of new - mechanics!

For the beginning I unlocked you the Quad - Painter - Connect the slots you would like to paint with on - the wires layer!

To switch to the wires layer, press - E." + title: Kabel & Pengecat (Empat Bagian) + desc: "Kamu baru saja membuka Lapisan Kabel: Ini adalah sebuah + lapisan terpisah diatas lapisan biasa dan memperkenalkan banyak mekanisme + baru!

Untuk permulaan kamu telah membuka Pengecat (Empat + Bagian) - Hubungkan slot yang ingin kamu cat pada + lapisan kabel!

Untuk mengubah ke lapisan kabel, tekan tombol + E.

NB: Nyalakan petunjuk di + pengaturan untuk mengaktifkan tutorial kabel!" reward_filter: - title: Item Filter - desc: You unlocked the Item Filter! It will route items either - to the top or the right output depending on whether they match the - signal from the wires layer or not.

You can also pass in a - boolean signal (1 / 0) to entirely activate or disable it. + title: Filter Item + desc: Kamu telah membuka Filter! Bangunan ini akan mengarahkan item baik + ke output atas atau output kanan tergantung apakah mereka cocok dengan + sinyal dari lapisan kabel atau tidak.

Kamu juga bisa memasukkan + sinyal boolean (1 atau 0) untuk mengaktifkan atau menonaktifkannya. reward_demo_end: - title: End of Demo - desc: You have reached the end of the demo version! + title: Akhir dari Demo + desc: Kamu telah mencapai akhir dari versi demo! settings: title: Pengaturan categories: general: Umum userInterface: Antarmuka Pengguna - advanced: Tingkat Tinggi - performance: Performance + advanced: Terdepan + performance: Performa versionBadges: dev: Pengembangan - staging: Pementasan + staging: Tahapan prod: Produksi buildDate: Dibangun labels: uiScale: - title: Skala Antarmuka + title: Skala Antarmuka (User Interface) description: Ganti ukuran antarmuka pengguna. Antarmuka tetap akan berskalakan - berdasar resolusi peralatan Anda, tetapi pengaturan ini + berdasar resolusi perangkatmu, tetapi pengaturan ini mengontrol besar skala. scales: super_small: Sangat kecil @@ -761,8 +791,8 @@ settings: huge: Sangat besar autosaveInterval: title: Jeda Penyimpanan Otomatis - description: Mengatur seberapa sering permainan menyimpan secara otomatis. Anda - juga dapat menonaktifkannya sama sekali disini. + description: Mengatur seberapa sering permainan menyimpan secara otomatis. Kamu + juga dapat menonaktifkannya secara total disini. intervals: one_minute: 1 Menit two_minutes: 2 Menit @@ -771,9 +801,9 @@ settings: twenty_minutes: 20 Menit disabled: Dinonaktifkan scrollWheelSensitivity: - title: Kepekaan perbesaran - description: Mengubah seberapa peka perbesaran yang dilakukan (baik dengan roda - tetikus atau trackpad). + title: Kepekaan Zoom + description: Mengubah seberapa peka zoom yang dilakukan (baik dengan roda + mouse atau trackpad). sensitivity: super_slow: Sangat lambat slow: Lambat @@ -782,8 +812,7 @@ settings: super_fast: Sangat cepat movementSpeed: title: Kecepatan gerakan - description: Mengubah seberapa cepat pandangan bergerak ketika menggunakan papan - ketik. + description: Mengubah seberapa cepat pandangan bergerak ketika menggunakan keyboard atau mouse. speeds: super_slow: Sangat lambat slow: Lambat @@ -793,16 +822,16 @@ settings: extremely_fast: Luar biasa cepat language: title: Bahasa - description: Ganti bahasa. Semua terjemahan adalah contribusi pengguna dan + description: Ganti bahasa. Semua terjemahan adalah kontribusi pengguna dan mungkin saja tidak lengkap! enableColorBlindHelper: title: Mode buta warna - description: Mengaktifkan berbagai peralatan yang memungkinkan Anda bermain - apabila Anda buta warna. + description: Mengaktifkan berbagai peralatan yang memungkinkan kamu bermain + apabila kamu buta warna. fullscreen: title: Layar penuh description: Direkomendasikan untuk bermain dengan layar penuh untuk mendapatkan - pengalaman terbaik. Hanya tersedia dalam versi penuh. + pengalaman terbaik. Hanya tersedia dalam versi lengkap. soundsMuted: title: Bisukan suara description: Apabila diaktifkan, membisukan semua efek suara. @@ -816,96 +845,94 @@ settings: dark: Gelap light: Terang refreshRate: - title: Target Simulasi - description: Apabila Anda memiliki monitor 144hz, ganti laju penyegaran sehingga + title: Laju Penyegaran (Tick Rate) + description: Apabila kamu memiliki monitor 144hz, ganti laju penyegaran sehingga permainan dapat disimulasikan dengan benar pada laju yang lebih tinggi. Ini mungkin saja mengurangi laju bingkai per detik - (frames per second) apabila computer anda terlalu lambat. + (frames per second) apabila komputer kamu terlalu lambat. alwaysMultiplace: - title: Peletakkan berganda + title: Peletakkan Ganda description: Apabila diaktifkan, semua bangunan akan tetap terpilih setelah - penempatan sampai Anda membatalkannya. Ini sama saja dengan + penempatan sampai kamu membatalkannya. Ini sama saja dengan menahan tombol SHIFT secara permanen. offerHints: - title: Petunjuk & penuntun - description: Apakah akan menawarkan petunjuk dan penuntun ketika bermain. Juga + title: Petunjuk & Tutorial + description: Akan menawarkan petunjuk dan tutorial ketika bermain. Juga menyembunyikan elemen-elemen antarmuka pengguna (user interface) tertentu sampai level tertentu untuk membuat lebih mudah untuk bermain. enableTunnelSmartplace: - title: Terowongan cerdas + title: Terowongan Cerdas description: Ketika diaktifkan, proses penempatan terowongan akan menghapus konveyor yang tidak berguna secara otomatis. Ini juga - memungkinkan Anda untuk menyeret terowongan dan kelebihan + memungkinkan kamu untuk menyeret terowongan dan kelebihan terowongan akan dihilangkan. vignette: - title: Vinyet - description: Mengaktifkan vinyet, yang menggelapkan sudut-sudut layar dan + title: Vignette + description: Mengaktifkan vignette, yang menggelapkan sudut-sudut layar dan membuat teks lebih mudah dibaca. rotationByBuilding: title: Pemutaran masing-masing tipe bangunan - description: Setiap tipe bangunan mengingat putaran yang Anda tetapkan - kepadanya. Ini mungkin lebih nyaman apabila Anda sering berganti + description: Setiap tipe bangunan mengingat putaran atau rotasi yang kamu tetapkan + kepadanya. Ini mungkin lebih nyaman apabila kamu sering berganti untuk menempatkan berbagai tipe bangunan. compactBuildingInfo: - title: Pemadatan informasi banguna + title: Pemadatan Informasi Bangunan description: Memendekkan kotak-kotak informasi bangunan-bangunan dengan hanya menampilkan rasionya. Jika tidak, deskripsi dan gambar ditampilkan. disableCutDeleteWarnings: - title: Nonaktifkan peringatan pemindahan/penghapusan + title: Nonaktifkan Peringatan Pemindahan/Penghapusan description: Menonaktifkan peringatan yang muncul ketikan pemindahkan/menghapus lebih dari 100 entitas. soundVolume: - title: Sound Volume - description: Set the volume for sound effects + title: Volume Suara + description: Mengatur volume untuk efek suara musicVolume: - title: Music Volume - description: Set the volume for music + title: Volume Musik + description: Mengatur volume untuk musik lowQualityMapResources: - title: Low Quality Map Resources - description: Simplifies the rendering of resources on the map when zoomed in to - improve performance. It even looks cleaner, so be sure to try it - out! + title: Kualitas Peta Sumber Daya Rendah + description: Menyederhanakan rendering sumber daya pada peta saat diperbesar untuk meningkatkan performa. + Bahkan terlihat lebih rapi, jadi pastikan untuk mencobanya! disableTileGrid: - title: Disable Grid - description: Disabling the tile grid can help with the performance. This also - makes the game look cleaner! + title: Nonaktifkan Grid + description: Menonaktifkan ubin grid dapat membantu performa. + Ini juga membuat game menjadi lebih rapi! clearCursorOnDeleteWhilePlacing: - title: Clear Cursor on Right Click - description: Enabled by default, clears the cursor whenever you right click - while you have a building selected for placement. If disabled, - you can delete buildings by right-clicking while placing a - building. + title: Menghapus Kursor dengan Klik Kanan + description: Diaktifkan secara default, menghapus kursor setiap kali kamu mengklik kanan saat kamu memiliki bangunan yang dipilih untuk penempatan. Jika dinonaktifkan, kamu dapat menghapus bangunan dengan mengklik kanan saat meletakkan bangunan. lowQualityTextures: - title: Low quality textures (Ugly) - description: Uses low quality textures to save performance. This will make the - game look very ugly! + title: Tekstur kualitas rendah (Jelek) + description: Menggunakan kualitas rendah untuk menyelamatkan performa. + Ini akan membuat penampilan game menjadi jelek! displayChunkBorders: - title: Display Chunk Borders - description: The game is divided into chunks of 16x16 tiles, if this setting is - enabled the borders of each chunk are displayed. + title: Tampilkan Batasan Chunk + description: Game ini dibagi-bagi menjadi ubin 16x16 bagian, jika pengaturan ini + diaktifkan maka batas dari tiap chunk akan diperlihatkan. pickMinerOnPatch: - title: Pick miner on resource patch - description: Enabled by default, selects the miner if you use the pipette when - hovering a resource patch. + title: Memilih ekstraktor pada tampungan sumber daya + description: Diaktifkan secara default, memilih ekstraktor apabila kamu menggunakan pipet ketika + mengarahkan pada tampungan sumber daya. simplifiedBelts: - title: Simplified Belts (Ugly) - description: Does not render belt items except when hovering the belt to save - performance. I do not recommend to play with this setting if you - do not absolutely need the performance. + title: Sabuk Sederhana (Jelek) + description: Tidak merender item pada sabuk konveyor kecuali ketika mengarahkan ke konveyor + untuk menyelamatkan performa. Saya tidak merekomendasikan untuk bermain dengan pengaturan ini + jika kamu tidak benar-benar perlu performanya. enableMousePan: - title: Enable Mouse Pan - description: Allows to move the map by moving the cursor to the edges of the - screen. The speed depends on the Movement Speed setting. + title: Bergeser pada Layar Tepi + description: Memungkinkan untuk memindahkan peta dengan menggerakkan kursor ke tepi layar. Kecepatannya tergantung pada pengaturan Kecepatan Gerakan. zoomToCursor: - title: Zoom towards Cursor - description: If activated the zoom will happen in the direction of your mouse - position, otherwise in the middle of the screen. + title: Zoom ke arah Kursor + description: Jika dinyalakan maka zoom akan terjadi pada arah dan posisi kursor, + sebaliknya zoom kana mengarah pada tengah layar. + mapResourcesScale: + title: Ukuran Sumber Daya Peta + description: Mengontrol ukuran bentuk-bentuk pada gambaran peta (ketika zoom out). rangeSliderPercentage: % keybindings: - title: Tombol pintas - hint: "Petunjuk: Pastikan Anda menggunakan CTRL, SHIFT and ALT! Mereka + title: Tombol Pintas + hint: "Petunjuk: Pastikan kamu menggunakan CTRL, SHIFT and ALT! Mereka memungkinkan berbagai opsi penempatan." resetKeybindings: Setel Ulang Tombol Pintas categoryLabels: @@ -913,9 +940,9 @@ keybindings: ingame: Permainan navigation: Navigasi placement: Penempatan - massSelect: Pemilihan massal - buildings: Tombol pintas bangunan - placementModifiers: Pengubah penempatan + massSelect: Pemilihan Massal + buildings: Tombol Pintas Bangunan + placementModifiers: Pengubah Penempatan mappings: confirm: Konfirmasi back: Kembali @@ -925,56 +952,56 @@ keybindings: mapMoveLeft: Geser ke kiri mapMoveFaster: Geser lebih cepat centerMap: Pusat peta - mapZoomIn: Perbesar - mapZoomOut: Perkecil + mapZoomIn: Zoom in + mapZoomOut: Zoom out createMarker: Buat penanda menuOpenShop: Tingkatan-tingkatan menuOpenStats: Statistik menuClose: Tutup menu - toggleHud: Alihkan HUD - toggleFPSInfo: Alihkan laju bingkan per detik (frame per second) dan informasi debug + toggleHud: Aktifkan HUD + toggleFPSInfo: Aktifkan FPS dan Informasi Debug switchLayers: Ganti lapisan - exportScreenshot: Ekspor keseluruhan pangkalan pusat sebagai gambar + exportScreenshot: Ekspor keseluruhan pabrik sebagai Screenshot belt: Sabuk Konveyor underground_belt: Terowongan miner: Ekstraktor cutter: Pemotong rotater: Pemutar - stacker: Penyusun + stacker: Penumpuk mixer: Pencampur Warna - painter: Pencat + painter: Pengecat trash: Tong Sampah - wire: Kawat Energi + wire: Kabel pipette: Pipet rotateWhilePlacing: Putar cycleBuildingVariants: Ganti varian confirmMassDelete: Hapus area - pasteLastBlueprint: Gandakan cetak biru terakhir + pasteLastBlueprint: Tempel (paste) cetak biru terakhir cycleBuildings: Ganti bangunan lockBeltDirection: Aktifkan perencana konveyor switchDirectionLockSide: "Planner: Alih sisi" massSelectStart: Tahan dan seret untuk memulai massSelectSelectMultiple: Pilih berbagai area - massSelectCopy: Gandakan area - massSelectCut: Pindahkan area + massSelectCopy: Salin (copy) area + massSelectCut: Pindahkan (cut) area placementDisableAutoOrientation: Nonaktifkan orientasi otomatis placeMultiple: Tinggal di mode penempatan placeInverse: Balikkan orientasi otomatis konveyor - balancer: Balancer - storage: Storage - constant_signal: Constant Signal - logic_gate: Logic Gate - lever: Switch (regular) + balancer: Penyeimbang + storage: Tempat Penyimpanan + constant_signal: Sinyal Konstan + logic_gate: Gerbang Logis + lever: Saklar filter: Filter - wire_tunnel: Wire Crossing - display: Display - reader: Belt Reader - virtual_processor: Virtual Cutter + wire_tunnel: Terowongan Kabel + display: Layar + reader: Pembaca Sabuk Konveyor + virtual_processor: Pemotong Virtual transistor: Transistor - analyzer: Shape Analyzer - comparator: Compare - item_producer: Item Producer (Sandbox) - copyWireValue: "Wires: Copy value below cursor" + analyzer: Penganalisa Bentuk + comparator: Pembanding + item_producer: Pembuat Item + copyWireValue: "Kabel: Salin nilai di bawah kursor" backwardsModifier: "Modifier: Cycle backwards" about: title: Tentang permainan ini @@ -983,13 +1010,13 @@ about: href="https://github.com/tobspr" target="_blank">Tobias Springer (ini adalah saya).

- Apabila Anda ingin berkontribusi, periksa shapez.io di github.

+ Apabila kamu ingin berkontribusi, periksa shapez.io di github.

- Permainan ini tidak mungkin ada tanpa komunitas Discord di sekitar permainan saya – Anda hendaknya bergabung server Discord!

+ Permainan ini tidak mungkin ada tanpa komunitas Discord di sekitar game saya – Kamu hendaknya bergabung server Discord!

Lagunya dibuat oleh Peppsen - Dia mengagumkan.

- Akhirnya, banyak terima kasih kepada teman baik saya Niklas - Tanpa sesi-sesi factorio kami, permainan ini tidak mungkin tercipta. + Akhir kata, banyak terima kasih kepada teman baik saya Niklas - Tanpa sesi-sesi factorio kami, permainan ini tidak mungkin tercipta. changelog: title: Catatan Perubahan demo: @@ -1001,63 +1028,59 @@ demo: exportingBase: Mengekspor keseluruhan pangkalan pusat sebagai gambar settingNotAvailable: Tidak tersedia dalam versi demo. tips: - - The hub accepts input of any kind, not just the current shape! - - Make sure your factories are modular - it will pay out! - - Don't build too close to the hub, or it will be a huge chaos! - - If stacking does not work, try switching the inputs. - - You can toggle the belt planner direction by pressing R. - - Holding CTRL allows dragging of belts without auto-orientation. - - Ratios stay the same, as long as all upgrades are on the same Tier. - - Serial execution is more efficient than parallel. - - You will unlock more variants of buildings later in the game! - - You can use T to switch between different variants. - - Symmetry is key! - - You can weave different tiers of tunnels. - - Try to build compact factories - it will pay out! - - The painter has a mirrored variant which you can select with T - - Having the right building ratios will maximize efficiency. - - At maximum level, 5 extractors will fill a single belt. - - Don't forget about tunnels! - - You don't need to divide up items evenly for full efficiency. - - Holding SHIFT will activate the belt planner, letting you place - long lines of belts easily. - - Cutters always cut vertically, regardless of their orientation. - - To get white mix all three colors. - - The storage buffer priorities the first output. - - Invest time to build repeatable designs - it's worth it! - - Holding CTRL allows to place multiple buildings. - - You can hold ALT to invert the direction of placed belts. - - Efficiency is key! - - Shape patches that are further away from the hub are more complex. - - Machines have a limited speed, divide them up for maximum efficiency. - - Use balancers to maximize your efficiency. - - Organization is important. Try not to cross conveyors too much. - - Plan in advance, or it will be a huge chaos! - - Don't remove your old factories! You'll need them to unlock upgrades. - - Try beating level 20 on your own before seeking for help! - - Don't complicate things, try to stay simple and you'll go far. - - You may need to re-use factories later in the game. Plan your factories to - be re-usable. - - Sometimes, you can find a needed shape in the map without creating it with - stackers. - - Full windmills / pinwheels can never spawn naturally. - - Color your shapes before cutting for maximum efficiency. - - With modules, space is merely a perception; a concern for mortal men. - - Make a separate blueprint factory. They're important for modules. - - Have a closer look on the color mixer, and your questions will be answered. - - Use CTRL + Click to select an area. - - Building too close to the hub can get in the way of later projects. - - The pin icon next to each shape in the upgrade list pins it to the screen. - - Mix all primary colors together to make white! - - You have an infinite map, don't cramp your factory, expand! - - Also try Factorio! It's my favorite game. - - The quad cutter cuts clockwise starting from the top right! - - You can download your savegames in the main menu! - - This game has a lot of useful keybindings! Be sure to check out the - settings page. - - This game has a lot of settings, be sure to check them out! - - The marker to your hub has a small compass to indicate its direction! - - To clear belts, cut the area and then paste it at the same location. - - Press F4 to show your FPS and Tick Rate. - - Press F4 twice to show the tile of your mouse and camera. - - You can click a pinned shape on the left side to unpin it. + - Bangunan pusat menerima segala input, tidak hanya bentuk sekarang! + - Pastikan pabrikmu berbentuk modul - akan membantu! + - Jangan membangun terlalu dekat PUSAT, atau akan terjadi kericuhan yang besar! + - Apabila penumpukkan tidak bekerja, cobalah tukar kedua input. + - Kamu bisa mengaktifkan Perencana Sabuk Konveyor dengan menekan tombol R. + - Menahan CTRL memungkinkan untuk menyeret sabuk konveyor tanpa rotasi otomatis. + - Rasio akan tetap sama, selama semua upgrade berada pada Tingkatan yang sama. + - Eksekusi atau pembuatan secara serial lebih efisian daripada paralel. + - Kamu akan membuka lebih banyak variasi bangunan nanti dalam game! + - Kamu bisa menggunakan tombol T untuk berganti antara varian. + - Simetri adalah kunci! + - Kamu dapat memadukan dua varian terowongan dalam satu baris ubin. + - Cobalah untuk membuat pabrik yang kompak dan padat - akan membantu! + - Pengecat memiliki varian lain yang bisa kamu pilih dengan menekan tombol T + - Memiliki rasio bangunan yang tepat dapat memaksimalkan efektivitas. + - Pada level maksimum, 5 ekstraktor akan memenuhi 1 sabuk konveyor. + - Jangan lupa tentang terowongan! + - Kamu tidak perlu membagi item secara merata untuk meraih efisiensi maksimal. + - Menahan SHIFT akan mengaktifkan Perencana Sabuk Konveyor, memungkinkan kamu untuk meletakkan sabuk konveyor yang panjang dengan mudah + - Pemotong selalu memotong secara vertikal, bagaimanapun orientasinya. + - Untuk mendapatkan warna putih, campurkan ketiga warna. + - Tempat penyimpanan memprioritaskan output pertama. + - Gunakan waktu untuk menciptakan desain yang dapat diulang - itu sangat berharga! + - Menahan CTRL memungkinkan untuk meletakkan beberapa bangunan. + - Kamu dapat menahan ALT untuk memutar arah pada sabuk konveyor yang sudah diletakkan. + - Efisiensi adalah kunci! + - Tampungan bentuk yang semakin jauh dari pusat maka akan semakin kompleks. + - Mesin-mesin memiliki kecepatan maksimum, bagilah mereka untuk mendapatkan efisiensi maksimal. + - Gunakan penyeimbang untuk memaksimalkan efisiensi pabrikmu. + - Pabrik yang terorganisir itu penting. Cobalah untuk tidak banyak menyebrangi konveyor. + - Rencanakan terlebih dahulu, atau akan menjadi kericuhan yang besar! + - Jangan hapus pabrik-pabrik lama kamu! Kamu akan memerlukannya untuk membuka tingkatan. + - Cobalah untuk menyelesaikan level 20 sebelum mencari bantuan! + - Jangan mempersulit hal-hal, cobalah untuk tetap simpel dan kamu akan maju. + - Kamu mungkin perlu menggunakan ulang pabrik-pabrik yang telah kamu buat. Rencanakan pabrik kamu supaya dapat digunakan kembali. + - Terkadang, kamu dapat menemukan bentuk yang diperlukan pada peta tanpa harus menumpuknya. + - Bentuk penuh windmills dan pinwheels tidak akan pernah muncul secara natural. + - Warnai bentuk sebelum memotongnya untuk meningkatkan efisiensi. + - Dengan modul-modul, ruang hanyalah persepsi; sebuah kekhawatiran untuk seorang yang hidup. + - Buatlah pabrik Cetak Biru yang terpisah. Mereka sangat penting untuk membuat modul. + - Perhatikan lebih dekat pencampur warnanya, dan pertanyaanmu akan terjawab. + - Gunakan CTRL + Klik untuk memilih sebuah area. + - Bangunan yang terlau dekat dengan pusat dapat menghalangi projek yang akan datang. + - Ikon pin di samping tiap bentuk pada tab upgrade akan mem-pin bentuknya ke layar. + - Campur semua warna utama untuk menciptakan warna putih! + - Kamu punya peta yang tak terbatas, jadi jangan memadatkan pabrikmu di pusat, luaskan! + - Cobalah Factorio juga! Itu game favorit saya. + - Pemotong (Empat Bagian) memotong searah jarum jam mulai dari bagian kanan atas! + - Kamu bisa mengunduh data simpananmu di menu utama (main menu)! + - Game ini memiliki banyak tombol pintas yag sangat berguna! Pastikan untuk mengeceknya di pengaturan. + - Game ini memiliki banyak pengaturan, Pastikan untuk mengeceknya! + - Penanda ke bangunan pusatmu memiliki kompas yang menunjukkan lokasinya! + - Untuk membersihkan sabuk konveyor, pindahkan bagian dan tempel di lokasi yang sama. + - Tekan F4 untuk menunjukkan FPS dan Tick Rate kamu. + - Tekan F4 dua kali untuk menunjukkan ubin mouse dan kameramu. + - Kamu bisa mengklik bentuk yang di-pin di sebelah kiri untuk tidak mem-pinnya lagi. diff --git a/translations/base-it.yaml b/translations/base-it.yaml index 57768204..f31b16ef 100644 --- a/translations/base-it.yaml +++ b/translations/base-it.yaml @@ -22,7 +22,7 @@ steamPage: - L'aggiornamento dei Cavi per una dimensione completamente nuova! - Modalità scura! - Salvataggi illimitati - - Segnapunti illimitati + - Etichette illimitate - Mi sostieni! ❤️ title_future: Contenuti pianificati planned: @@ -82,8 +82,8 @@ demoBanners: title: Versione Demo intro: Ottieni la versione completa per sbloccare tutte le funzioni! mainMenu: - play: Play - changelog: Changelog + play: Gioca + changelog: Registro modifiche importSavegame: Importa openSourceHint: Questo gioco è open source! discordLink: Server ufficiale Discord @@ -121,9 +121,9 @@ dialogs: text: "Impossibile caricare il salvataggio:" confirmSavegameDelete: title: Conferma eliminazione - text: Are you sure you want to delete the following game?

- '' at level

This can not be - undone! + text: Sei sicuro di voler eliminare la partita seguente?

+ '' al livello

Da qui in poi + non si può più tornare indietro! savegameDeletionError: title: Impossibile eliminare text: "Impossibile eliminare il salvataggio:" @@ -177,13 +177,14 @@ dialogs: class='keybinding'>ALT
: Inverti l'orientamento dei nastri trasportatori.
" createMarker: - title: Nuovo segnapunto - desc: Give it a meaningful name, you can also include a short - key of a shape (Which you can generate here) - titleEdit: Modifica segnapunto + title: Nuova etichetta + desc: Dagli un nome significativo, puoi anche inserire un + codice di una forma (Che puoi generare + qui) + titleEdit: Modifica etichetta markerDemoLimit: - desc: Puoi creare solo due segnapunti personalizzati nella Demo. Ottieni la - versione completa per avere segnapunti personalizzati illimitati! + desc: Puoi creare solo due etichette personalizzate nella Demo. Ottieni la + versione completa per avere etichette personalizzate illimitati! massCutConfirm: title: Conferma taglio desc: Stai tagliando molte strutture ( per essere precisi)! Sei sicuro di @@ -205,6 +206,14 @@ dialogs: renameSavegame: title: Rinomina salvataggio. desc: Qui puoi cambiare il nome del salvataggio. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Sposta @@ -234,7 +243,7 @@ ingame: range: Raggio storage: Spazio oneItemPerSecond: 1 oggetto / secondo - itemsPerSecond: oggetti / s + itemsPerSecond: oggetti / secondo itemsPerSecondDouble: (x2) tiles: caselle levelCompleteNotification: @@ -245,7 +254,7 @@ ingame: notifications: newUpgrade: È disponibile un nuovo aggiornamento! gameSaved: Partita salvata. - freeplayLevelComplete: Level has been completed! + freeplayLevelComplete: Il livello è stato completato! shop: title: Miglioramenti buttonUnlock: Sblocca @@ -256,7 +265,7 @@ ingame: dataSources: stored: title: Immagazzinate - description: Mostra il numero di forme immagizzinate nell'edificio centrale. + description: Mostra il numero di forme immagazzinate nell'Edificio centrale. produced: title: Prodotte description: Mostra tutte le forme prodotte dalla tua fabbrica, inclusi i @@ -280,19 +289,19 @@ ingame: blueprintPlacer: cost: Costo waypoints: - waypoints: Segnapunti + waypoints: Punti di interesse hub: HUB - description: Clic sinistro su un segnapunto per raggiungerlo, clic destro per - cancellarlo.

Premi per creare un segnapunto + description: Clic sinistro su un etichetta per raggiungerla, clic destro per + cancellarla.

Premi per creare un etichetta dalla visuale corrente, oppure click destro per - creare un segnapunto nella posizione selezionata. - creationSuccessNotification: Il segnapunto è stato creato. + creare un etichetta nella posizione selezionata. + creationSuccessNotification: L'etichetta è stata creata. interactiveTutorial: title: Tutorial hints: 1_1_extractor: Posiziona un estrattore sopra una forma circolare per estrarla! - 1_2_conveyor: "Connetti l'estrattore all'Hub centrale utilizzando un + 1_2_conveyor: "Connetti l'estrattore all'Edificio centrale utilizzando un nastro trasportatore!

Suggerimento: Clicca e trascina il nastro con il mouse!" 1_3_expand: "Questo NON è un idle game! Costruisci più @@ -300,6 +309,30 @@ ingame: velocemente.

Suggerimento: Tieni premuto MAIUSC per piazzare estrattori multipli, e usa R per ruotarli." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." colors: red: Rosso green: Verde @@ -308,7 +341,7 @@ ingame: purple: Magenta cyan: Azzurro white: Bianco - uncolored: No colore + uncolored: Senza colore black: Nero shapeViewer: title: Strati @@ -320,7 +353,7 @@ ingame: limited_items: Limitato a watermark: title: Versione demo - desc: Clicca qui per vedere i vantaggi della versione Steam! + desc: Clicca qui per vedere i vantaggi della versione Completa! get_on_steam: Ottieni su Steam standaloneAdvantages: title: Ottieni la versione completa! @@ -339,7 +372,7 @@ ingame: title: 20 gradi di miglioramenti desc: Questa demo ne ha solo 5! markers: - title: ∞ segnapunti + title: ∞ etichette desc: Non perderti nella tua fabbrica! wires: title: Cavi @@ -367,43 +400,43 @@ buildings: belt: default: name: Nastro Trasportatore - description: Trasporta oggetti, clicca e trascina per posizionare in sequenza. + description: Trasporta oggetti, clicca e trascina per posizionarli in sequenza. miner: default: name: Estrattore - description: Posiziona sopra una forma o un colore per estrarlo. + description: Posizionalo sopra una forma o un colore per estrarlo. chainable: name: Estrattore (Catena) - description: Posiziona sopra una forma o un colore per estrarlo. Puoi combinarlo - con altri estrattori. + description: Posizionalo sopra una forma o un colore per estrarlo. Puoi + combinarlo con altri estrattori. underground_belt: default: name: Tunnel - description: Permette di far passare delle risorse sotto a costruzioni e nastri - trasportatori. + description: Permette di far passare le risorse sotto alle costruzioni e ai + nastri trasportatori. tier2: name: Tunnel Grado II - description: Permette di far passare delle risorse sotto a costruzioni e nastri - trasportatori. + description: Permette di far passare le risorse sotto alle costruzioni e ai + nastri trasportatori. cutter: default: - name: Tagliatrice - description: Taglia le forme verticalmente e restituisce le metà destra e - sinistra. Se usi solo una parte, distruggi l'altra o la - macchina si fermerà! + name: Taglierino + description: Taglia le forme verticalmente e restituisce le due metà a destra e + a sinistra. Se usi solo una parte, distruggi l'altra o + la macchina si fermerà! quad: - name: Tagliatrice (4x) - description: Taglia le forme in quattro parti. Se usi solo una parte, - distruggi le altre o la macchina si fermerà! + name: Taglierino (4x) + description: Taglia le forme in quattro parti. Se usi meno di quattro + parti, distruggi le altre o la macchina si fermerà! rotater: default: - name: Ruotatrice + name: Ruotatore description: Ruota le forme di 90 gradi in senso orario. ccw: - name: Ruotatrice (Ant.) + name: Ruotatore (Ant.) description: Ruota le forme di 90 gradi in senso antiorario. rotate180: - name: Ruotatrice (180) + name: Ruotatore (180°) description: Ruota le forme di 180 gradi. stacker: default: @@ -412,26 +445,26 @@ buildings: uniti, l'oggetto destro è posizionato sopra il sinstro. mixer: default: - name: Mixer Colori + name: Miscelatore di vernice description: Mescola due colori mediante sintesi additiva. painter: default: - name: Verniciatrice + name: Verniciatore description: Colora l'intera forma dall'ingresso sinistro con il colore - dall'ingresso destro. + dall'ingresso superiore. double: - name: Verniciatrice (2x) + name: Verniciatore (2x) description: Colora le forme dagli ingressi sinistri con il colore dall'ingresso - destro. + superiore. quad: - name: Verniciatrice (4x) - description: Allows you to color each quadrant of the shape individually. Only - slots with a truthy signal on the wires layer - will be painted! + name: Verniciatore (4x) + description: Ti permette di colorare ogni quadrante della forma individualmente. + Solo gli spazi con un Vero sul livello + elettrico saranno colorati! mirrored: - name: Verniciatrice + name: Verniciatore description: Colora l'intera forma dall'ingresso sinistro con il colore - dall'ingresso destro. + dall'ingresso inferiore. trash: default: name: Cestino @@ -452,7 +485,7 @@ buildings: balancer: default: name: Bilanciatore - description: Multifunzionale, distribuisce equamente gli ogetti in ingresso tra + description: Multifunzione, distribuisce equamente gli oggetti in ingresso tra tutte le uscite. merger: name: Aggregatore (compatto) @@ -468,13 +501,13 @@ buildings: description: Divide un nastro in due. storage: default: - name: Stoccaggio + name: Magazzino description: Immagazzina gli oggetti in eccesso, fino ad una capacità massima. - Prioritizza l'uscita sinistra e può quindi essere usato per + Dà priorità all'uscita sinistra e può quindi essere usato per gestire le eccedenze. wire_tunnel: default: - name: Incrocio cavi + name: Incrocio fra cavi description: Consente a due cavi di attraversarsi senza connettersi. constant_signal: default: @@ -483,15 +516,15 @@ buildings: un booleano (1 / 0). lever: default: - name: Bottone + name: Interruttore description: Può essere azionato per emettere un segnale booleano (1 / 0) nel - livello dei cavi, che può essere usato per controllare, per + livello elettrico, che può essere usato per controllare, per esempio, un filtro. logic_gate: default: name: Porta AND description: Emette un "1" booleano se entrambi gli ingressi sono veri. (Vero - significa forma, colore o "1" boolean) + significa forma, colore o "1" booleano) not: name: Porta NOT description: Emette un "1" booleano se l'ingresso è falso. (Vero significa @@ -506,11 +539,11 @@ buildings: significa forma, colore o "1" booleano) transistor: default: - name: Transistor + name: Transistore description: Inoltra il segnale dall'ingresso inferiore se l'ingresso laterale è vero (una forma, un colore o "1"). mirrored: - name: Transistor + name: Transistore description: Inoltra il segnale dall'ingresso inferiore se l'ingresso laterale è vero (una forma, un colore o "1"). filter: @@ -542,105 +575,107 @@ buildings: comparare forme, colori e booleani. virtual_processor: default: - name: Tagliatrice virtuale + name: Taglierino virtuale description: Taglia virtualmente la forma in due metà. rotater: - name: Ruotatrice virtuale - description: Ruota virtualmente la forma, sia in senso orario che antiorario. + name: Ruotatore virtuale + description: Ruota virtualmente la forma, sia in senso orario sia antiorario. unstacker: name: Disimpilatrice virtuale description: Estrae virtualmente lo strato più alto e lo emette a destra, i restanti sono emessi a sinistra. stacker: name: Impilatrice virtuale - description: Impila visrtualmente la forma destra sulla sinistra. + description: Impila virtualmente la forma destra sulla sinistra. painter: - name: Verniciatrice virtuale + name: Verniciatore virtuale description: Vernicia virtualmente la forma dall'ingresso inferiore con il colore dall'ingresso destro. item_producer: default: name: Generatore di oggetti description: Disponibile solo nella modalità sandbox, emette il segnale dal - livello dei cavi come oggetti sul livello normale. + livello elettrico come oggetti sul livello normale. storyRewards: reward_cutter_and_trash: title: Taglio forme - desc: You just unlocked the cutter, which cuts shapes in half - from top to bottom regardless of its - orientation!

Be sure to get rid of the waste, or - otherwise it will clog and stall - For this purpose - I have given you the trash, which destroys - everything you put into it! + desc: Il taglierino è stato bloccato! Taglia le forme a metà da + sopra a sotto indipendentemente dal suo + orientamento!

Assicurati di buttare via lo scarto, + sennò si intaserà e andrà in stallo - Per questo + ti ho dato il certino, che distrugge tutto quello + che riceve! reward_rotater: title: Rotazione - desc: La ruotatrice è stata sbloccata! Ruota le forme di 90 + desc: Il ruotatore è stato sbloccato! Ruota le forme di 90 gradi in senso orario. reward_painter: title: Verniciatura - desc: "La verniciatrice è stata sbloccata - Estrai dalle vene + desc: "Il verniciatore è stato sbloccato! Estrai dalle vene colorate (esattamente come fai con le forme) e combina il colore con una forma nella veniciatrice per colorarla!

PS: Se sei daltonico, c'è la modalità daltonici nelle - opzioni!" + impostazion!" reward_mixer: title: Mix colori - desc: Il mixer è stato sbloccato - Con questo edificio, puoi - combinare due colori mediante sintesi additiva! + desc: Il miscelatore è stato sbloccato! Con questo edificio, + puoi combinare due colori mediante la sintesi + additiva! reward_splitter: title: Separatore/Agrregatore - desc: You have unlocked a splitter variant of the - balancer - It accepts one input and splits them - into two! + desc: Il separatore è stato sbloccato! è una variante del + bilanciatore - Accetta un imput e lo divide in due! reward_tunnel: title: Tunnel - desc: Il tunnel è stato sbloccato. In questo modo puoi + desc: Il tunnel è stato sbloccato! In questo modo puoi trasportare oggetti al di sotto di nastri ed edifici! reward_rotater_ccw: title: Rotazione antioraria - desc: Hai sbloccato una variante della ruotatrice. Consente di + desc: Hai sbloccato una variante del ruotatore! Consente di ruotare in senso antiorario! Per costruirla, seleziona la ruotatrice e premi 'T' per cambiare variante! reward_miner_chainable: title: Estrattore a catena - desc: "You have unlocked the chained extractor! It can - forward its resources to other extractors so you - can more efficiently extract resources!

PS: The old - extractor has been replaced in your toolbar now!" + desc: "L'estrattore a catena è stato sbloccato! Può + passare le sue risorse agli altri estrattori, così + tu puoi estrarre le risorse in modo più efficiente!

PS: Il + primo estrattore è stato rimpiazzato nel tuo inventario!" reward_underground_belt_tier_2: title: Tunnel grado II - desc: Hai sbloccato una nuova variante del tunnel. Ha un + desc: Hai sbloccato una variante del tunnel! Ha un raggio più ampio e puoi anche mischiare le due varianti ora! reward_cutter_quad: title: Taglio quadruplo - desc: Hai sbloccato una variante della tagliatrice. Cconsente - di tagliare le forme in quattro parti invece che in + desc: Hai sbloccato una variante del taglierino! Consente di + tagliare le forme in quattro parti invece che in due! reward_painter_double: title: Verniciatura doppia - desc: Hai sbloccato una variante della verniciatrice. Funziona - come una normale verniciatrice, ma processa due forme alla + desc: Hai sbloccato una variante del verniciatore! Funziona + come un normale verniciatore, ma processa due forme alla volta consumando solo un'unità di colore invece che due! reward_storage: title: Unità di stoccaggio - desc: You have unlocked the storage building - It allows you to - store items up to a given capacity!

It priorities the left - output, so you can also use it as an overflow gate! + desc: Hai sbloccato il magazzino! Ti permette di immagazzinare + le forme fino a un certo limite!

Dà priorità all'uscita a + sinistra, puoi quindi usarlo per gestire le + eccedenze! reward_freeplay: title: Modalità libera - desc: You did it! You unlocked the free-play mode! This means - that shapes are now randomly generated!

- Since the hub will require a throughput from now - on, I highly recommend to build a machine which automatically - delivers the requested shape!

The HUB outputs the requested - shape on the wires layer, so all you have to do is to analyze it and - automatically configure your factory based on that. + desc: Ce l'hai fatta! Hai sbloccato la modalità libera! Questo + significa che le forme da adesso in poi sono generate + casualmente!

Visto che la HUB avrà bisogno + di una portata maggiore Ti consiglio vivamente di + costruire un macchinario che consegna automaticamente la forma + richiesta!

La HUB da come output la forma richiesta sul + livello elettrico, quindi ti basta solo analizzarla e configurare + automaticamente la tua fabbrica in base a quei dati. reward_blueprints: title: Progetti - desc: Ora puoi copiare ed incollare parti della tua fabbrica! - Seleziona un'area (Tieni premuto CTRL e trascina con il mouse) e - premi 'C' per copiarla.

Incollarla non è + desc: Ora puoi copiare ed incollare componenti della tua + fabbrica! Seleziona un'area (Tieni premuto CTRL e trascina con il + mouse) e premi 'C' per copiarla.

Incollarla non è gratis, devi produrre forme progetto per potertelo permettere! (Quelle che hai appena consegnato). no_reward: @@ -667,7 +702,7 @@ storyRewards: reward_merger: title: Aggregatore compatto desc: Hai sbloccato un aggregatore, variante del - bilanciatore. Acetta due ingressi e li aggrega su + bilanciatore! Acetta due ingressi e li aggrega su un unico nastro! reward_belt_reader: title: Lettore di nastri @@ -676,19 +711,19 @@ storyRewards: allora sì che sarà molto utile! reward_rotater_180: title: Ruotatrice (180 gradi) - desc: Hai appena sbloccato la ruotatrice a 180 gradi! Consente + desc: Hai appena sbloccato il ruotatore a 180 gradi! Consente di ruotare una forma di 180 gradi (Sorpresa! :D) reward_display: title: Display - desc: "You have unlocked the Display - Connect a signal on the - wires layer to visualize it!

PS: Did you notice the belt - reader and storage output their last read item? Try showing it on a - display!" + desc: "Hai sbloccato il Display! Connetti un segnale sul + livello elettrico per visualizzarlo!

PS: Hai notato che il + lettore di nastri e il magazzino mostrano l'ultimo oggetto da loro + letto? Prova a mostrarlo su di un display!" reward_constant_signal: title: Sengale costante - desc: Hai sblocatto l'edificio segnale costante sul livello dei - cavi! È utile collegarlo ai filtri oggetti per - esempio.

Il segnale costante può emettere una + desc: Hai sblocatto l'edificio segnale costante sul livello + elettrico! È utile collegarlo ai filtri di oggetti + per esempio.

Il segnale costante può emettere una forma, un colore o un booleano (1 / 0). reward_logic_gates: @@ -697,33 +732,34 @@ storyRewards: entusiasta, ma in realtà sono fantastiche!

Con quelle porte ora puoi eseguire le operazioni logiche di AND, OR, XOR e NOT.

Come bonus extra ti ho anche regalato un - transistor! + transistore! reward_virtual_processing: title: Lavorazione virtuale desc: Ti ho appena dato un bel po' di nuovi edifici che ti consentono di simulare la lavorazione delle forme!

Ora - puoi simulare una tagliatrice, una ruotatrice, un'impilatrice e - molto altro sul livello dei cavi! In questo modo hai tre opzioni per + puoi simulare un taglierino, un ruotatore, un'impilatrice e molto + altro sul livello elettrico! In questo modo hai tre opzioni per continuare il gioco:

-Costruisci una macchina automatica per creare ogni possibile forma richiesta dall'HUB (ti consiglio di provarci!).

- Costruisci qualcosa di interessante con i cavi.

- Continua a giocare - normalmente.

Qualsiasi cosa tu scelga, riordati di + normalmente.

Qualsiasi cosa tu scelga, ricordati di divertirti! reward_wires_painter_and_levers: title: Cavi e Verniciatrice quadrupla - desc: "Hai appena sbloccato il livello dei cavi: È un livello - separato al di sopra di quello normale e introduce un sacco di nuove - meccaniche!

Per il momento ti ho sbloccato la - Verniciatrice quadrupla. Collega gli ingressi con i - quali vuoi dipingere nel livello dei cavi!

Per passare al - livello dei cavi, premi E." + desc: "You just unlocked the Wires Layer: It is a separate + layer on top of the regular layer and introduces a lot of new + mechanics!

For the beginning I unlocked you the Quad + Painter - Connect the slots you would like to paint with on + the wires layer!

To switch to the wires layer, press + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Filtro oggetti desc: Hai sbloccato il filtro oggetti! Smisterà gli oggetti - verso l'alto o verso destra a seconda che corrispondano al sengale - dal livello dei cavi o no.

Puoi anche mandargli un segnale - booleano (1 / 0) per attivarlo o disattivarlo completamente. + verso l'alto o verso destra a seconda del segnale dal livello + elettrico o meno.

Puoi anche mandargli un segnale booleano + (1 / 0) per attivarlo o disattivarlo completamente. reward_demo_end: title: Fine della demo desc: Hai raggiunto la fine della demo! @@ -733,7 +769,7 @@ settings: general: Generali userInterface: Interfaccia utente advanced: Avanzate - performance: Performance + performance: Prestazioni versionBadges: dev: Sviluppo staging: Staging @@ -894,6 +930,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Comandi @@ -918,7 +958,7 @@ keybindings: centerMap: Centra mappa mapZoomIn: Aumenta zoom mapZoomOut: Riduci zoom - createMarker: Crea segnapunto + createMarker: Crea Etichetta menuOpenShop: Miglioramenti menuOpenStats: Statistiche toggleHud: Mostra/Nascondi HUD @@ -926,16 +966,16 @@ keybindings: belt: Nastro Trasportatore underground_belt: Tunnel miner: Estrattore - cutter: Tagliatrice - rotater: Ruotatrice + cutter: Taglierino + rotater: Ruotatore stacker: Impilatrice - mixer: Mixer Colori - painter: Verniciatrice + mixer: Miscelatore di vernice + painter: Verniciatore trash: Cestino rotateWhilePlacing: Ruota cycleBuildingVariants: Cicla varianti confirmMassDelete: Conferma eliminazione di massa - cycleBuildings: Cicla edifici + cycleBuildings: Cambia variante massSelectStart: Clicca e trascina per cominciare massSelectSelectMultiple: Seleziona aree multiple massSelectCopy: Copia area @@ -953,16 +993,16 @@ keybindings: switchLayers: Cambia livello wire: Cavo balancer: Bilanciatore - storage: Stoccaggio + storage: Magazzino constant_signal: Segnale costante logic_gate: Porta logica - lever: Bottone (normale) + lever: Interruttore (normale) filter: Filtro wire_tunnel: Incrocio cavi display: Display reader: Lettore nastri - virtual_processor: Tagliatrice virtuale - transistor: Transistor + virtual_processor: Taglierino virtuale + transistor: Transistore analyzer: Analizzatore forme comparator: Comparatore item_producer: Generatore di oggetti (Sandbox) @@ -983,7 +1023,7 @@ about: Per finire, grazie di cuore al mio migliore amico Niklas - Senza le nostre sessioni su factorio questo gioco non sarebbe mai esistito. changelog: - title: Changelog + title: Registro modifiche demo: features: restoringGames: Recupero salvataggi @@ -1008,8 +1048,7 @@ tips: - La simmetria è la chiave! - Puoi intrecciare gradi diversi del tunnel. - Cerca di costruire fabbriche compatte, sarai ricompensato! - - La verniciatrice ha una variante speculare che puoi selezionare con - T + - Il verniciatore ha una variante speculare che puoi selezionare con T - Avere i giusti rapporti tra gli edifici massimizzerà l'efficienza. - Al massimo livello, 5 estrattori saturano un singolo nastro. - Non dimenticare i tunnel! @@ -1017,10 +1056,10 @@ tips: efficienza. - Tenere premuto SHIFT attiva il pianificatore nastri, facilitando il posizionamento dei nastri più lunghi - - Le tagliatrici tagliano sempre in verticale, indipendentemente dalla - direzione. + - I taglierini tagliano sempre in verticale, indipendentemente + dall'orientamento. - Mischia tutti i tre colori per fare il bianco. - - L'unità di stoccaggio prioritizza la prima uscita. + - Il magazzino prioritizza la prima uscita. - Impiega tempo per costruire design replicabili, ne vale la pena! - Tenere premuto CTRL ti consente di piazzare multipli edifici. - Puoi tenere premuto ALT per invertire la direzione dei nastri @@ -1046,23 +1085,24 @@ tips: mortali. - Costruisci una fabbrica dedicata per i progetti. Sono importanti per i moduli. - - Guarda da vicino il mixer dei colori, e le tue domande avranno risposta. + - Guarda da vicino il miscelatore di colori, e le tue domande avranno + risposta. - Usa CTRL + Clic per selezionare un'area. - Costruire troppo vicino all'hub potrebbe intralciare progetti futuri. - Premere la puntina vicino a ogni forma nel menù miglioramenti la farà visualizzare sempre a schermo - Mescola tutti i colori primari per fare il bianco! - - Hai una mappa finita, non incastrare la tua fabbrica, espanditi! - - Prova anhe factorio! È il mio gioco preferito. - - La tagliatrice quadrupla taglia in senso orario a partire dal quadrante in + - Hai una mappa infinita, non incastrare la tua fabbrica, espanditi! + - Prova anche factorio! È il mio gioco preferito. + - Il taglierino quadruplo taglia in senso orario a partire dal quadrante in alto a destra! - Puoi scaricare i salvataggi dal menù principale! - Questo gioco ha molti tasti di scelta rapida! Dai un'occhiata alla pagina delle impostazioni - Questo gioco ha molte impostazioni, dai un'occhiata! - - Il segnapunto dell'hub ha una piccola bussola per indicarne la direzione! - - Per svutare i nastri, taglia e re-incolla l'area nello stesso punto. + - L'etichetta dell'hub ha una piccola bussola per indicarne la direzione! + - Per svuotare i nastri, taglia e re-incolla l'area nello stesso punto. - Premi F4 per mostrare FPS e Tick al secondo. - Press F4 due volte per mostrare la casella del cursore e della telecamera. - Puoi cliccare a sinistra di una forma fermata a schermo per rimuoverla - dalla lisata. + dalla lista. diff --git a/translations/base-ja.yaml b/translations/base-ja.yaml index 8b3b75fd..609fa3b4 100644 --- a/translations/base-ja.yaml +++ b/translations/base-ja.yaml @@ -176,6 +176,14 @@ dialogs: renameSavegame: title: セーブデータの名前を変更 desc: セーブデータの名前を変更することができます + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: マップ移動 @@ -279,6 +287,30 @@ ingame: もっと早く要件を満たせるように、追加の抽出機とベルトを設置しましょう。

Tip: SHIFT キーを押し続けると抽出機を連続配置できます。Rキーで設置方向を回転できます。" + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1個の抽出機 n_miners: 個の抽出機 @@ -568,10 +600,13 @@ storyRewards: desc: 回転機のバリエーションが利用可能になりました! 180度の回転ができるようになります!(サプライズ! :D) reward_wires_painter_and_levers: title: ワイヤ&着色機(四分割) - desc: "ワイヤレイヤが利用可能になりました!: - 通常レイヤとは別のレイヤーであり、異なる機能が使用できます!

- 最初に、着色機(四分割)が利用可能です。着色したいスロットを、ワイヤレイヤで接続します。
ワイヤレイヤに切り替えるには、Eを押します。" + desc: "You just unlocked the Wires Layer: It is a separate + layer on top of the regular layer and introduces a lot of new + mechanics!

For the beginning I unlocked you the Quad + Painter - Connect the slots you would like to paint with on + the wires layer!

To switch to the wires layer, press + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: アイテムフィルタ desc: アイテムフィルタが利用可能になりました! ワイヤレイヤの信号と一致するかどうかに応じて、 @@ -753,6 +788,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). keybindings: title: キー設定 hint: "Tip: CTRL, SHIFT, ALTを利用するようにしてください。これらはそれぞれ建造物配置の際の機能があります。" diff --git a/translations/base-kor.yaml b/translations/base-kor.yaml index 6fdd4786..4ab6b581 100644 --- a/translations/base-kor.yaml +++ b/translations/base-kor.yaml @@ -77,7 +77,7 @@ demoBanners: mainMenu: play: 시작 changelog: 버전 기록 - importSavegame: 불러오기 + importSavegame: 가져오기 openSourceHint: 이 게임은 오픈 소스입니다! discordLink: 공식 디스코드 서버 helpTranslate: 번역을 도와주세요! @@ -104,14 +104,14 @@ dialogs: showUpgrades: 업그레이드 보기 showKeybindings: 조작법 보기 importSavegameError: - title: 불러오기 오류 - text: "Failed to import your savegame:" + title: 가져오기 오류 + text: "세이브 파일을 가져오지 못했습니다:" importSavegameSuccess: - title: 세이브 파일 불러오기 성공 + title: 세이브 파일 가져오기 성공 text: 세이브 파일을 성공적으로 불러왔습니다. gameLoadFailure: title: 세이브 파일 에러 - text: "Failed to load your savegame:" + text: "세이브 파일을 불러오지 못했습니다:" confirmSavegameDelete: title: 삭제 확인 text: 이 세이브 파일을 정말로 삭제하시겠습니까?

'' @@ -176,11 +176,18 @@ dialogs: desc: 이 영역에는 붙여넣기를 할 수 없습니다! 정말 자르시겠습니까? editSignal: title: 신호 설정 - descItems: "Choose a pre-defined item:" + descItems: "미리 정의된 아이템을 선택합니다:" descShortKey: ... 또는 도형 단축키를 사용합니다 (여기에서 만드실 수 있습니다). renameSavegame: title: 세이브 파일 이름 설정 desc: 여기에서 세이브 파일의 이름을 바꿀 수 있습니다. + tutorialVideoAvailable: + title: 활성화된 튜토리얼 + desc: 현재 레벨에서 사용할 수 있는 튜토리얼 비디오가 있습니다! 보시겠습니까? + tutorialVideoAvailableForeignLanguage: + title: 활성화된 튜토리얼 + desc: 현재 레벨에서 사용할 수 있는 튜토리얼 비디오가 있습니다! 허나 영어로만 + 제공될 것입니다. 보시겠습니까? ingame: keybindingsOverlay: moveMap: 이동 @@ -204,7 +211,7 @@ ingame: switchLayers: 레이어 전환 buildingPlacement: cycleBuildingVariants: 키를 눌러 변형 전환 - hotkeyLabel: "Hotkey: " + hotkeyLabel: "단축키: " infoTexts: speed: 속도 range: 최대 거리 @@ -266,13 +273,33 @@ ingame: hints: 1_1_extractor: 원형 도형을 추출하기 위해 그 위에 추출기를 선택한 뒤 배치하여 추출하세요! - 1_2_conveyor: "Connect the extractor with a conveyor belt to - your hub!

Tip: Click and drag the belt - with your mouse!" - 1_3_expand: "This is NOT an idle game! Build more extractors - and belts to finish the goal quicker.

Tip: Hold - SHIFT to place multiple extractors, and use - R to rotate them." + 1_2_conveyor: "이제 컨베이어 벨트를 추출기와 허브를 서로 연결하세요!

팁: 벨트를 + 마우스로 클릭한 뒤 드래그하세요!" + 1_3_expand: "이 게임은 방치형 게임이 아닙니다! 더 많은 추출기와 벨트를 만들어 지정된 목표를 빨리 + 달성하세요.

팁: SHIFT 키를 누른 상태에서는 빠르게 배치할 수 + 있고, R 키를 눌러 회전할 수 있습니다." + 2_1_place_cutter: "이제 절단기를 배치하여 원형 도형을 둘로 자르세요!

+ 추신: 절단기는 방향에 관계 없이 항상 수직으로 자릅니다." + 2_2_place_trash: 절단기가 막히거나 멈출 수 있습니다!

+ 휴지통을 사용하여 현재 필요없는 쓰레기 도형 (!)을 + 제거하세요. + 2_3_more_cutters: "잘하셨습니다! 느린 처리 속도를 보완하기 위해 절단기를 두 개 + 이상 배치해보세요!

추신: 상단 숫자 단축키 (0~9)를 사용하여 + 건물을 빠르게 선택할 수 있습니다!" + 3_1_rectangles: "이제 사각형 도형을 추출해 볼까요! 추출기 네 개를 + 배치하고 허브와 연결하세요.

추신: 긴 벨트 한 줄을 + 간단히 만들려면 SHIFT 키를 누른 채 드래그하세요!" + 21_1_place_quad_painter: 4단 색칠기를 배치하여 흰색과 + 빨간색이 칠해진 원형 + 도형을 만들어보세요! + 21_2_switch_to_wires: E 키를 눌러 전선 레이어 + 로 전환하세요!

그 후 색칠기의 네 입력 부분을 + 모두 케이블로 연결하세요! + 21_3_place_button: 훌륭해요! 이제 스위치를 배치하고 전선으로 + 연결하세요! + 21_4_press_button: "스위치를 눌러
참 신호를 내보내 + 색칠기를 활성화하세요. 추신: 모든 입력을 연결할 필요는 없습니다! + 지금은 두 개만 연결하세요." colors: red: 빨간색 green: 초록색 @@ -284,13 +311,13 @@ ingame: black: 검은색 uncolored: 회색 shapeViewer: - title: 층 + title: 레이어 empty: 비었음 copyKey: 키 복사하기 connectedMiners: one_miner: 추출기 1 개 n_miners: 추출기 개 - limited_items: 개로 제한됨 + limited_items: 까지가 한계임 watermark: title: 체험판 버전 desc: 정식 버전의 장점을 보려면 여기를 클릭하세요! @@ -510,12 +537,10 @@ buildings: storyRewards: reward_cutter_and_trash: title: 절단기 - desc: You just unlocked the cutter, which cuts shapes in half - from top to bottom regardless of its - orientation!

Be sure to get rid of the waste, or - otherwise it will clog and stall - For this purpose - I have given you the trash, which destroys - everything you put into it! + desc: 절단기가 잠금 해제되었습니다! 절단기는 들어오는 도형이 어떤 모양을 하고 있던 수직으로 잘라 + 반으로 나눕니다!

쓰지 않는 도형은 쓰레기로 처리하세요, 그렇지 않으면 + 작동을 멈출 것입니다! 이러한 목적을 위해 휴지통도 함께 + 지급되었습니다. 휴지통에 들어간 것은 모두 파괴됩니다! reward_rotater: title: 회전기 desc: 회전기가 잠금 해제되었습니다! 회전기는 들어오는 도형을 시계 방향으로 90도 회전시켜줍니다. @@ -580,9 +605,8 @@ storyRewards: 기능을 사용할 수 있습니다! (방금 당신이 만든 것입니다.) no_reward: title: 다음 레벨 - desc: "This level gave you no reward, but the next one will!

PS: Better - not destroy your existing factory - You'll need all - those shapes later to unlock upgrades!" + desc: "이번 레벨의 보상은 없네요. 대신 다음 레벨에서 줄겁니다!

추신: 기존 공장을 파괴하지는 마세요. 후에 + 업그레이드 잠금 해제되면 기존의 모든 도형이 필요합니다!" no_reward_freeplay: title: 다음 레벨 desc: 축하드립니다! @@ -625,12 +649,12 @@ storyRewards: - 평소처럼 게임을 진행합니다.

어떤 방식으로든, 재미있게 게임을 플레이해주시길 바랍니다! reward_wires_painter_and_levers: title: 전선과 4단 색칠기 - desc: "You just unlocked the Wires Layer: It is a separate - layer on top of the regular layer and introduces a lot of new - mechanics!

For the beginning I unlocked you the Quad - Painter - Connect the slots you would like to paint with on - the wires layer!

To switch to the wires layer, press - E." + desc: "전선 레이어가 잠금 해제되었습니다! 전선 레이어는 + 일반 레이어 위에 존재하는 별도의 레이어로, 이를 통한 다양하고 새로운 + 메커니즘을 소개하겠습니다!

우선 4단 색칠기가 + 잠금 해제되었습니다. 전선 레이어에서 색칠하고 싶은 슬롯에 전선을 연결하세요! + 전선 레이어로 전환하려면 E 키를 누르세요.

+ 추신: 설정에서 힌트를 활성화하여 전선 튜토리얼을 활성화하세요!" reward_filter: title: 아이템 선별기 desc: 아이템 선별기가 잠금 해제되었습니다! 전선 레이어의 신호와 일치하는지에 대한 여부로 아이템을 위쪽 @@ -773,14 +797,15 @@ settings: title: 화면 가장자리 패닝 description: 커서를 화면 가장자리로 옮기면 스크롤되어 지도를 이동할 수 있습니다. 스크롤 속도는 이동 속도 설정에 따릅니다. zoomToCursor: - title: Zoom towards Cursor - description: If activated the zoom will happen in the direction of your mouse - position, otherwise in the middle of the screen. + title: 커서를 기준으로 줌 + description: 활성화할 경우 화면 줌 인 아웃이 마우스 커서가 있는 지점을 기준이 되며, 아닐 경우 화면 중앙이 기준이 됩니다. + mapResourcesScale: + title: 지도 자원 크기 + description: 지도를 축소할 때 나타나는 도형의 크기를 제어합니다. rangeSliderPercentage: % keybindings: title: 조작법 - hint: "Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different - placement options." + hint: "팁: CTRL, SHIFT, ALT를 적절히 사용하세요! 건물을 배치할 때 유용합니다." resetKeybindings: 초기화 categoryLabels: general: 애플리케이션 @@ -829,7 +854,7 @@ keybindings: exportScreenshot: 공장 전체를 이미지로 내보내기 mapMoveFaster: 더 빠르게 움직이기 lockBeltDirection: 벨트 계획기 활성화 - switchDirectionLockSide: "Planner: Switch side" + switchDirectionLockSide: "계획기: 방향 바꾸기" pipette: 피펫 menuClose: 메뉴 닫기 switchLayers: 레이어 전환 @@ -848,7 +873,7 @@ keybindings: analyzer: 도형 분석기 comparator: 비교기 item_producer: 아이템 생성기 (샌드박스) - copyWireValue: "Wires: Copy value below cursor" + copyWireValue: "전선: 커서 아래 값 복사" backwardsModifier: "Modifier: Cycle backwards" about: title: 게임 정보 @@ -868,7 +893,7 @@ changelog: demo: features: restoringGames: 게임 세이브 파일 복원 하기 - importingGames: 게임 세이브 파일 불러오기 + importingGames: 게임 세이브 파일 가져오기 oneGameLimit: 게임 세이브 파일 최대 1개 customizeKeybindings: 조작법 설정하기 exportingBase: 공장 전체를 이미지로 내보내기 @@ -892,8 +917,7 @@ tips: - 최대 레벨에서, 한 줄의 벨트를 채우기 위해 다섯 개의 추출기가 필요합니다. - 터널을 잊지 마세요! - 완벽한 효율성을 위해 굳이 아이템을 균등하게 배분할 필요는 없습니다. - - Holding SHIFT will activate the belt planner, letting you place - long lines of belts easily. + - SHIFT키를 누르면 벨트 계획기가 활성화되어 긴 길이의 벨트 한 줄을 쉽게 배치할 수 있습니다. - 절단기는 들어오는 도형과 배치된 절단기의 방향에 관계 없이, 언제나 수직으로 자릅니다. - 흰색은 세 가지의 색소를 혼합해야 합니다. - 저장고의 양쪽 출력 중 왼쪽 출력이 가장 우선됩니다. diff --git a/translations/base-lt.yaml b/translations/base-lt.yaml index a4f8f457..c90fa45a 100644 --- a/translations/base-lt.yaml +++ b/translations/base-lt.yaml @@ -197,6 +197,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Move @@ -291,6 +299,30 @@ ingame: and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." colors: red: Red green: Green @@ -694,7 +726,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -864,6 +897,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Keybindings diff --git a/translations/base-nl.yaml b/translations/base-nl.yaml index 4e92b8e2..b8781ba9 100644 --- a/translations/base-nl.yaml +++ b/translations/base-nl.yaml @@ -2,27 +2,28 @@ steamPage: shortText: shapez.io is een spel dat draait om het bouwen van fabrieken voor het produceren en automatiseren van steeds complexere vormen in een oneindig groot speelveld. - discordLinkShort: Officiële Discord + discordLinkShort: Officiële Discord server intro: >- Shapez.io is een spel waarin je fabrieken moet bouwen voor de automatische productie van geometrische vormen. Naarmate het spel vordert, worden de vormen complexer, en moet je uitbreiden in het oneindige speelveld. - En als dat nog niet genoeg is moet je ook nog eens steeds me produceren om aan de vraag te kunnen voldoen. Het enige dat helpt is uitbreiden! + En als dat nog niet genoeg is moet je ook nog eens steeds meer produceren om aan de vraag te kunnen voldoen. Het enige dat helpt is uitbreiden! Ondanks het feit dat je in het begin alleen vormen maakt, komt er het punt waarop je ze moet kleuren. Deze kleuren moet je vinden en mengen! - Door het spel op Steam te kopen kun je de volledige versie spelen. Je kunt echter ook een demo versie spelen op shapez.io en later beslissen. + Door het spel op Steam te kopen kun je de volledige versie spelen. Je kunt echter ook een demo versie spelen op shapez.io en later beslissen + om over te schakelen zonder voortgang te verliezen. title_advantages: Standalone Voordelen advantages: - 12 Nieuwe Levels met een totaal van 26 levels - 18 Nieuwe Gebouwen voor een volledig geautomatiseerde fabriek! - 20 Upgrade Levels voor vele speeluren! - Draden Update voor een volledig nieuwe dimensie! - - Dark Mode! - - Ongelimiteerde Saves - - Ongelimiteerde Markers + - Dark Mode Donkere modus! + - Oneindig veel werelden. + - Oneindig veel Markers - Help mij! ❤️ title_future: Geplande Content planned: @@ -40,7 +41,7 @@ steamPage: roadmap: Roadmap subreddit: Subreddit source_code: Source code (GitHub) - translate: Help vertalen + translate: Hulp met vertalen text_open_source: >- Iedereen mag meewerken. Ik ben actief betrokken in de community en probeer alle suggesties en feedback te beoordelen als dat nodig is. @@ -56,9 +57,9 @@ global: millions: M billions: B trillions: T - infinite: inf + infinite: ∞ time: - oneSecondAgo: één seconde geleden + oneSecondAgo: een seconde geleden xSecondsAgo: seconden geleden oneMinuteAgo: een minuut geleden xMinutesAgo: minuten geleden @@ -86,12 +87,12 @@ mainMenu: importSavegame: Importeren openSourceHint: Dit spel is open source! discordLink: Officiële Discord-server (Engelstalig) - helpTranslate: Help met vertalen! + helpTranslate: Help ons met vertalen! browserWarning: Sorry, maar dit spel draait langzaam in je huidige browser! Koop de standalone versie of download chrome voor de volledige ervaring. savegameLevel: Level savegameLevelUnknown: Onbekend Level - continue: Verder + continue: Ga verder newGame: Nieuw Spel madeBy: Gemaakt door subreddit: Reddit @@ -119,10 +120,10 @@ dialogs: title: Het spel is kapot text: "Het laden van je savegame is mislukt:" confirmSavegameDelete: - title: Bevestig verwijderen - text: Are you sure you want to delete the following game?

- '' at level

This can not be - undone! + title: Bevestig het verwijderen + text: Ben je zeker dat je het volgende spel wil verwijderen?

+ '' op niveau

Dit kan niet ongedaan worden + gemaakt! savegameDeletionError: title: Verwijderen mislukt text: "Het verwijderen van de savegame is mislukt:" @@ -177,9 +178,9 @@ dialogs: van lopende banden om te draaien wanneer je ze plaatst.
" createMarker: title: Nieuwe markering - desc: Give it a meaningful name, you can also include a short - key of a shape (Which you can generate here) - titleEdit: Edit Marker + desc: Geef het een nuttige naam, Je kan ook een snel + toets van een vorm gebruiken (die je here kan genereren). + titleEdit: Bewerk markering markerDemoLimit: desc: Je kunt maar twee markeringen plaatsen in de demo. Koop de standalone voor een ongelimiteerde hoeveelheid markeringen! @@ -197,13 +198,20 @@ dialogs: desc: Je kunt het je niet veroorloven om de selectie te plakken! Weet je zeker dat je het wil knippen? editSignal: - title: Set Signal + title: Stel het signaal in. descItems: "Kies een ingesteld item:" - descShortKey: ... of voer de short key van een vorm (Die je - hier kunt vinden) in. + descShortKey: ... of voer de hotkey in van een vorm (Die je + hier kunt vinden). renameSavegame: title: Hernoem opgeslagen spel desc: Geef je opgeslagen spel een nieuwe naam. + tutorialVideoAvailable: + title: Tutorial Beschikbaar + desc: Er is een tutorial video beschikbaar voor dit level! Zou je het willen bekijken? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: Er is een tutorial beschikbaar voor dit level, maar het is alleen + beschikbaar in het Engels. Zou je het toch graag kijken? ingame: keybindingsOverlay: moveMap: Beweeg speelveld @@ -232,8 +240,8 @@ ingame: speed: Snelheid range: Bereik storage: Opslag - oneItemPerSecond: 1 voorwerp / s - itemsPerSecond: voorwerpen / s + oneItemPerSecond: 1 voorwerp/s + itemsPerSecond: voorwerpen/s itemsPerSecondDouble: (x2) tiles: tegels levelCompleteNotification: @@ -265,9 +273,9 @@ ingame: description: Geeft alle vormen weer die in de HUB worden bezorgd. noShapesProduced: Er zijn nog geen vormen geproduceerd. shapesDisplayUnits: - second: / s - minute: / m - hour: / h + second: /s + minute: /m + hour: /h settingsMenu: playtime: Speeltijd buildingsPlaced: Gebouwen @@ -299,6 +307,30 @@ ingame: en lopende banden om het doel sneller te behalen.

Tip: Houd SHIFT ingedrukt om meerdere ontginners te plaatsen en gebruik R om ze te draaien." + 2_1_place_cutter: "Plaats nu een Knipper om de cirkels in twee te knippen + halves!

PS: De knipper knipt altijd van boven naar + onder ongeacht zijn oriëntatie." + 2_2_place_trash: De knipper kan vormen verstoppen en bijhouden!

Gebruik een + vuilbak om van het (!) niet + nodige afval vanaf te geraken. + 2_3_more_cutters: "Goed gedaan! Plaats nu 2 extra knippers om dit traag + process te versnellen!

PS: Gebruik de 0-9 + sneltoetsen om gebouwen sneller te selecteren." + 3_1_rectangles: "Laten we nu rechthoeken ontginnen! Bouw 4 + ontginners en verbind ze met de lever.

PS: + Houd SHIFT Ingedrukt terwijl je lopende banden plaats + om ze te plannen!" + 21_1_place_quad_painter: Plaats de quad painter en krijg een paar + cirkels in witte en + rode kleur! + 21_2_switch_to_wires: Schakel naar de draden laag door te duwen op + E!

verbind daarna alle + inputs van de verver met kabels! + 21_3_place_button: Mooi! Plaats nu een schakelaar en verbind het + met draden! + 21_4_press_button: "Druk op de schakelaar om het een Juist signaal door + te geven en de verver te activeren.

PS: Je + moet niet alle inputs verbinden! Probeer er eens 2." colors: red: Rood green: Groen @@ -320,7 +352,7 @@ ingame: watermark: title: Demo versie desc: Klik hier om het spel op Steam te bekijken! - get_on_steam: Get on steam + get_on_steam: Krijg het op Steam standaloneAdvantages: title: Koop de volledige versie! no_thanks: Nee, bedankt! @@ -398,10 +430,10 @@ buildings: name: Roteerder description: Draait vormen 90 graden met de klok mee. ccw: - name: Roteerder (andersom) + name: Roteerder (omgekeerd) description: Draait vormen 90 graden tegen de klok in. rotate180: - name: Roteerder (180) + name: Roteerder (180°) description: Draait vormen 180 graden. stacker: default: @@ -435,7 +467,7 @@ buildings: name: Vuilnisbak description: Accepteert input van alle kanten en vernietigt het. Voor altijd. hub: - deliver: Lever + deliver: Lever in toUnlock: om te ontgrendelen levelShortcut: LVL endOfDemo: End of Demo @@ -458,11 +490,11 @@ buildings: name: Samenvoeger description: Voeg 2 lopende banden samen. splitter: - name: Splitter (compact) - description: Split een lopende band in tweeën. + name: Splitser (compact) + description: Splits een lopende band in tweeën. splitter-inverse: - name: Splitter - description: Split een lopende band in tweeën. + name: Splitser + description: Splits een lopende band in tweeën. storage: default: name: Opslag @@ -485,18 +517,18 @@ buildings: default: name: AND poort description: Zend een 1 uit als beide invoeren hetzelfde zijn. (Kan een vorm, - kleur of boolean (1 / 0) zijn) + kleur of boolean (1/0) zijn) not: name: NOT poort description: Zend een 1 uit als de invoer een 0 is. xor: name: XOR poort description: Zend een 1 uit als de invoeren niet hetzelfde zijn. (Kan een vorm, - kleur of boolean (1 / 0) zijn) + kleur of boolean (1/0) zijn) or: - name: OR gate + name: OR poort description: Zend een 1 uit als de invoeren wel of niet hetzelfde zijn, maar - niet uit zijn. (Kan een vorm, kleur of boolean (1 / 0) zijn) + niet uit zijn. (Kan een vorm, kleur of boolean (1/0) zijn) transistor: default: name: Transistor @@ -513,7 +545,7 @@ buildings: default: name: Scherm description: Verbind een signaal met het scherm om de soort weer te geven. Kan - een vorm, kleur of boolean (1 / 0) zijn. + een vorm, kleur of boolean (1/0) zijn. reader: default: name: Lopende band lezer @@ -528,7 +560,7 @@ buildings: default: name: Vergelijker description: Zend 1 uit als beiden invoeren gelijk zijn, kunnen vormen, kleuren - of booleans (1 / 0) zijn + of booleans (1/0) zijn virtual_processor: default: name: Virtuele Snijder @@ -555,12 +587,12 @@ buildings: storyRewards: reward_cutter_and_trash: title: Vormen Knippen - desc: You just unlocked the cutter, which cuts shapes in half - from top to bottom regardless of its - orientation!

Be sure to get rid of the waste, or - otherwise it will clog and stall - For this purpose - I have given you the trash, which destroys - everything you put into it! + desc: Je hebt juist de knipper ontgrendeld, die vormen in de helft + kan knippen van boven naar onder ongeacht zijn rotatie + !

Wees zeker dat je het afval weggooit, want + anders zal het vastlopen - Voor deze reden + heb ik je de vuilbak gegeven, die alles + vernietigd wat je erin laat stromen! reward_rotater: title: Roteren desc: De roteerder is ontgrendeld - Het draait vormen 90 graden @@ -585,10 +617,10 @@ storyRewards: worden dan wordt het rechtervoorwerp boven op het linker geplaatst! reward_splitter: - title: Splitter/samenvoeger - desc: You have unlocked a splitter variant of the - balancer - It accepts one input and splits them - into two! + title: Splitser/samenvoeger + desc: Je hebt de splitser ontgrendeld, een variant van de + samenvoeger - Het accepteert 1 input en verdeelt het + in 2! reward_tunnel: title: Tunnel desc: De tunnel is ontgrendeld - Je kunt nu voorwerpen onder @@ -601,15 +633,15 @@ storyRewards: wisselen
! reward_miner_chainable: title: Ketting-ontginner - desc: "You have unlocked the chained extractor! It can - forward its resources to other extractors so you - can more efficiently extract resources!

PS: The old - extractor has been replaced in your toolbar now!" + desc: "Je hebt de Ketting-ontginner ontgrendeld! Het kan + zijn materialen ontginnen via andere ontginners zodat je + meer materialen tegelijkertijd kan ontginnen!

PS: De oude + ontginner is vervangen in je toolbar!" reward_underground_belt_tier_2: title: Tunnel Niveau II - desc: You have unlocked a new variant of the tunnel - It has a - bigger range, and you can also mix-n-match those - tunnels now! + desc: Je hebt een nieuwe variant van de tunnel ontgrendeld. - Het heeft een + groter bereik, en je kan nu ook die tunnels mixen + over en onder elkaar! reward_cutter_quad: title: Quad Knippen desc: Je hebt een variant van de knipper ontgrendeld - Dit @@ -621,18 +653,18 @@ storyRewards: tegelijk
met één kleur in plaats van twee! reward_storage: title: Opslagbuffer - desc: You have unlocked the storage building - It allows you to - store items up to a given capacity!

It priorities the left - output, so you can also use it as an overflow gate! + desc: Je hebt een variant van de opslag ontgrendeld - Het laat je toe om + vormen op te slagen tot een bepaalde capaciteit!

Het verkiest de linkse + output, dus je kan het altijd gebruiken als een overloop poort! reward_freeplay: title: Vrij spel - desc: You did it! You unlocked the free-play mode! This means - that shapes are now randomly generated!

- Since the hub will require a throughput from now - on, I highly recommend to build a machine which automatically - delivers the requested shape!

The HUB outputs the requested - shape on the wires layer, so all you have to do is to analyze it and - automatically configure your factory based on that. + desc: Je hebt het gedaan! Je hebt de free-play modus ontgrendeld! Dit betekend + dat vormen nu willekeurig gegenereerd worden!

+ Omdat de hub vanaf nu een bepaald aantal vormen per seconden nodig heeft, + Raad ik echt aan een machine te maken die automatisch + de juiste vormen genereert!

De HUB geeft de vorm die je nodig hebt + op de tweede laag met draden, dus alles wat je moet doen is dat analyseren + en je fabriek dat automatisch laten maken op basis van dat. reward_blueprints: title: Blauwdrukken desc: Je kunt nu delen van je fabriek kopiëren en plakken! @@ -653,9 +685,9 @@ storyRewards: uitgebereid in de standalone! reward_balancer: title: Verdeler - desc: The multifunctional balancer has been unlocked - It can - be used to build bigger factories by splitting and merging - items onto multiple belts! + desc: De multifunctionele verdeler is nu ontgrendeld - Het kan + gebruikt worden om grotere te knippen en plakken vormen op meerdere + lopende banden te zetten reward_merger: title: Compacte samenvoeger desc: Je hebt een variant op de samenvoeger van de @@ -672,17 +704,17 @@ storyRewards: je een item op de band 180 graden draaien! reward_display: title: Scherm - desc: "You have unlocked the Display - Connect a signal on the - wires layer to visualize it!

PS: Did you notice the belt - reader and storage output their last read item? Try showing it on a - display!" + desc: "Je hebt het scherm ontgrendeld - Verbind een signaal met de + laag van draden om het te visualiseren!

PS: Heb je gezien dat de lopende band + lezer en opslag hun laatste vorm weergeven? Probeer het te tonen op + een scherm!" reward_constant_signal: title: Constante Signaal desc: Je hebt het constante signaal vrijgespeeld op de kabel dimensie! Dit gebouw is handig in samenwerking met item filters.

Het constante signaal kan een vorm, kleur of - boolean (1 / 0) zijn. + boolean (1/0) zijn. reward_logic_gates: title: Logische poorten desc: Je hebt de logische poorten vrijgespeeld! Misschien word @@ -691,28 +723,29 @@ storyRewards: uitvoeren.

Als bonus krijg je ook nog een transistor van mij! reward_virtual_processing: - title: Virtual Processing - desc: I just gave a whole bunch of new buildings which allow you to - simulate the processing of shapes!

You can - now simulate a cutter, rotater, stacker and more on the wires layer! - With this you now have three options to continue the game:

- - Build an automated machine to create any possible - shape requested by the HUB (I recommend to try it!).

- Build - something cool with wires.

- Continue to play - regulary.

Whatever you choose, remember to have fun! + title: VIrtuele verwerking + desc: Ik heb juist een hele hoop nieuwe gebouwen toegevoegd die je toetstaan om + het process van vormen te stimuleren!

Je kan + nu de knipper, draaier, stapelaar en meer op de dradenlaag stimuleren! + Met dit heb je nu 3 opties om verder te gaan met het spel:

- + Bouw een automatische fabriek om eender welke mogelijke + vorm te maken gebraagd door de HUB (Ik raad aan dit te proberen!).

- Bouw + iets cool met draden.

- Ga verder met normaal + spelen.

Wat je ook kiest, onthoud dat je plezier hoort te hebben! reward_wires_painter_and_levers: title: Wires & Quad Painter - desc: "You just unlocked the Wires Layer: It is a separate - layer on top of the regular layer and introduces a lot of new - mechanics!

For the beginning I unlocked you the Quad - Painter - Connect the slots you would like to paint with on - the wires layer!

To switch to the wires layer, press - E." + desc: "Je hebt juist de draden laag ontgrendeld: Het is een aparte + laag boven op de huidige laag en introduceert heel veel nieuwe + manieren om te spelen!

Voor het begin heb ik voor jou de Quad + Painter ontgrendeld - Verbind de gleuf waarin je wilt verven op + de draden laag!

Om over te schakelen naar de draden laag, Duw op + E.

PS: Zet hints aan in + de instellingen om de draden tutorial te activeren!" reward_filter: title: Item Filter desc: Je hebt de Item Filter vrijgespeeld! Items worden naar rechts of naar boven gestuurd, afhankelijk van de invoer.

Er - kan ook een boolean (1 / 0) worden ingevoerd om de filter in en uit + kan ook een boolean (1/0) worden ingevoerd om de filter in en uit te schakelen. reward_demo_end: title: Einde van de Demo @@ -723,10 +756,10 @@ settings: general: Algemeen userInterface: Opmaak advanced: Geavanceerd - performance: Performance + performance: Prestatie versionBadges: dev: Ontwikkeling - staging: Staging + staging: Positie prod: Productie buildDate: gebouwd labels: @@ -766,12 +799,12 @@ settings: description: Wanneer dit aan staat wordt alle muziek uitgeschakeld. theme: title: Donkere modus - description: Kies de gewenste weergave (licht / donker). + description: Kies de gewenste weergave (licht/donker). themes: dark: Donker light: Licht refreshRate: - title: Simulation Target + title: Simulatie doel description: Wanneer je een 144 hz monitor hebt, verander de refresh rate hier zodat het spel naar behoren weer blijft geven. Dit verlaagt mogelijk de FPS als je computer te traag is. @@ -835,11 +868,11 @@ settings: laatst geplaatst hebt. Dit kan handig zijn wanneer je vaak tussen verschillende soorten gebouwen wisselt. soundVolume: - title: Sound Volume - description: Set the volume for sound effects + title: Geluidsvolume + description: Stel het volume voor geluidseffecten in. musicVolume: - title: Music Volume - description: Set the volume for music + title: Muziekvolume + description: Stel het volume voor muziek in. lowQualityMapResources: title: Lage kwaliteit van resources description: Versimpeldde resources op de wereld wanneer ingezoomd om de @@ -878,9 +911,13 @@ settings: Plaats de cursor boven, rechts, links of onder om daar naartoe te bewegen. zoomToCursor: - title: Zoom towards Cursor - description: If activated the zoom will happen in the direction of your mouse - position, otherwise in the middle of the screen. + title: Zoom naar de Muis + description: "Wanneer geactiveert: de zoom zal gebeuren in de richting van je + muispositie, anders in het midden van het scherm." + mapResourcesScale: + title: Kaartbronnen schaal + description: Controleert de grote van de vormen op het map overzicht (wanneer je + uitzoomt). rangeSliderPercentage: % keybindings: title: Sneltoetsen @@ -976,7 +1013,7 @@ demo: restoringGames: Savegames terughalen importingGames: Savegames importeren oneGameLimit: Gelimiteerd tot één savegame - customizeKeybindings: Custom sneltoetsen + customizeKeybindings: Aangepaste sneltoetsen exportingBase: Exporteer volledige basis als afbeelding settingNotAvailable: Niet beschikbaar in de demo. tips: diff --git a/translations/base-no.yaml b/translations/base-no.yaml index 70865d5f..289a1d21 100644 --- a/translations/base-no.yaml +++ b/translations/base-no.yaml @@ -203,6 +203,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Beveg @@ -297,6 +305,30 @@ ingame: og belter for å nå målet raskere.

Tips: Hold SHIFT for å plassere flere utdragere, og bruk R for å rotere dem." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." colors: red: Rød green: Grønn @@ -708,7 +740,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -880,6 +913,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Hurtigtaster diff --git a/translations/base-pl.yaml b/translations/base-pl.yaml index 7eb1732f..510815c2 100644 --- a/translations/base-pl.yaml +++ b/translations/base-pl.yaml @@ -206,6 +206,14 @@ dialogs: renameSavegame: title: Zmień nazwę zapisu gry desc: Tutaj możesz zmienić nazwę zapisu gry. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Ruch @@ -315,6 +323,30 @@ ingame: szybciej.

Porada: Przytrzymaj SHIFT, by postawić wiele ekstraktorów. Naciśnij R, by je obracać.' + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 ekstraktor n_miners: ekstraktorów @@ -717,12 +749,13 @@ storyRewards: bawić! reward_wires_painter_and_levers: title: Przewody i poczwórny malarz - desc: "Właśnie odblokowałeś Warstwę przewodów: Jest to osobna - warstwa położnoa na istniejącej, która wprowadza wiele nowych - mechanik!

Na początek dałem ci Poczwórnego - Malarza - Podłącz ćwiartki, które chcesz pomalować na - warstwie przewodów!

By przełączyć się na warstwę przewodów, - wciśnij E." + desc: "You just unlocked the Wires Layer: It is a separate + layer on top of the regular layer and introduces a lot of new + mechanics!

For the beginning I unlocked you the Quad + Painter - Connect the slots you would like to paint with on + the wires layer!

To switch to the wires layer, press + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Filtr przedmiotów desc: Właśnie odblokowałeś Filtr Przedmiotów! Będzie on @@ -892,6 +925,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Klawiszologia diff --git a/translations/base-pt-BR.yaml b/translations/base-pt-BR.yaml index bf3864bd..7847f8ac 100644 --- a/translations/base-pt-BR.yaml +++ b/translations/base-pt-BR.yaml @@ -198,6 +198,14 @@ dialogs: renameSavegame: title: Renomear Save desc: Você pode renomear seu save aqui. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Mover @@ -307,6 +315,30 @@ ingame: esteiras para concluir o objetivo mais rapidamente.

Dica, segure SHIFT para colocar vários extratores e use R para girá-los. + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 Extrator n_miners: Extratores @@ -707,12 +739,13 @@ storyRewards: lembre de se divertir! reward_wires_painter_and_levers: title: Fios e Pintor Quádruplo - desc: "Você acabou de desbloquear o Plano de Fiação: Ele é um - plano separado no topo do plano comum e introduz um monte de novas - mecânicas!

Para começar eu te dou o Pintor - Quádruplo - Conecte a entrada que você quer que seja - colorida com o plano da fiação!

Para mudar de plano, aperte - E." + desc: "You just unlocked the Wires Layer: It is a separate + layer on top of the regular layer and introduces a lot of new + mechanics!

For the beginning I unlocked you the Quad + Painter - Connect the slots you would like to paint with on + the wires layer!

To switch to the wires layer, press + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Filtro de Itens desc: Você desbloqueou o Filtro de Itens! Ele irá rotear os @@ -889,6 +922,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Controles diff --git a/translations/base-pt-PT.yaml b/translations/base-pt-PT.yaml index 5cee132d..031637d3 100644 --- a/translations/base-pt-PT.yaml +++ b/translations/base-pt-PT.yaml @@ -206,6 +206,14 @@ dialogs: renameSavegame: title: Renomear Savegame desc: Podes renomear o teu savegame aqui. + tutorialVideoAvailable: + title: Tutorial Disponível + desc: Existe um vídeo de tutorial disponível para este nível! Gostarias de + o ver? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Disponível + desc: Existe um vídeo de tutorial disponível para este nível, mas apenas + está disponível em Inglês. Gostarias de o ver? ingame: keybindingsOverlay: moveMap: Mover @@ -300,6 +308,30 @@ ingame: e tapetes para atingir o objetivo mais rapidamente.

Dica: Pressiona SHIFT para colocar vários extratores, e usa R para os rodar." + 2_1_place_cutter: "Agora coloca um Cortador para cortares os circulos + em duas metades!

PS: O cortador corta sempre de cima para + baixo independentemente da sua orientação" + 2_2_place_trash: O cortador pode encravar e parar!

Usa + um lixo para de livrares do atual (!) não + é necessário desperdício. + 2_3_more_cutters: "Bom trabalho! Agora colocamais 2 cortadores para acelerades + este progresso lento!

PS: Usa os atalhos + 0-9 para acederes às contruções mais rapidamente!" + 3_1_rectangles: "Agora vamos extrair alguns retângulos! Constrói 4 + extratores e conecta-os ao edifício central.

PS: + Pressiona SHIFT enquanto arrastas um tapete rolante + para ativares o planeador de tapetes!" + 21_1_place_quad_painter: Coloca o pintor quádruplo e arranja alguns + círculos, cores branca e + vermelha! + 21_2_switch_to_wires: Troca para a camada de fios pressionando + E!

A seguir conecta todas as quatro + entradas do pintor com fios! + 21_3_place_button: Fantástico! Agora coloca o Interruptor e conecta-o + com os fios! + 21_4_press_button: "Pressiona o interruptor para que ele emita um + sinal verdadeiro, isso irá ativar o pintor.

PS: Tu + não tens de conectar todas as entradas! Tenta conectar apenas duas." colors: red: Vermelho green: Verde @@ -719,9 +751,10 @@ storyRewards: desc: "Desbloquaste a Camada de Fios: É uma camada separada no topo da camada normal e introduz um monte de novas mecânicas!

Para o inicio eu dei-te o Pintor - Quádruplo - Conecta as entradasque queres pintar na camada + Quádruplo - Conecta as entradas que queres pintar na camada de fios!

Para trocares para a camada de fios, pressiona a - tecla E." + tecla E.

PS: Ativa as dicas nas + definições para ativares o tutorial de fios!" reward_filter: title: Filtro de Itens desc: Desbloquaste o Filtro de Itens! Vai mandar itens ou para @@ -897,6 +930,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Atalhos @@ -996,22 +1033,22 @@ demo: exportingBase: Exportar base como uma imagem settingNotAvailable: Não disponível no Demo. tips: - - O edifício central aceita qualquer entrada, não apenas a forma atual! + - O edifício central aceita qualquer entrada, não apenas a da forma atual! - Tem a certeza que as tuas fábricas são modulares - vai valer a pena! - - Não construas demasiado perto do edifício, ou vai ser um grande caos! + - Não construas demasiado perto do edifício, ou será um grande caos! - Se empilhar não funciona, tenta trocar as entradas. - Podes alternar a direção do planeador de tapete rolante ao pressionar R. - - Ao segurar CTRL podes arrastar tapetes rolantes sem auto-orientação. + - Ao pressionares CTRL podes arrastar tapetes rolantes sem auto-orientação. - Os rácios continuam os mesmos, desde que todos os upgrades estejam no mesmo Nível. - Execução em série é mais eficiente que em paralelo. - - Vais desbloquear mais variações de edifícios mais tarde no jogo! - - Podes usar T para trocar entre as diferentes variantes. + - Vais desbloquear mais variações de edifícios, mais tarde no jogo! + - Podes usar T para trocares entre as diferentes variantes. - Simetria é a solução! - - Podes entrelaçar diferentes níveis de túneis. + - Podes entrelaçar diferentes tipos de túneis. - Tenta construir fábricas compactas - vai valer a pena! - - O pintor tem uma variante espelhada que podes selectionar com T + - O pintor tem uma variante espelhada que podes selecionar com T - Ter os rácios de edifícios corretos vai maximizar a eficiência. - No nível máximo, 5 extratores vão encher um tapete. - Não te esqueças dos túneis! @@ -1029,31 +1066,31 @@ tips: - As formas que estão mais longes do edifício central são mais complexas. - As Máquinas têm uma velocidade limitada, divide-as para eficiência máxima. - Usa balanceadores para maximizar a tua eficiência. - - Organização é importante. Tenta não cruzar tapetes demasiado. - - Planeja antecipadamente, ou vai ser um grande caos! - - Não removas as tuas fábricas antigas! Vais precisar delas para desbloquear + - Organização é importante. Tenta não cruzar demasiados tapetes. + - Planeia antecipadamente, ou vai ser um grande caos! + - Não removas as tuas fábricas antigas! Vais precisar delas para desbloqueares upgrades. - - Tenta superar o nível 18 sozinho sem procurar ajuda! + - Tenta superar o nível 20 sozinho sem procurar ajuda! - Não complicas as coisas, tenta continuar simples e irás muito longe. - - Talvez precises de reusar fábricas mais tarde no jogo. Planeia as tuas + - Talvez precises de reutilizar fábricas, mais tarde no jogo. Planeia as tuas fábricas para serem reutilizáveis. - Às vezes, podes encontrar uma forma necessária no mapa sem criar-la com empilhadoras. - Moinhos de vento e cataventos completos nunca aparecem naturalmente. - - Pinta as tuas formas antes de cortar-las para eficiência máxima. - - Com módulos, o espaço é apenas uma percepção; uma preocupação para pessoas + - Pinta as tuas formas antes de as cortares para eficiência máxima. + - Com módulos, o espaço é apenas uma perceção; uma preocupação para pessoas mortais. - Faz uma fábrica de diagramas separada. São importantes para módulos. - Dá uma olhada ao misturador de cores, e as tuas questões serão respondidas. - - Use CTRL + Clique para selecionar uma área. + - Usa CTRL + Clique para selecionar uma área. - Construir demasiado perto do edifício central pode ficar no caminho de projetos futuros. - - O ícone de alfinete perto duma forma na lista de upgrades vai afixar-la ao + - O ícone de alfinete perto duma forma na lista de upgrades vai afixa-la ao ecrã. - - Junta todas as cores primárias juntas para fazer branco! + - Junta todas as cores primárias para fazeres branco! - Tu tens um mapa infinito, não limites a tua fábrica, expande! - Tenta também Factorio! É o meu jogo favorito. - - O cortador quádruplo corta no sentido dos ponteiros começando no canto + - O cortador quádruplo corta no sentido dos ponteiros do relógio começando no canto superior direito! - Podes fazer download dos teus savegames no menu principal! - Este jogo tem muitos atalhos de teclado úteis! Não te esqueças de @@ -1064,4 +1101,4 @@ tips: - Para limpar tapetes, corta a área e cola-a na mesma localização. - Pressiona F4 para mostrar os teus FPS e Tick Rate. - Pressiona F4 duas vezes para mostrar a tile do teu rato e câmara. - - Podes clicar numa forma afixada no lado direito para desafixar-la. + - Podes clicar numa forma afixada no lado direito para desafixa-la. diff --git a/translations/base-ro.yaml b/translations/base-ro.yaml index 279b451d..017be38f 100644 --- a/translations/base-ro.yaml +++ b/translations/base-ro.yaml @@ -204,6 +204,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Move @@ -299,6 +307,30 @@ ingame: rapid.

Sfat: Ține apăsat SHIFT pentru a plasa mai multe extractoare, și flosește R pentru a le roti." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." colors: red: Roșu green: Verde @@ -710,7 +742,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -884,6 +917,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Tastele setate diff --git a/translations/base-ru.yaml b/translations/base-ru.yaml index 5587cc1c..c2613c80 100644 --- a/translations/base-ru.yaml +++ b/translations/base-ru.yaml @@ -1,51 +1,51 @@ steamPage: shortText: shapez.io — это игра о строительстве фабрик для автоматизации создания и объединения все более сложных фигур на бесконечной карте. - discordLinkShort: Official Discord + discordLinkShort: Официальный Discord сервер intro: >- - Shapez.io is a relaxed game in which you have to build factories for the - automated production of geometric shapes. + Shapez.io - это спокойная игра о создании фабрик для автоматизации + создания сложных геометрических фигур. - As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map. + По мере управления уровня, фигуры становятся все сложнее, так что придется расширять фабрику засчет бесконечной карты. - And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling! + Если этого мало, то Вам так же придется экспоненциально производить все больше и больше фигур, чтобы удовлетворить потребности Вашей фабрики. Ключ к успеху - расширение! - While you only process shapes at the beginning, you have to color them later - for this you have to extract and mix colors! + Вначале игры Вам понадобится производить только фигуры, однако позже фигуры надо будет окрашивать. Для этого добывайте и смешивайте краски! - Buying the game on Steam gives you access to the full version, but you can also play a demo on shapez.io first and decide later! - title_advantages: Standalone Advantages + Приобретение игры в Steam предоставляет доступ к полной версии игры, но вы можете опробовать демоверсию игры на shapez.io и принять решение позже! + title_advantages: Преимущества полной версии advantages: - - 12 New Level for a total of 26 levels - - 18 New Buildings for a fully automated factory! - - 20 Upgrade Tiers for many hours of fun! - - Wires Update for an entirely new dimension! - - Dark Mode! - - Unlimited Savegames - - Unlimited Markers - - Support me! ❤️ - title_future: Planned Content + - 12 новых уровней - всего 26 уровней! + - 18 новых построек для полностью автоматизированной фабрики! + - 20 стадий улучшения для долгих часов веселья! + - Провода - открывает полноценное новое измерение! + - Темная тема! + - Неограниченные сохранения + - Неограниченные маркеры + - Поддержите меня! ❤️ + title_future: Запланированный контент planned: - - Blueprint Library (Standalone Exclusive) - - Steam Achievements - - Puzzle Mode - - Minimap - - Mods - - Sandbox mode - - ... and a lot more! - title_open_source: This game is open source! - title_links: Links + - Библиотека чертежей (только для Полной версии) + - Достижения Steam + - Режим головоломок + - Мини-карта + - Моды + - Режим песочницы + - ... и многое другое! + title_open_source: Эта игра находится в открытом доступе! + title_links: Ссылки links: - discord: Official Discord - roadmap: Roadmap + discord: Официальный Discord сервер + roadmap: Планы subreddit: Subreddit - source_code: Source code (GitHub) - translate: Help translate + source_code: Исходный код (GitHub) + translate: Помочь с переводом text_open_source: >- - Anybody can contribute, I'm actively involved in the community and - attempt to review all suggestions and take feedback into consideration - where possible. + Кто угодно может внести свой вклад в разработку игры - я активно + вовлечен в сообщество и стараюсь просмотреть все предложения и по + возможности прислушиваться к отзывам. - Be sure to check out my trello board for the full roadmap! + Не забудьте заглянуть на мой Trello board, чтобы ознакомиться с планами на будущее! global: loading: Загрузка error: Ошибка @@ -78,7 +78,7 @@ global: shift: SHIFT space: ПРОБЕЛ demoBanners: - title: Демо-версия + title: Демоверсия intro: Приобретите полную версию, чтобы разблокировать все возможности! mainMenu: play: Играть @@ -96,7 +96,7 @@ mainMenu: newGame: Новая Игра madeBy: Создал subreddit: Reddit - savegameUnnamed: Unnamed + savegameUnnamed: Без названия dialogs: buttons: ok: OK @@ -121,9 +121,8 @@ dialogs: text: Не удалось загрузить сохранение игры. confirmSavegameDelete: title: Подтвердите удаление. - text: Are you sure you want to delete the following game?

- '' at level

This can not be - undone! + text: Вы уверены, что хотите удалить это сохранение?

'' на + уровне

Это не может быть отменено! savegameDeletionError: title: Ошибка удаления text: Не удалось удалить сохранение игры. @@ -142,13 +141,13 @@ dialogs: title: Сброс управления desc: Настройки управления сброшены до соответствующих значений по умолчанию! featureRestriction: - title: Демо-версия + title: Демоверсия desc: Вы попытались получить доступ к функции (), которая недоступна в - демо-версии. Вы можете приобрести полную версию чтобы пользоваться + демоверсии. Вы можете приобрести полную версию чтобы пользоваться всеми функциями! oneSavegameLimit: title: Лимит сохранений - desc: Вы можете иметь только одно сохранение игры в демо-версии. Пожалуйста, + desc: Вы можете иметь только одно сохранение игры в демоверсии. Пожалуйста, удалите существующее или приобретите полную версию! updateSummary: title: Новое обновление! @@ -177,11 +176,12 @@ dialogs: Инвертировать направление размещаемых конвейерных лент.
" createMarker: title: Новый маркер - desc: Give it a meaningful name, you can also include a short - key of a shape (Which you can generate here) + desc: Дайте ему значимое название, вы также можете добавить короткий + ключ фигуры (Который можно сгенерировать + здесь) titleEdit: Редактирование маркера markerDemoLimit: - desc: Вы можете создать только 2 своих маркера в демо-версии. Приобретите полную + desc: Вы можете создать только 2 своих маркера в демоверсии. Приобретите полную версию для безлимитных маркеров. massCutConfirm: title: Подтвердите вырезку @@ -197,13 +197,19 @@ dialogs: desc: Вы не можете позволить себе вставить эту область! Вы уверены, что хотите вырезать ее? editSignal: - title: Set Signal - descItems: "Choose a pre-defined item:" - descShortKey: ... or enter the short key of a shape (Which you - can generate here) + title: Установить Сигнал + descItems: "Выберите объект:" + descShortKey: ... или введите короткий ключ фигуры (Который + можно сгенерировать здесь) renameSavegame: - title: Rename Savegame - desc: You can rename your savegame here. + title: Переименовать Сохранение + desc: Здесь вы можете изменить название своего сохранения. + tutorialVideoAvailable: + title: Доступно обучение + desc: Для этого уровня доступно видео-обучение! Посмотрите его? + tutorialVideoAvailableForeignLanguage: + title: Доступно обучение + desc: Для этого уровня доступно видео-обучение, но только на английском языке. Посмотрите его? ingame: keybindingsOverlay: moveMap: Передвижение @@ -212,7 +218,7 @@ ingame: rotateBuilding: Повернуть постройку placeMultiple: Поставить несколько reverseOrientation: Реверсировать направление - disableAutoOrientation: Отключить авто-определение направления + disableAutoOrientation: Отключить автоопределение направления toggleHud: Переключить HUD placeBuilding: Разместить постройку createMarker: Создать маркер @@ -244,7 +250,7 @@ ingame: notifications: newUpgrade: Новое улучшение доступно! gameSaved: Игра сохранена. - freeplayLevelComplete: Level has been completed! + freeplayLevelComplete: Уровень завершён! shop: title: Улучшения buttonUnlock: Улучшить @@ -265,9 +271,9 @@ ingame: description: Показывает фигуры, которые доставляются в хаб. noShapesProduced: Фигуры еще не произведены. shapesDisplayUnits: - second: / s - minute: / m - hour: / h + second: / с + minute: / м + hour: / ч settingsMenu: playtime: Игровое время buildingsPlaced: Постройки @@ -298,6 +304,26 @@ ingame: конвейеров, чтобы достичь цели быстрее.

Подсказка: Удерживайте SHIFT чтобы разместить несколько экстракторов, а R чтобы вращать их." + 2_1_place_cutter: "Разместите Резак для разрезания кругов на две половины! +

PS: Резак всегда разрезает сверху вниз независимо от ориентации." + 2_2_place_trash: Резак может засориться и остановиться!

Используйте + мусорку что бы избавиться от в данный момент (!) ненужных частей. + 2_3_more_cutters: "Хорошая работа! Теперь разместите ещё 2 резака что бы ускорить + этот медленный процесс!

PS: Используйте клавиши 0-9 + для быстрого доступа к постройкам!" + 3_1_rectangles: "Теперь давайте извлечём немного прямоугольников! Постройте 4 + экстрактораи соедините их с хабом.

PS: + Удерживайте SHIFT во время удерживания конвейера для активации планировщика + конвейеров!" + 21_1_place_quad_painter: Разместите покрасчик для 4 предметов и получите + круги, белого и + красного цветов! + 21_2_switch_to_wires: Переключите слой проводов нажатием клавиши + E!

Потом соедините все входы покрасчика кабелями! + 21_3_place_button: Отлично! Теперь разместите Переключатель и присоедини его проводами! + 21_4_press_button: "Нажмите на переключатель что бы заставить его выдавать истинный сигнал + и активировать этим покрасчика.

PS: Не обязательно + соединять все входы! Достаточно двух." colors: red: Красный green: Зеленый @@ -313,41 +339,41 @@ ingame: empty: Пусто copyKey: Копировать connectedMiners: - one_miner: 1 Miner - n_miners: Miners - limited_items: Limited to + one_miner: 1 Экстрактор + n_miners: Экстрактора(-ов) + limited_items: Ограничено до watermark: - title: Demo version - desc: Click here to see the Steam version advantages! - get_on_steam: Get on steam + title: Демоверсия + desc: Нажмите сюда, чтобы узнать о преимуществах Steam версии! + get_on_steam: Приобрести в Steam standaloneAdvantages: - title: Get the full version! - no_thanks: No, thanks! + title: Приобретите полную версию! + no_thanks: Нет, спасибо! points: levels: - title: 12 New Levels - desc: For a total of 26 levels! + title: 12 Новых Уровней! + desc: Всего 26 уровней! buildings: - title: 18 New Buildings - desc: Fully automate your factory! + title: 18 новых Построек! + desc: Полностью автоматизируйте свою фабрику! savegames: - title: ∞ Savegames - desc: As many as your heart desires! + title: ∞ Сохранений + desc: Сколько Вашей душе угодно! upgrades: - title: 20 Upgrade Tiers - desc: This demo version has only 5! + title: 20 стадий улучшений! + desc: В демоверсии всего 5! markers: - title: ∞ Markers - desc: Never get lost in your factory! + title: ∞ Маркеров! + desc: Никогда не теряйтесь в своей фабрике! wires: - title: Wires - desc: An entirely new dimension! + title: Провода! + desc: Полноценное дополнительное измерение! darkmode: - title: Dark Mode - desc: Stop hurting your eyes! + title: Темная Тема! + desc: Дайте глазам отдохнуть! support: - title: Support me - desc: I develop it in my spare time! + title: Поддержите меня + desc: Я занимаюсь разработкой в свободное время! shopUpgrades: belt: name: Конвейеры, Разделители & Туннели @@ -387,11 +413,11 @@ buildings: default: name: Резак description: Разрезает фигуры сверху вниз и выводит обе половины. Если - Вы собираетесь использовать только одну часть, уничтожьте + вы собираетесь использовать только одну часть, уничтожьте другую, иначе производство остановится! quad: name: Резак (4Вых.) - description: Разрезает фигуры на четыре части. Если Вы собираетесь + description: Разрезает фигуры на четыре части. Если вы собираетесь использовать не все части - уничтожьте оставшиеся, иначе производство остановится! rotater: @@ -402,8 +428,8 @@ buildings: name: Вращатель (Обр.) description: Поворачивает фигуры против часовой стрелки на 90 градусов. rotate180: - name: Rotate (180) - description: Rotates shapes by 180 degrees. + name: Вращатель (180) + description: Поворачивает фигуры на 180 градусов. stacker: default: name: Объединитель @@ -422,9 +448,9 @@ buildings: description: Красит фигуру из левых входов красителем из перпендикулярного. quad: name: Покрасчик (4Вх.) - description: Allows you to color each quadrant of the shape individually. Only - slots with a truthy signal on the wires layer - will be painted! + description: Позволяет отдельно окрашивать каждую часть фигуры. Только ячейки с + положительным сигналом на слое с проводами + будут окрашены! mirrored: name: Покрасчик description: Красит всю фигуру из левого входа красителем из перпендикулярного. @@ -436,134 +462,139 @@ buildings: deliver: Доставить toUnlock: чтобы открыть levelShortcut: Ур. - endOfDemo: End of Demo + endOfDemo: Конец Демо wire: default: name: Энерг. провод description: Позволяет транспортировать энергию. second: - name: Wire - description: Transfers signals, which can be items, colors or booleans (1 / 0). - Different colored wires do not connect. + name: Энерг. провод + description: Передает сигналы, которые могут быть ресурсами, цветами или + логическими значениями (1 / 0). Провода разных цветов не + соединяются. balancer: default: - name: Balancer - description: Multifunctional - Evenly distributes all inputs onto all outputs. + name: Балансер + description: Многофункциональный - равномерно распределяет все входы на выходы. merger: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Соединитель (компактный) + description: Соединяет две линии ковейера в одну. merger-inverse: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Соединитель (компактный) + description: Соединяет две линии ковейера в одну. splitter: - name: Splitter (compact) - description: Splits one conveyor belt into two. + name: Разделитель (компактный) + description: Разделяет одну линию конвейера на две. splitter-inverse: - name: Splitter (compact) - description: Splits one conveyor belt into two. + name: Разделитель (компактный) + description: Разделяет одну линию конвейера на две. storage: default: - name: Storage - description: Stores excess items, up to a given capacity. Prioritizes the left - output and can be used as an overflow gate. + name: Буферное Хранилище + description: Хранит излишние ресурсы пока есть место. Левый выход в приоритете, + может быть использован как буфер. wire_tunnel: default: - name: Wire Crossing - description: Allows to cross two wires without connecting them. + name: Пересечение Проводов + description: Позволяет пересекать провода при этом их не соединяя. constant_signal: default: - name: Constant Signal - description: Emits a constant signal, which can be either a shape, color or - boolean (1 / 0). + name: Постоянный Сигнал + description: Издает постоянный сигнал, который может быть ресурсом, цветом или + логическим значением (1 / 0). lever: default: - name: Switch - description: Can be toggled to emit a boolean signal (1 / 0) on the wires layer, - which can then be used to control for example an item filter. + name: Переключатель + description: Может быть переключен, чтобы издавать логический сигнал (1 / 0) на + слое с проводами, который может быть использован для управления + Фильтром, например. logic_gate: default: name: AND Gate - description: Emits a boolean "1" if both inputs are truthy. (Truthy means shape, - color or boolean "1") + description: Издает значение "1" если оба входа положительны. (Положительный - + значит ресурс, цвет или логическое значение "1") not: name: NOT Gate - description: Emits a boolean "1" if the input is not truthy. (Truthy means - shape, color or boolean "1") + description: Издает значение "1" если вход не положительный. (Положительный - + значит ресурс, цвет или логическое значение "1") xor: name: XOR Gate - description: Emits a boolean "1" if one of the inputs is truthy, but not both. - (Truthy means shape, color or boolean "1") + description: Издает значение "1" только один из входов положительный. + (Положительный - значит ресурс, цвет или логическое значение + "1") or: name: OR Gate - description: Emits a boolean "1" if one of the inputs is truthy. (Truthy means - shape, color or boolean "1") - transistor: - default: - name: Transistor - description: Forwards the bottom input if the side input is truthy (a shape, - color or "1"). - mirrored: - name: Transistor - description: Forwards the bottom input if the side input is truthy (a shape, - color or "1"). + description: Издает значение "1" если хотя бы один вход положительный. + (Положительный - значит ресурс, цвет или логическое значение + "1"). filter: default: - name: Filter - description: Connect a signal to route all matching items to the top and the - remaining to the right. Can be controlled with boolean signals - too. + name: Фильтр + description: Подключите сигнал, чтобы направить все подходящие ресурсы наверх, а + остальные направо. Также контролируемо логическими сигналами. display: default: - name: Display - description: Connect a signal to show it on the display - It can be a shape, - color or boolean. + name: Экран + description: Подключите сигнал, чтобы отобразить его на экране. Это может + ресурс, цвет или логическое значение (1 / 0). reader: default: - name: Belt Reader - description: Allows to measure the average belt throughput. Outputs the last - read item on the wires layer (once unlocked). + name: Измеритель + description: Позволяет измерять среднюю пропускную способность конвейера. + Отображает последний прошедший ресурс на слое с проводами (когда + разблокировано). analyzer: default: - name: Shape Analyzer - description: Analyzes the top right quadrant of the lowest layer of the shape - and returns its shape and color. + name: Анализатор Фигур + description: Анализирует правую верхнюю часть низшего слоя фигуры и возвращает + ее форму и цвет. comparator: default: - name: Compare - description: Returns boolean "1" if both signals are exactly equal. Can compare - shapes, items and booleans. + name: Сравнить + description: Возвращает значение "1" если оба сигнала полностью одинаковы. Может + сравнивать фигуры, цвета и логические значения. virtual_processor: default: - name: Virtual Cutter - description: Virtually cuts the shape into two halves. + name: Виртуальный Резак + description: Виртуально разрезает фигуру пополам. rotater: - name: Virtual Rotater - description: Virtually rotates the shape, both clockwise and counter-clockwise. + name: Виртуальный Вращатель + description: Виртуально вращает фигуру как по часовой стрелке, так и против + часовой стрелки. unstacker: - name: Virtual Unstacker - description: Virtually extracts the topmost layer to the right output and the - remaining ones to the left. + name: Виртуальный Разъединитель + description: Виртуально извлекает самый верхний слой фигуры направо, а все + остальное направо. stacker: - name: Virtual Stacker - description: Virtually stacks the right shape onto the left. + name: Виртуальный Объединитель + description: Виртуально помещает правый предмет поверх левого. painter: - name: Virtual Painter - description: Virtually paints the shape from the bottom input with the shape on - the right input. + name: Виртуальный Покрасчик + description: Виртуально окрашивает фигуру из нижнего входа цветом из правого + входа. item_producer: default: - name: Item Producer - description: Available in sandbox mode only, outputs the given signal from the - wires layer on the regular layer. + name: Генератор Ресурсов + description: Доступен только в режиме песочницы, производит заданный на слое с + проводами сигнал на обычном слое. + transistor: + default: + name: Транзистор + description: Пропускает предметы только если вход сбоку имеет истинноре значение (фигура, + цвет или "1"). + mirrored: + name: Транзистор + description: Пропускает предметы только если вход сбоку имеет истинноре значение (фигура, + цвет или "1"). storyRewards: reward_cutter_and_trash: title: Разрезание Фигур - desc: You just unlocked the cutter, which cuts shapes in half - from top to bottom regardless of its - orientation!

Be sure to get rid of the waste, or - otherwise it will clog and stall - For this purpose - I have given you the trash, which destroys - everything you put into it! + desc: Разблокирован резак, который разрезает фигуры пополам по + вертикали независимо от ориентации!

Не + забудьте избавляться от излишков, иначе он забьется и + остановится - для этого я также открыл для Вас + мусорку, которая уничтожает все, что в нее + попадает! reward_rotater: title: Вращение desc: Разблокирован вращатель! Он поворачивает фигуры по @@ -586,9 +617,9 @@ storyRewards: правого входа наложится на фигуру из левого! reward_splitter: title: Разделитель / Соединитель - desc: You have unlocked a splitter variant of the - balancer - It accepts one input and splits them - into two! + desc: Разблокирован разделитель один из вариантов + балансера - он принимает один вход и разделяет его + на два! reward_tunnel: title: Туннель desc: Разблокирован туннель! Теперь вы можете транспортировать @@ -600,10 +631,10 @@ storyRewards: нажмите 'T', чтобы переключить вариант! reward_miner_chainable: title: Цепной Экстрактор - desc: "You have unlocked the chained extractor! It can - forward its resources to other extractors so you - can more efficiently extract resources!

PS: The old - extractor has been replaced in your toolbar now!" + desc: "Разблокирован цепной экстрактор! Он может + передавать свои ресурсы другим экстракторам, чтобы + вы могли эффективнее извлекать ресурсы!

PS: Старый + экстрактор был заменен в панели инструментов!" reward_underground_belt_tier_2: title: Туннель II desc: Разблокирован новый вариант туннеля с большей @@ -619,18 +650,19 @@ storyRewards: одновременно, потребляя только один краситель вместо двух! reward_storage: title: Буферное Хранилище - desc: You have unlocked the storage building - It allows you to - store items up to a given capacity!

It priorities the left - output, so you can also use it as an overflow gate! + desc: Разблокировано буферное хранилище - оно позволяет хранить + в нем ресурсы пока есть место!

Левый выход в приоритете, + может быть использован как буфер! reward_freeplay: title: Свободная игра - desc: You did it! You unlocked the free-play mode! This means - that shapes are now randomly generated!

- Since the hub will require a throughput from now - on, I highly recommend to build a machine which automatically - delivers the requested shape!

The HUB outputs the requested - shape on the wires layer, so all you have to do is to analyze it and - automatically configure your factory based on that. + desc: У Вас получилось! Разблокирован свободный режим! Это + означает что теперь фигуры будут генерироваться + случайно!

Так как ХАБ отныне будет + требовать определенную пропускную способность, я + настоятельно рекомендую построить механизм, автоматически + доставляющий запрашиваемую фигуру!

ХАБ выводит запрашиваемую + фигуру на слое с проводами, так что все, что необходимо сделать, - + это проанализировать ее и автоматически настроить вашу фабрику. reward_blueprints: title: Чертежи desc: Теперь вы можете копировать и вставлять части вашей @@ -648,70 +680,71 @@ storyRewards: title: Следующий уровень desc: Поздравляем! Кстати, больше контента планируется для полной версии! reward_balancer: - title: Balancer - desc: The multifunctional balancer has been unlocked - It can - be used to build bigger factories by splitting and merging - items onto multiple belts! + title: Балансер + desc: Многофункциональный банансер разблокирован - Он используется для разделения и обьединения + потора предметов на несколько конвейеров! reward_merger: - title: Compact Merger - desc: You have unlocked a merger variant of the - balancer - It accepts two inputs and merges them - into one belt! + title: Компактный Соединитель + desc: Разблокирован соединитель - вариант + балансера - он принимает два входа и объединяет их + в один конвейер. reward_belt_reader: - title: Belt reader - desc: You have now unlocked the belt reader! It allows you to - measure the throughput of a belt.

And wait until you unlock - wires - then it gets really useful! + title: Измеритель + desc: Разблокирован измеритель! Он позволяет измерять + пропускную способность конвейера.

А как полезен он будет, + когда вы разблокируете провода! reward_rotater_180: - title: Rotater (180 degrees) - desc: You just unlocked the 180 degress rotater! - It allows - you to rotate a shape by 180 degress (Surprise! :D) + title: Вращатель (180 градусов) + desc: Разблокирован вращатель на 180 градусов! - Он позволяет + вращать фигур на 180 градусов (Сюрприз! :D) reward_display: - title: Display - desc: "You have unlocked the Display - Connect a signal on the - wires layer to visualize it!

PS: Did you notice the belt - reader and storage output their last read item? Try showing it on a - display!" + title: Экран + desc: "Разблокирован Экран - Подключите сигнал на слое с + проводами чтобы отобразить его!

PS: Заметили ли вы, что + измеритель и буферное хранилище отображают последний ресурс, + прошедший через них? Попробуйте отобразить его на экране!" reward_constant_signal: - title: Constant Signal - desc: You unlocked the constant signal building on the wires - layer! This is useful to connect it to item filters - for example.

The constant signal can emit a - shape, color or - boolean (1 / 0). + title: Постоянный Сигнал + desc: Разблокирован постоянный сигнал на слое с проводами! Он + полезен для подключения к фильтрам, + например.

Постоянный сигнал может издавать + фигуру, цвет или + логическое значение (1 / 0). reward_logic_gates: - title: Logic Gates - desc: You unlocked logic gates! You don't have to be excited - about this, but it's actually super cool!

With those gates - you can now compute AND, OR, XOR and NOT operations.

As a - bonus on top I also just gave you a transistor! + title: Логические Элементы + desc: Разблокированы логические элементы! Вы не обязаны + радоваться по этому поводу, но вообще это очень круто!

С + этими элементами теперь вы можете производить И, ИЛИ, исключающее + ИЛИ и НЕ операции.

Как бонус, я также дал вам + транзистор! reward_virtual_processing: - title: Virtual Processing - desc: I just gave a whole bunch of new buildings which allow you to - simulate the processing of shapes!

You can - now simulate a cutter, rotater, stacker and more on the wires layer! - With this you now have three options to continue the game:

- - Build an automated machine to create any possible - shape requested by the HUB (I recommend to try it!).

- Build - something cool with wires.

- Continue to play - regulary.

Whatever you choose, remember to have fun! + title: Виртуальное Производство + desc: Только что я открыл вам множество новых построек, которые позволят + симулировать производство фигур!

Теперь вы + можете симулировать резак, вращатель, объединитель и др. на слое с + проводами! Теперь у вас есть три варианта продолжения игры:

+ - Построить автоматический механизм для + производства любой фигуры, запрашиваемой ХАБ (рекомендую + попробовать!).

- Построить что-то клевое, используя + провода.

- Продолжить обычную игру.

Что бы вы не + выбрали, не забывайте хорошо проводить время! reward_wires_painter_and_levers: - title: Wires & Quad Painter - desc: "You just unlocked the Wires Layer: It is a separate - layer on top of the regular layer and introduces a lot of new - mechanics!

For the beginning I unlocked you the Quad - Painter - Connect the slots you would like to paint with on - the wires layer!

To switch to the wires layer, press - E." + title: Провода & Покрасчик (4 входа) + desc: "Вы разблокировали Слой проводов: Это отдельный + слой выше обычного слоя и он предоставляет много новых + механик!

Для начала я разблокировал тебе Покрасчик на 4 входа + - Соедини слоты которые нужно покрасить на слое проводов!

Для переключения видимости слоя проводов, нажми + E.

PS: Включи подсказки в + настройках что бы активировать обучение по проводам!" reward_filter: - title: Item Filter - desc: You unlocked the Item Filter! It will route items either - to the top or the right output depending on whether they match the - signal from the wires layer or not.

You can also pass in a - boolean signal (1 / 0) to entirely activate or disable it. + title: Фильтр + desc: Разблокирован Фильтр! Он направит ресурсы наверх или + направо в зависмости от того, совпадают ли они с установленным + сигналом.

Вы также можете передавать логические значения (1 + / 0), чтобы полностью отключить или включить его. reward_demo_end: - title: End of Demo - desc: You have reached the end of the demo version! + title: Конец Демо + desc: Вы достигли конца демоверсии игры! settings: title: Настройки categories: @@ -805,9 +838,9 @@ settings: description: Включает виньетирование, которое затемняет углы экрана и облегчает чтение текста. autosaveInterval: - title: Интервал авто-сохранения + title: Интервал автосохранения description: Управляет тем, как часто игра автоматически сохраняется. Также - здесь можно полностью отключить авто-сохранение. + здесь можно полностью отключить автосохранение. intervals: one_minute: 1 Минута two_minutes: 2 Минуты @@ -834,51 +867,53 @@ settings: установлен. С этой настройкой может быть удобнее, при частом переключении между различными типами зданий. soundVolume: - title: Sound Volume - description: Set the volume for sound effects + title: Громкость Звука + description: Задает громкость звуковых эффектов. musicVolume: title: Music Volume - description: Set the volume for music + description: Задает громкость музыки. lowQualityMapResources: - title: Low Quality Map Resources - description: Simplifies the rendering of resources on the map when zoomed in to - improve performance. It even looks cleaner, so be sure to try it - out! + title: Низкое качество ресурсов на карте + description: Упрощает отображение ресурсов на карте при приближении для + улучшения производительности. Оно даже выглядит аккуратнее, + поэтому обязательно попробуйте! disableTileGrid: - title: Disable Grid - description: Disabling the tile grid can help with the performance. This also - makes the game look cleaner! + title: Отключить Сетку + description: Отключение разделительной сетки может помочь улучшить + производительность. Кроме того, делает игру визуально проще! clearCursorOnDeleteWhilePlacing: - title: Clear Cursor on Right Click - description: Enabled by default, clears the cursor whenever you right click - while you have a building selected for placement. If disabled, - you can delete buildings by right-clicking while placing a - building. + title: Очистить Курсор на ПКМ + description: Включено по умолчанию, очищает курсор от выбранной постройки при + нажатии на ПКМ. Если отключено, вы можете удалять постройки при + нажатии на ПКМ во время строительства. lowQualityTextures: - title: Low quality textures (Ugly) - description: Uses low quality textures to save performance. This will make the - game look very ugly! + title: Низкое качество текстур (Некрасиво) + description: Использует низкое качество текстур, чтобы улучшить + производительность. Это сделает игру очень некрасивой! displayChunkBorders: - title: Display Chunk Borders - description: The game is divided into chunks of 16x16 tiles, if this setting is - enabled the borders of each chunk are displayed. + title: Отображать границы чанков + description: Эта игра разделена на чанки, состоящие из 16x16 ячеек, если эта + настройка включена, границы чанков будут отображаться. pickMinerOnPatch: - title: Pick miner on resource patch - description: Enabled by default, selects the miner if you use the pipette when - hovering a resource patch. + title: Выбрать Экстрактор над Жилой + description: Включено по умолчанию, выбирает экстрактор, если использовать + пипетку над жилой с ресурсами. simplifiedBelts: - title: Simplified Belts (Ugly) - description: Does not render belt items except when hovering the belt to save - performance. I do not recommend to play with this setting if you - do not absolutely need the performance. + title: Упрощенные Конвейеры (Некрасиво) + description: Не отображает ресурсы, находящиеся на конвейере, если не навести + курсор для улучшения производительности. Не рекомендую играть с + этой настройкой, если вас устраивает производительность. enableMousePan: - title: Enable Mouse Pan - description: Allows to move the map by moving the cursor to the edges of the - screen. The speed depends on the Movement Speed setting. + title: Включить Перемещение Мышкой + description: Позволяет двигать карту, перемещая курсор к краям экрана. Скорость + зависит от настройки Скорости движения. zoomToCursor: - title: Zoom towards Cursor - description: If activated the zoom will happen in the direction of your mouse - position, otherwise in the middle of the screen. + title: Приближение в точку курсора + description: Если включено, приближение будет в направлении курсора мыши, + иначе в центр экрана. + mapResourcesScale: + title: Размер ресурсов на карте + description: Устанавливает размер фигур на карте (когда вид достаточно отдалён). rangeSliderPercentage: % keybindings: title: Настройки управления @@ -924,9 +959,9 @@ keybindings: massSelectStart: Модификатор для выделения области massSelectSelectMultiple: Выбрать несколько областей massSelectCopy: Копировать область - placementDisableAutoOrientation: Отключить авто-определение направления + placementDisableAutoOrientation: Отключить автоопределение направления placeMultiple: Оставаться в режиме размещения - placeInverse: Инвертировать авто-определение направления конвейеров + placeInverse: Инвертировать автоопределение направления конвейеров pasteLastBlueprint: Вставить последний чертеж massSelectCut: Вырезать область exportScreenshot: Экспорт всей Базы в виде Изображения @@ -937,21 +972,21 @@ keybindings: menuClose: Закрыть меню switchLayers: Переключить слои wire: Энергетический провод - balancer: Balancer - storage: Storage - constant_signal: Constant Signal - logic_gate: Logic Gate - lever: Switch (regular) - filter: Filter - wire_tunnel: Wire Crossing - display: Display - reader: Belt Reader - virtual_processor: Virtual Cutter - transistor: Transistor - analyzer: Shape Analyzer - comparator: Compare - item_producer: Item Producer (Sandbox) - copyWireValue: "Wires: Copy value below cursor" + balancer: Балансер + storage: Буферное Хранилище + constant_signal: Постоянный Сигнал + logic_gate: Логический Элемент + lever: Переключатель (обычный) + filter: Фильтр + wire_tunnel: Пересечение Проводов + display: Экран + reader: Измеритель + virtual_processor: Виртуальный Резак + transistor: Транзистор + analyzer: Анализатор Фигур + comparator: Сравнить + item_producer: Генератор Ресурсов (Песочница) + copyWireValue: "Провода: скопировать значение под курсором" backwardsModifier: "Modifier: Cycle backwards" about: title: Об игре @@ -976,65 +1011,67 @@ demo: oneGameLimit: Ограниченность одним сохранением игры customizeKeybindings: Пользовательская настройка Управления exportingBase: Экспорт всей Базы в виде Изображения - settingNotAvailable: Не доступно в демо-версии. + settingNotAvailable: Недоступно в демоверсии. tips: - - The hub accepts input of any kind, not just the current shape! - - Make sure your factories are modular - it will pay out! - - Don't build too close to the hub, or it will be a huge chaos! - - If stacking does not work, try switching the inputs. - - You can toggle the belt planner direction by pressing R. - - Holding CTRL allows dragging of belts without auto-orientation. - - Ratios stay the same, as long as all upgrades are on the same Tier. - - Serial execution is more efficient than parallel. - - You will unlock more variants of buildings later in the game! - - You can use T to switch between different variants. - - Symmetry is key! - - You can weave different tiers of tunnels. - - Try to build compact factories - it will pay out! - - The painter has a mirrored variant which you can select with T - - Having the right building ratios will maximize efficiency. - - At maximum level, 5 extractors will fill a single belt. - - Don't forget about tunnels! - - You don't need to divide up items evenly for full efficiency. - - Holding SHIFT will activate the belt planner, letting you place - long lines of belts easily. - - Cutters always cut vertically, regardless of their orientation. - - To get white mix all three colors. - - The storage buffer priorities the first output. - - Invest time to build repeatable designs - it's worth it! - - Holding CTRL allows to place multiple buildings. - - You can hold ALT to invert the direction of placed belts. - - Efficiency is key! - - Shape patches that are further away from the hub are more complex. - - Machines have a limited speed, divide them up for maximum efficiency. - - Use balancers to maximize your efficiency. - - Organization is important. Try not to cross conveyors too much. - - Plan in advance, or it will be a huge chaos! - - Don't remove your old factories! You'll need them to unlock upgrades. - - Try beating level 20 on your own before seeking for help! - - Don't complicate things, try to stay simple and you'll go far. - - You may need to re-use factories later in the game. Plan your factories to - be re-usable. - - Sometimes, you can find a needed shape in the map without creating it with - stackers. - - Full windmills / pinwheels can never spawn naturally. - - Color your shapes before cutting for maximum efficiency. + - ХАБ принимает любые ресурсы, не только текущую фигуру! + - Старайтесь создавать модульные фабрики - вы не пожалеете! + - Не стройте слишком близко к ХАБ-у, иначе начнется ужасный хаос! + - Если не получается объединить фигуры, попробуйте поменять входы местами! + - Вы можете изменить направление конвейера при строительстве, нажав R. + - Удерживая CTRL, вы можете перемещать конвейеры без авто ориентации. + - Соотношения всегда одинаковы, если уровни улучшений равны. + - Последовательное выполнение эффективнее, чем параллельное. + - Вам будут открываться новые варианты построек по мере прохождения! + - Нажмите T, чтобы переключаться между различными вариантами. + - Симметрия - ключ к успеху! + - Вы можете переплетать между собой туннели разных уровней. + - Попробуйте строить компактные фабрики - вы не пожалеете! + - Покрасчик имеет зеркальный вариант, который может быть выбран, нажав + T. + - Правильные соотношения построек позволяет улучшить эффективность фабрики. + - На максимальном уровне, 5 экстракторов заполняют один конвейер. + - Резаки всегда разрезают пополам по вертикали вне зависимости от ориентации. + - Чтобы получить белый цвет, смешайте все три цвета. + - Удерживание SHIFT активирует планировщик конвейеров, что упрощает простройку длинных конвейеров. + - Вкладывайте время в строительство повторяемых механизмов - оно того стоит! + - Смешайте все три цвета для получения булого. + - Буффер хранилища с большим приоритетом выдаёт на левый выход. + - Эффективность - ключ к успеху! + - Удерживание CTRL даёт возможность размещения нескольких построек. + - Можно зажать ALT для инвертирования направления размещаемых конвейеров. + - Используйте балансеры, чтобы максимизировать эффективность. + - Организация очень важна, старайтесь не пересекать конвейеры слишком часто. + - Планируйте заранее, иначе начнется ужасный хаос! + - Не удаляйте свои старые фабрики! Они понадобятся вам, чтобы открывать + улучшения. + - Попробуйте пройти 20-ый уровень самостоятельно, прежде чем искать помощи! + - Не усложняйте себе жизнь, старайтесь думать проще и вы достигните больших + высот. + - Вам может снова понадобиться ваша старая фабрика позже в игре. Старайтесь + планировать фабрику, чтобы она могла быть повторно использована. + - Иногда, вы можете найти необходимую фигуру на карте, вместо того, чтобы + создавать ее самостоятельно. + - Полноценные мельницы/вертушки никогда не генерируются натурально. + - Окрашивайте свои фигуры, прежде чем разрезать для максимальной + эффективности. + - С модулями теряется восприятие пространства; забота смертных. + - Создайте отдельную фабрику чертежей. Они очень важны для модулей. + - Взгляните внимательнее на смешиватель и вы найдете ответы на свои вопросы. - With modules, space is merely a perception; a concern for mortal men. - - Make a separate blueprint factory. They're important for modules. - - Have a closer look on the color mixer, and your questions will be answered. - - Use CTRL + Click to select an area. - - Building too close to the hub can get in the way of later projects. - - The pin icon next to each shape in the upgrade list pins it to the screen. - - Mix all primary colors together to make white! - - You have an infinite map, don't cramp your factory, expand! - - Also try Factorio! It's my favorite game. - - The quad cutter cuts clockwise starting from the top right! - - You can download your savegames in the main menu! - - This game has a lot of useful keybindings! Be sure to check out the - settings page. - - This game has a lot of settings, be sure to check them out! - - The marker to your hub has a small compass to indicate its direction! - - To clear belts, cut the area and then paste it at the same location. - - Press F4 to show your FPS and Tick Rate. - - Press F4 twice to show the tile of your mouse and camera. - - You can click a pinned shape on the left side to unpin it. + - Строительство вблизи ХАБ-а может помешать будущим проектам. + - Иконка булавки на каждой фигуре закрепляет ее на экране. + - Используйте CTRL + ЛКМ для выбора области. + - В вашем распоряжении бесконечная карта! Не загромождайте вашу фабрику, + расширяйтесь! + - Также попробуйте Factorio. Это моя любимая игра. + - Резак(4 входа) разрезает по часовой стрелке, начиная с правой верхней + части! + - Вы можете скачать свои сохранения в главном меню! + - В этой игре множество полезных комбинаций клавиш. Загляните в настройки, + чтобы ознакомиться с ними. + - В этой игре множество настроек, не забудьте с ними ознакомиться. + - Маркер ХАБ-а имеет небольшой компас, указывающий его направление. + - Нажмите F4, чтобы показать FPS и Частоту Обновления. + - Нажмите F4 дважды, чтобы показать координаты курсора и камеры. + - Вы можете нажать на закрепленную фигуру слева, чтобы открепить ее. + - Для очистки конвейеров, вырежьте область и вставьте её в то же место. diff --git a/translations/base-sl.yaml b/translations/base-sl.yaml index 63c53df3..79efbf40 100644 --- a/translations/base-sl.yaml +++ b/translations/base-sl.yaml @@ -199,6 +199,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Move @@ -307,6 +315,30 @@ ingame: and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 Miner n_miners: Miners @@ -697,7 +729,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -867,6 +900,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Keybindings diff --git a/translations/base-sr.yaml b/translations/base-sr.yaml index 2d884cb6..02bbf185 100644 --- a/translations/base-sr.yaml +++ b/translations/base-sr.yaml @@ -199,6 +199,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Kretanje @@ -307,6 +315,30 @@ ingame: pokretnih traka će ubrzati napredak do cilja.

Savet: Drži SHIFT za postavljanje više rudara istovremeno, a pritisni R za okretanje." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 Miner n_miners: Miners @@ -695,7 +727,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -865,6 +898,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Tasteri diff --git a/translations/base-sv.yaml b/translations/base-sv.yaml index eb282e81..ef647d79 100644 --- a/translations/base-sv.yaml +++ b/translations/base-sv.yaml @@ -203,6 +203,14 @@ dialogs: renameSavegame: title: Byt namn på sparfil desc: Du kan byta namn på din sparfil här. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Flytta @@ -297,6 +305,30 @@ ingame: för att klara målet snabbare.

Tips: Håll SKIFT för att placera flera extraktörer, och använd R för att rotera dem." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." colors: red: Röd green: Grön @@ -637,7 +669,7 @@ storyRewards: title: Ritningar desc: Du kan nu kopiera och klistra in delar av din fabrik! Välj ett område (håll in CTRL, dra sedan med musen), och tryck 'C' - för att kopiera det.

Att klistra in ärinte + för att kopiera det.

Att klistra in är inte gratis, du behöver producera ritningsformer för att ha råd med det! (De du just levererade). @@ -706,7 +738,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -877,6 +910,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Snabbtangenter diff --git a/translations/base-tr.yaml b/translations/base-tr.yaml index 3effa29c..3830328f 100644 --- a/translations/base-tr.yaml +++ b/translations/base-tr.yaml @@ -201,6 +201,14 @@ dialogs: renameSavegame: title: Oyun Kaydının Yeniden Adlandır desc: Oyun kaydını buradan adlandırabilirsiniz. + tutorialVideoAvailable: + title: Eğitim Mevcut + desc: Bu seviye için eğitim vidyosu mevcut! İzlemek + ister misin? + tutorialVideoAvailableForeignLanguage: + title: Eğitim Mevcut + desc: Bu seviye için eğitim vidyosu mevcut, ama İngilizce dilinde. + İzlemek ister misin? ingame: keybindingsOverlay: moveMap: Hareket Et @@ -261,9 +269,9 @@ ingame: description: Merkez binanıza giden bütün şekilleri gösterir. noShapesProduced: Henüz hiçbir şekil üretilmedi. shapesDisplayUnits: - second: / s - minute: / m - hour: / h + second: / sn + minute: / dk + hour: / sa settingsMenu: playtime: Oynama zamanı buildingsPlaced: Yapılar @@ -294,6 +302,30 @@ ingame: yerleştir.

İpucu: Birden fazla üretici yerleştirmek için SHIFT tuşuna basılı tut, ve R tuşuyla taşıma bandının yönünü döndür." + 2_1_place_cutter: "Şimdi daireleri yarıya bölmek için bir Kesici yerleştir!

+ Not: Kesici şekilleri yönünden bağımsız olarak her zaman yukarıdan aşağıya + keser." + 2_2_place_trash: Kesicinin çıkış hatları doluysa durabilir!

+ Bunun için kullanılmayan çıktılara çöp + yerleştirin. + 2_3_more_cutters: "İyi iş çıkardın! Şimdi işleri hızlandırmak için iki kesici daha + yerleştir.

Not: 0-9 tuşlarını kullanarak yapılara + daha hızlı ulaşabilirsin!" + 3_1_rectangles: "Şimdi biraz dikdörtgen üretelim! 4 Üretici yerleştir ve + bunları merkeze bağla.

Not: SHIFT tuşuna + basılı tutarak bant planlayıcıyı + etkinleştir!" + 21_1_place_quad_painter: Dörtlü boyayıcıyı yerleştirin ve daireyi, + beyaz ve kırmızı renkleri + elde edin! + 21_2_switch_to_wires: Kablo katmanına E tuşuna basarak geçiş yapın!

+ Sonra boyayıcının dört girişini kablolara + bağlayın! + 21_3_place_button: Harika! Şimdi bir Anahtar yerleştirin ve onu + kablolarla bağlayın! + 21_4_press_button: "Anahtara basarak gerçekçi sinyal(1) gönderin ve bununla + boyayıcıyı aktifleştirin.

Not: Bütün girişleri bağlamanıza gerek yok! + Sadece iki tanesini kabloyla bağlamayı deneyin." colors: red: Kırmızı green: Yeşil @@ -562,7 +594,7 @@ storyRewards: eden çöpü de verdim! reward_rotater: title: Döndürme - desc: Döndürücü açıldı! Döndürücü şekilleri saat yönüne 90 + desc: Döndürücü açıldı! Döndürücü şekilleri saat yönünde 90 derece döndürür. reward_painter: title: Boyama @@ -653,9 +685,9 @@ storyRewards: desc: Deneme sürümünün sonuna geldin! reward_balancer: title: Dengeleyici - desc: The multifunctional balancer has been unlocked - It can - be used to build bigger factories by splitting and merging - items onto multiple belts! + desc: Çok fonksiyonlu dengeleyici açıldı. - Eşyaları + bantlara ayırarak ve bantları birleştirerek daha büyük + fabrikalar kurmak için kullanılabilir! reward_merger: title: Tekil Birleştirici desc: Birleştiriciyi açtın ! dengeleyecinin @@ -671,17 +703,17 @@ storyRewards: döndürür (Süpriz! :D) reward_display: title: Ekran - desc: "You have unlocked the Display - Connect a signal on the - wires layer to visualize it!

PS: Did you notice the belt - reader and storage output their last read item? Try showing it on a - display!" + desc: "Ekranı açtın. - Kablo katmanında bir sinyal bağla ve onu + ekranda göster!

Not: Bant okuyucunun ve deponun son + okudukları eşyayı çıkardığını fark ettin mi? Bunu ekranda göstermeyi + dene!" reward_constant_signal: title: Sabit Sinyal - desc: You unlocked the constant signal building on the wires - layer! This is useful to connect it to item filters - for example.

The constant signal can emit a - shape, color or - boolean (1 or 0). + desc: Kablo katmanında inşa edilebilen sabit sinyal'i açtın! + Bu yapı örneğin eşya filtrelerine bağlanabilir.

+ Sabit sinyal şekil, renk veya + ikili değer (1 veya 0) + gönderelebilir. reward_logic_gates: title: Mantık Kapıları desc: Mantık kapıları açıldı! Çok heyecanlanmana gerek yok, ama @@ -706,7 +738,8 @@ storyRewards: vardır!

Başlangıç olarak senin için Dörtlü Boyayıcıyı açıyorum. - Kablo katmanında boyamak için istediğin hatları bağla!

Kablo katmanına geçiş yapmak için - E tuşunu kullan." + E tuşunu kullan.

Not: İpuçlarını kablo eğitimlerini + görmek için ayarlarda aktifleştirmeyi unutma." reward_filter: title: Eşya Filtresi desc: Eşya filtresini açtın! Kablo katmanından gelen sinyalle @@ -725,6 +758,7 @@ settings: staging: Yükseltme prod: Üretim buildDate: derlendi + rangeSliderPercentage: % labels: uiScale: title: Arayüz Ölçeğİ @@ -872,10 +906,14 @@ settings: title: Fare Kaydırarak Hareket Etme description: Fareyi ekranın köşelerine getirerek hareket ettirmeyi sağlar. zoomToCursor: - title: Zoom towards Cursor - description: If activated the zoom will happen in the direction of your mouse - position, otherwise in the middle of the screen. - rangeSliderPercentage: % + title: Farenin Konumuna Yakınlaştırma + description: Eğer etkinleştirilirse zaman ekran yakınlaştırılması fare imlecinin + bulunduğu yere doğru olur. Etkinleştirilmezse yakınlaştırma + ekranın ortasına doğru olur. + mapResourcesScale: + title: Uzak Bakışta Kaynakların Büyüklüğü + description: Haritaya uzaktan bakıldığında, haritadaki şekillerin büyüklüğünü + ayarlar. keybindings: title: Tuş Atamaları hint: "İpucu: CTRL, SHIFT ve ALT tuşlarından yararlanın! Farklı yerleştirme diff --git a/translations/base-uk.yaml b/translations/base-uk.yaml index 6428d222..ff8a89c2 100644 --- a/translations/base-uk.yaml +++ b/translations/base-uk.yaml @@ -202,6 +202,14 @@ dialogs: renameSavegame: title: Rename Savegame desc: You can rename your savegame here. + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: Рухатися @@ -311,6 +319,30 @@ ingame: швидше.

Підказка: Утримуйте SHIFT, щоб розмістити багато екстракторів, і використовуйте R, щоб обертати їх." + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." connectedMiners: one_miner: 1 Miner n_miners: Miners @@ -705,7 +737,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -878,6 +911,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: Гарячі клавіши diff --git a/translations/base-zh-CN.yaml b/translations/base-zh-CN.yaml index 9c0966af..f4461117 100644 --- a/translations/base-zh-CN.yaml +++ b/translations/base-zh-CN.yaml @@ -176,6 +176,14 @@ dialogs: renameSavegame: title: 重命名存档 desc: 您可以在此重命名存档。 + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: 移动地图 @@ -262,6 +270,30 @@ ingame: 1_2_conveyor: 用传送带将你的开采机连接到基地上!

提示:用你的鼠标按下并拖动传送带! 1_3_expand: 这不是一个挂机游戏!建造更多的开采机和传送带来更快地完成目标。

提示:按住 SHIFT 键来放置多个开采机,用 R 键旋转它们。 + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." colors: red: 红色 green: 绿色 @@ -638,7 +670,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -791,6 +824,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: 按键设置 diff --git a/translations/base-zh-TW.yaml b/translations/base-zh-TW.yaml index fa55fb06..3b5a2060 100644 --- a/translations/base-zh-TW.yaml +++ b/translations/base-zh-TW.yaml @@ -18,7 +18,7 @@ steamPage: - 無限存檔 - 無限標記 - 支持我! ❤️ - title_future: Planned Content + title_future: 未來計劃 planned: - 藍圖圖庫(單機版獨有) - Steam 成就 @@ -79,8 +79,8 @@ mainMenu: openSourceHint: 本遊戲已開源! discordLink: 官方 Discord 伺服器 helpTranslate: 幫助我們翻譯! - browserWarning: 很抱歉, 本遊戲在當前瀏覽器上可能運行緩慢! 使用chrome或者獲取獨立版以得到更好的體驗。 - savegameLevel: Level + browserWarning: 很抱歉, 本遊戲在當前瀏覽器上可能運行緩慢! 使用chrome或者獲取單機版以得到更好的體驗。 + savegameLevel: 級 savegameLevelUnknown: 未知關卡 continue: 繼續 newGame: 新遊戲 @@ -95,7 +95,7 @@ dialogs: later: 之後 restart: 重啟 reset: 重置 - getStandalone: 獲得獨立版 + getStandalone: 獲得單機版 deleteGame: 我知道我在做什麼 viewUpdate: 查看更新 showUpgrades: 顯示建築升級 @@ -129,10 +129,10 @@ dialogs: desc: 成功重置了所有按鍵! featureRestriction: title: 演示版 - desc: 你嘗試使用了 功能。該功能在演示版中不可用。請考慮購買獨立版以獲得更好的體驗。 + desc: 你嘗試使用了 功能。該功能在演示版中不可用。請考慮購買單機版以獲得更好的體驗。 oneSavegameLimit: title: 存檔數量限制 - desc: 演示版中只能保存一份存檔。請刪除舊存檔或者獲取獨立版! + desc: 演示版中只能保存一份存檔。請刪除舊存檔或者獲取單機版! updateSummary: title: 更新了! desc: "以下為自上次遊戲以來更新的內容:" @@ -153,9 +153,9 @@ dialogs: class='keybinding'>ALT: 反向放置傳送帶。
" createMarker: title: 創建標記 - desc: Give it a meaningful name, you can also include a short - key of a shape (Which you can generate here) - titleEdit: Edit Marker + desc: 給地圖標記起一個的名字。 你可以在名字中加入一個短代碼以加入圖形。 (你可以在 here + 生成短代碼。) + titleEdit: 修改標記 markerDemoLimit: desc: 在演示版中你只能創建兩個地圖標記。請獲取單機版以創建更多標記。 massCutConfirm: @@ -175,6 +175,14 @@ dialogs: renameSavegame: title: 重新命名存檔 desc: 你可以在這裡重新命名存檔 + tutorialVideoAvailable: + title: Tutorial Available + desc: There is a tutorial video available for this level! Would you like to + watch it? + tutorialVideoAvailableForeignLanguage: + title: Tutorial Available + desc: There is a tutorial video available for this level, but it is only + available in English. Would you like to watch it? ingame: keybindingsOverlay: moveMap: 移動 @@ -262,6 +270,30 @@ ingame:

提示:用你的游標按下並拖動傳送帶! 1_3_expand: 這不是一個放置型遊戲!建造更多的開採機和傳送帶來更快地完成目標。

提示:按住SHIFT鍵來放置多個開採機,用R鍵旋轉它們。 + 2_1_place_cutter: "Now place a Cutter to cut the circles in two + halves!

PS: The cutter always cuts from top to + bottom regardless of its orientation." + 2_2_place_trash: The cutter can clog and stall!

Use a + trash to get rid of the currently (!) not + needed waste. + 2_3_more_cutters: "Good job! Now place 2 more cutters to speed + up this slow process!

PS: Use the 0-9 + hotkeys to access buildings faster!" + 3_1_rectangles: "Now let's extract some rectangles! Build 4 + extractors and connect them to the hub.

PS: + Hold SHIFT while dragging a belt to activate + the belt planner!" + 21_1_place_quad_painter: Place the quad painter and get some + circles, white and + red color! + 21_2_switch_to_wires: Switch to the wires layer by pressing + E!

Then connect all four + inputs of the painter with cables! + 21_3_place_button: Awesome! Now place a Switch and connect it + with wires! + 21_4_press_button: "Press the switch to make it emit a truthy + signal and thus activate the painter.

PS: You + don't have to connect all inputs! Try wiring only two." colors: red: 紅 green: 綠 @@ -277,13 +309,13 @@ ingame: empty: 空 copyKey: Copy Key connectedMiners: - one_miner: 1 Miner - n_miners: Miners + one_miner: 1 個開採機 + n_miners: 個開採機 limited_items: Limited to watermark: title: Demo version desc: Click here to see the Steam version advantages! - get_on_steam: Get on steam + get_on_steam: 在 Steam 上取得 standaloneAdvantages: title: 取得單機版! no_thanks: 不用了,謝謝! @@ -296,7 +328,7 @@ ingame: desc: 邁向完全自動化! savegames: title: ∞ 個存檔 - desc: As many as your heart desires! + desc: 隨心所欲! upgrades: title: 20 個等級 desc: 試玩版只有 5 個。 @@ -401,7 +433,7 @@ buildings: balancer: default: name: 平衡機 - description: Multifunctional - Evenly distributes all inputs onto all outputs. + description: 多功能——將所有輸入平均分配到所有輸出。 merger: name: 合流機(右) description: 將兩個傳送帶整合成一個。 @@ -429,35 +461,31 @@ buildings: boolean (1 / 0). lever: default: - name: Switch + name: 信號切換器 description: Can be toggled to emit a boolean signal (1 / 0) on the wires layer, which can then be used to control for example an item filter. logic_gate: default: - name: AND Gate - description: Emits a boolean "1" if both inputs are truthy. (Truthy means shape, - color or boolean "1") + name: AND 邏輯閘 + description: 當輸入均為「真」時,輸出才為1。 (「真」值代表:形狀正確、顏色正確或布林值為1) not: - name: NOT Gate - description: Emits a boolean "1" if the input is not truthy. (Truthy means - shape, color or boolean "1") + name: NOT 邏輯閘 + description: 當輸入之ㄧ為「假」時,輸出才為1。 (「假」值代表:形狀不正確、顏色不正確或布林值為0) xor: - name: XOR Gate - description: Emits a boolean "1" if one of the inputs is truthy, but not both. - (Truthy means shape, color or boolean "1") + name: XOR 邏輯閘 + description: 當輸入均為「假」時,輸出才為1。 (「假」值代表:形狀不正確、顏色不正確或布林值為0) or: - name: OR Gate - description: Emits a boolean "1" if one of the inputs is truthy. (Truthy means - shape, color or boolean "1") + name: OR 邏輯閘 + description: 當輸入之ㄧ為「真」時,輸出才為1。 (「真」值代表:形狀正確、顏色正確或布林值為1) transistor: default: - name: Transistor - description: Forwards the bottom input if the side input is truthy (a shape, - color or "1"). + name: 電晶體 + description: 如果基極(側面)的輸入訊號為「真」,則把射極(底部)輸入的真假值複製到集極(頂部)的輸出。 + (「真」值代表:形狀正確、顏色正確或布林值為1) mirrored: - name: Transistor - description: Forwards the bottom input if the side input is truthy (a shape, - color or "1"). + name: 電晶體 + description: 如果基極(側面)的輸入訊號為「真」,則把射極(底部)輸入的真假值複製到集極(頂部)的輸出。 + (「真」值代表:形狀正確、顏色正確或布林值為1) filter: default: name: Filter @@ -471,54 +499,48 @@ buildings: color or boolean. reader: default: - name: Belt Reader + name: 傳送帶讀取機 description: Allows to measure the average belt throughput. Outputs the last read item on the wires layer (once unlocked). analyzer: default: - name: Shape Analyzer + name: 形狀分析機 description: Analyzes the top right quadrant of the lowest layer of the shape and returns its shape and color. comparator: default: - name: Compare + name: 比較機 description: Returns boolean "1" if both signals are exactly equal. Can compare shapes, items and booleans. virtual_processor: default: - name: Virtual Cutter - description: Virtually cuts the shape into two halves. + name: 虛擬切割機 + description: 虛擬地將圖形從上到下切開並輸出。 rotater: - name: Virtual Rotater - description: Virtually rotates the shape, both clockwise and counter-clockwise. + name: 虛擬旋轉機 + description: 虛擬地將圖形順時針或逆時針旋轉。 unstacker: - name: Virtual Unstacker - description: Virtually extracts the topmost layer to the right output and the - remaining ones to the left. + name: 虛擬提取機 + description: 虛擬地提取最上層的圖形到右方輸出,剩下的圖形由左方輸出。 stacker: - name: Virtual Stacker - description: Virtually stacks the right shape onto the left. + name: 虛擬堆疊機 + description: 虛擬地將輸入的圖形拼貼在一起。如果不能被直接拼貼,右邊的圖形會被疊在左邊的圖形上面。 painter: - name: Virtual Painter - description: Virtually paints the shape from the bottom input with the shape on - the right input. + name: 虛擬上色機 + description: 虛擬地將整個圖形塗上輸入的顏色。 item_producer: default: - name: Item Producer - description: Available in sandbox mode only, outputs the given signal from the - wires layer on the regular layer. + name: 物品製造機 + description: 沙盒模式專有,將電路層的輸入轉化成一般層的輸出。 storyRewards: reward_cutter_and_trash: title: 切割圖形 - desc: You just unlocked the cutter, which cuts shapes in half - from top to bottom regardless of its - orientation!

Be sure to get rid of the waste, or - otherwise it will clog and stall - For this purpose - I have given you the trash, which destroys - everything you put into it! + desc: 切割機已解鎖。不論切割機的方向,它都會把圖形垂直地切成兩半。 +

記得把不需要的部分處理掉,否則這個這個建築會停止運作。 + 為此我給你準備了垃圾桶,它會把所有放進去的物品銷毀掉。 reward_rotater: title: 順時針旋轉 - desc: 旋轉機已解鎖。它會順時針旋轉輸入的圖形90度。 + desc: 順時針旋轉機已解鎖。它會順時針旋轉輸入的圖形90度。 reward_painter: title: 上色 desc: 上色機已解鎖。開採一些顏色,用上色機把顏色和圖形混合,就可以為圖形著色。

備註:如果你是色盲,設置中有色盲模式可以選。 @@ -529,7 +551,7 @@ storyRewards: title: 混合 desc: 混合機已解鎖。如果沒有重疊的部分,混合機會嘗試把兩個輸入的圖形拼貼在一起。如果有重疊的部分,右邊的輸入會被到左邊的輸入上方! reward_splitter: - title: 分離/合併 + title: 分流 desc: You have unlocked a splitter variant of the balancer - It accepts one input and splits them into two! @@ -538,28 +560,24 @@ storyRewards: desc: 隧道已解鎖。你現在可以從其他傳送帶或建築底下運送物品了! reward_rotater_ccw: title: 逆時針旋轉 - desc: You have unlocked a variant of the rotater - It allows - you to rotate shapes counter-clockwise! To build it, select the - rotater and press 'T' to cycle through its - variants! + desc: 逆時針旋轉機已解鎖。它會逆時針旋轉輸入的圖形90度。 + 逆時針旋轉機是順時針旋轉機的變體。選擇「順時針旋轉機」並按「T」來切換變體就能創建。 reward_miner_chainable: - title: 鏈式開採機 - desc: "You have unlocked the chained extractor! It can - forward its resources to other extractors so you - can more efficiently extract resources!

PS: The old - extractor has been replaced in your toolbar now!" + title: 鏈式開採 + desc: "鏈式開採機變體已解鎖。它是開採機的一個變體。 + 它可以將開採出來的資源傳遞給其他的開採機,使得資源提取更加高效!

PS: + 工具列中舊的開採機已被取代。" reward_underground_belt_tier_2: title: 貳級隧道 desc: 貳級隧道變體已解鎖。這個隧道有更長的傳輸距離。你還可以混用不同的隧道變體! reward_cutter_quad: - title: 四分切割機 - desc: You have unlocked a variant of the cutter - It allows you - to cut shapes in four parts instead of just two! + title: 四分切割 + desc: 您已解鎖了切割機的變體:四分切割機。 + 它允許您將形狀直接切割為四個部分,而不是兩個! reward_painter_double: - title: 雙倍上色機 - desc: You have unlocked a variant of the painter - It works - similar to the regular painter but processes two shapes at - once, consuming just one color instead of two! + title: 雙倍上色 + desc: 您已經解鎖了上色機的變體:雙倍上色機。 + 它的運作方式跟上色機類似,但一次能處理兩個形狀,而且只消耗一種顏色而不是兩種顏色! reward_storage: title: 倉庫 desc: 倉庫 已解鎖: @@ -582,14 +600,12 @@ storyRewards: 你生產過的所有圖形都會被用來升級建築。" no_reward_freeplay: title: 下一關 - desc: 恭喜你!另外,我們已經計劃在獨立版中加入更多內容! + desc: 恭喜你!另外,我們已經計劃在單機版中加入更多內容! reward_balancer: - title: Balancer - desc: The multifunctional balancer has been unlocked - It can - be used to build bigger factories by splitting and merging - items onto multiple belts! + title: 平衡物流 + desc: 平衡機已解鎖。在大型工廠中,平衡機負責合流或分流多個傳送帶上的物品。 reward_merger: - title: Compact Merger + title: 合流 desc: You have unlocked a merger variant of the balancer - It accepts two inputs and merges them into one belt! @@ -638,7 +654,8 @@ storyRewards: mechanics!

For the beginning I unlocked you the Quad Painter - Connect the slots you would like to paint with on the wires layer!

To switch to the wires layer, press - E." + E.

PS: Enable hints in + the settings to activate the wires tutorial!" reward_filter: title: Item Filter desc: You unlocked the Item Filter! It will route items either @@ -684,7 +701,7 @@ settings: description: 改變語言。所有的翻譯皆由玩家提供,且有可能正在施工中! fullscreen: title: 全螢幕 - description: 全螢幕以獲得更好的遊戲體驗。僅在獨立版中可用。 + description: 全螢幕以獲得更好的遊戲體驗。僅在單機版中可用。 soundsMuted: title: 關閉音效 description: 關閉所有音效。 @@ -747,11 +764,11 @@ settings: title: 依建築類型旋轉 description: 每個建築類型,將會分別記住您最後一次使用的旋轉方向。 如果您常常切換不同類型的建築,這樣可能會更方便。 soundVolume: - title: Sound Volume - description: Set the volume for sound effects + title: 音效 + description: 音效設定 musicVolume: - title: Music Volume - description: Set the volume for music + title: 音樂 + description: 音樂設定 lowQualityMapResources: title: Low Quality Map Resources description: Simplifies the rendering of resources on the map when zoomed in to @@ -792,6 +809,10 @@ settings: title: Zoom towards Cursor description: If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen. + mapResourcesScale: + title: Map Resources Size + description: Controls the size of the shapes on the map overview (when zooming + out). rangeSliderPercentage: % keybindings: title: 按鍵設置 @@ -847,12 +868,12 @@ keybindings: switchDirectionLockSide: 規劃器:換邊 pipette: Pipette menuClose: Close Menu - switchLayers: Switch layers - wire: Energy Wire - balancer: Balancer + switchLayers: 更換層 + wire: 電線 + balancer: 平衡機 storage: Storage constant_signal: Constant Signal - logic_gate: Logic Gate + logic_gate: 邏輯閘 lever: Switch (regular) filter: Filter wire_tunnel: Wire Crossing @@ -860,9 +881,9 @@ keybindings: reader: Belt Reader virtual_processor: Virtual Cutter transistor: Transistor - analyzer: Shape Analyzer - comparator: Compare - item_producer: Item Producer (Sandbox) + analyzer: 形狀分析機 + comparator: 比對機 + item_producer: 物品生產機(沙盒模式) copyWireValue: "Wires: Copy value below cursor" backwardsModifier: "Modifier: Cycle backwards" about: @@ -873,7 +894,7 @@ about: 如果你想參與開發,請查看shapez.io on github

- 這個遊戲的開發少不了熱情的Discord社區。請加入我們的Discord 服務器

+ 這個遊戲的開發少不了熱情的 Discord 社區。請加入我們的Discord 伺服器

本遊戲的音樂由Peppsen製作——他是個很棒的伙伴。

@@ -889,63 +910,59 @@ demo: exportingBase: 匯出工廠截圖 settingNotAvailable: 在演示版中不可用。 tips: - - The hub accepts input of any kind, not just the current shape! - - Make sure your factories are modular - it will pay out! - - Don't build too close to the hub, or it will be a huge chaos! - - If stacking does not work, try switching the inputs. - - You can toggle the belt planner direction by pressing R. - - Holding CTRL allows dragging of belts without auto-orientation. - - Ratios stay the same, as long as all upgrades are on the same Tier. - - Serial execution is more efficient than parallel. - - You will unlock more variants of buildings later in the game! - - You can use T to switch between different variants. - - Symmetry is key! - - You can weave different tiers of tunnels. - - Try to build compact factories - it will pay out! - - The painter has a mirrored variant which you can select with T - - Having the right building ratios will maximize efficiency. - - At maximum level, 5 extractors will fill a single belt. - - Don't forget about tunnels! - - You don't need to divide up items evenly for full efficiency. - - Holding SHIFT will activate the belt planner, letting you place - long lines of belts easily. - - Cutters always cut vertically, regardless of their orientation. - - To get white mix all three colors. - - The storage buffer priorities the first output. - - Invest time to build repeatable designs - it's worth it! - - Holding CTRL allows to place multiple buildings. - - You can hold ALT to invert the direction of placed belts. - - Efficiency is key! - - Shape patches that are further away from the hub are more complex. - - Machines have a limited speed, divide them up for maximum efficiency. - - Use balancers to maximize your efficiency. - - Organization is important. Try not to cross conveyors too much. - - Plan in advance, or it will be a huge chaos! - - Don't remove your old factories! You'll need them to unlock upgrades. - - Try beating level 20 on your own before seeking for help! - - Don't complicate things, try to stay simple and you'll go far. - - You may need to re-use factories later in the game. Plan your factories to - be re-usable. - - Sometimes, you can find a needed shape in the map without creating it with - stackers. - - Full windmills / pinwheels can never spawn naturally. - - Color your shapes before cutting for maximum efficiency. - - With modules, space is merely a perception; a concern for mortal men. - - Make a separate blueprint factory. They're important for modules. - - Have a closer look on the color mixer, and your questions will be answered. - - Use CTRL + Click to select an area. - - Building too close to the hub can get in the way of later projects. - - The pin icon next to each shape in the upgrade list pins it to the screen. - - Mix all primary colors together to make white! - - You have an infinite map, don't cramp your factory, expand! - - Also try Factorio! It's my favorite game. - - The quad cutter cuts clockwise starting from the top right! - - You can download your savegames in the main menu! - - This game has a lot of useful keybindings! Be sure to check out the - settings page. - - This game has a lot of settings, be sure to check them out! - - The marker to your hub has a small compass to indicate its direction! - - To clear belts, cut the area and then paste it at the same location. - - Press F4 to show your FPS and Tick Rate. - - Press F4 twice to show the tile of your mouse and camera. - - You can click a pinned shape on the left side to unpin it. + - 基地接受任何輸入,不只是當前要求的圖形! + - 盡量讓工廠模組化,會有回報的! + - 建築不要距離基地太近,否則容易混亂! + - 如果堆疊不如預期,嘗試將輸入端互換。 + - 輸送帶的方向可以按 R 更換。 + - 按住 CTRL 來防止輸送帶自動轉向。 + - 同等級的生產比例會是一樣的。 + - 串聯比並聯更有效率。 + - 遊戲後期可以解鎖更多建築變體! + - 玩家可以按 T 來選擇不同變體。 + - 對稱是關鍵! + - 不同等級的隧道可以相互交織。 + - 盡量讓工廠保持緊密,會有回報的! + - 上色機有對稱的變體。按 T 來選擇不同變體。 + - 正確的建築比例可以將效率最大化。 + - 最高級時,五個開採機可填滿一個輸送帶。 + - 別忘記使用隧道! + - 最高效率不一定來自均勻切割。 + - 按住 SHIFT 輕鬆規劃長距離輸送帶。 + - 不論擺放方向,切割機永遠做垂直切割。 + - 白 = 紅 + 綠 + 藍。 + - 倉庫優先從左側輸出。 + - 花點時間研究可以重複利用的設計,會有回報的! + - 按住 CTRL 可以一次放置多個建築。 + - 按住 ALT 以反轉輸送帶的放置方向。 + - 效率是關鍵! + - 離基地越遠得圖形叢越複雜。 + - 機器的運作速度有上限,多放幾個增加生產效率。 + - 用平衡機讓效率最大化。 + - 規劃很重要,盡量別讓輸送帶錯綜複雜。 + - 預先規劃,不然會混亂不堪! + - 不要刪除舊的工廠,解鎖更新能會需要它們。 + - 先試著靠自己破第20關再去尋求幫助。 + - 不要讓東西複雜化,保持簡單則行的遠。 + - 遊戲中有時需要重複利用工廠,設計時記得考量重複利用性。 + - 有些圖形地圖上就找的到,不必自行堆疊。 + - 地圖永遠部會自然生成完整的風車圖形。 + - 先上色再切割會比較有效率。 + - 有了模組,空間淪為假議題、凡夫俗子的憂思。 + - 創建一個藍圖工廠,這對模組化很有幫助。 + - 靠近一點看混色機,你會找到解答。 + - 按 CTRL + 點選想選取的區域。 + - 離基地太近的建築可能在未來會礙事。 + - 更新目錄的每個圖形旁都有圖釘,點選即可把圖形釘在螢幕上(目標圖形旁)。 + - 混合所有基本色就會得到白色! + - 地圖是無限延展的,別執著,擴張吧! + - Factorio 是我最喜歡的遊戲,非常推薦! + - 四分切割機從右上角順時鐘地輸出圖形的四個區塊。 + - 你可以從主畫面下載存檔。 + - 去設定頁看看,有很多有用的按鍵組合! + - 有很多東西都可以設定,有空的話去設定頁看看。 + - 看不見基地時,基地的標示左側有個小指南針會提醒你它的方位。 + - 清除輸送帶有個方法:複製它再原地貼上。 + - 按 F4 來顯示螢幕的幀數(FPS)與刷新率(Tick Rate)。 + - 按 F4 兩次來顯示相機和游標的絕對位置。 + - 在已標記的圖形上按左鍵去除標記。 diff --git a/version b/version index 867e5243..cb174d58 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.2.0 \ No newline at end of file +1.2.1 \ No newline at end of file