1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-17 04:01:51 +00:00

Updated to 1.4.4

This commit is contained in:
DJ1TJOO 2021-09-01 17:55:44 +02:00
commit aed74cd263
106 changed files with 4930 additions and 2547 deletions

View File

@ -39,7 +39,7 @@ You can use [Gitpod](https://www.gitpod.io/) (an Online Open Source VS Code-like
- 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/)
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/tobspr/shapez.io)
## Helping translate

View File

@ -0,0 +1 @@
To build, place the lib64 folder from the wegame sdk for electron 13 in `wegame_sdk` and run the `wegame.main.standalone` gulp task.

View File

@ -51,8 +51,9 @@ function createWindow() {
webPreferences: {
nodeIntegration: true,
webSecurity: false,
contextIsolation: false,
},
// allowRunningInsecureContent: false,
allowRunningInsecureContent: false,
});
if (isLocal) {

View File

@ -10,7 +10,7 @@
"start": "electron --disable-direct-composition --in-process-gpu ."
},
"devDependencies": {
"electron": "3.1.13"
"electron": "^13.1.6"
},
"dependencies": {
"async-lock": "^1.2.8"

View File

@ -1,5 +1,5 @@
const railsdk = require("./wegame_sdk/railsdk.js");
const { dialog } = require("electron");
const { dialog, app, remote, ipcMain } = require("electron");
function init(isDev) {
console.log("Step 1: wegame: init");
@ -39,7 +39,7 @@ function init(isDev) {
event.state === railsdk.RailSystemState.kSystemStatePlatformExit ||
event.state === railsdk.RailSystemState.kSystemStateGameExitByAntiAddiction
) {
remote.app.exit();
app.exit();
}
}
});
@ -47,6 +47,17 @@ function init(isDev) {
function listen() {
console.log("wegame: listen");
ipcMain.handle("profanity-check", async (event, data) => {
if (data.length === 0) {
return "";
}
const result = railsdk.RailUtils.DirtyWordsFilter(data, true);
if (result.check_result.dirty_type !== 0 /** kRailDirtyWordsTypeNormalAllowWords */) {
return result.check_result.replace_string;
}
return data;
});
}
module.exports = { init, listen };

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -137,16 +137,20 @@
button.continue {
background: #555;
@include S(margin-right, 10px);
}
button.menu {
background: #555;
}
button.nextPuzzle {
background-color: $colorGreenBright;
}
> button {
@include S(min-width, 100px);
@include S(padding, 10px, 20px);
@include S(padding, 8px, 16px);
@include S(margin, 0, 6px);
@include IncreasedClickArea(0px);
}
}

View File

@ -0,0 +1,41 @@
#ingame_HUD_PuzzleNextPuzzle {
position: absolute;
@include S(top, 17px);
@include S(right, 10px);
display: flex;
flex-direction: column;
align-items: flex-end;
backdrop-filter: blur(D(1px));
padding: D(3px);
> .button {
@include ButtonText;
@include IncreasedClickArea(0px);
pointer-events: all;
cursor: pointer;
position: relative;
color: #333438;
transition: all 0.12s ease-in-out;
text-transform: uppercase;
transition-property: opacity, transform;
@include PlainText;
@include S(padding-right, 25px);
opacity: 1;
@include DarkThemeInvert;
&:hover {
opacity: 0.9 !important;
}
&.pressed {
transform: scale(0.95) !important;
}
& {
/* @load-async */
background: uiResource("icons/state_next_button.png") right center / D(15px) no-repeat;
}
}
}

View File

@ -21,6 +21,7 @@
@import "adinplay";
@import "changelog_skins";
@import "states/wegame_splash";
@import "states/preload";
@import "states/main_menu";
@import "states/ingame";
@ -64,6 +65,7 @@
@import "ingame_hud/puzzle_play_settings";
@import "ingame_hud/puzzle_play_metadata";
@import "ingame_hud/puzzle_complete_notification";
@import "ingame_hud/puzzle_next";
// prettier-ignore
$elements:
@ -82,6 +84,7 @@ ingame_HUD_PinnedShapes,
ingame_HUD_GameMenu,
ingame_HUD_KeybindingOverlay,
ingame_HUD_PuzzleBackToMenu,
ingame_HUD_PuzzleNextPuzzle,
ingame_HUD_PuzzleEditorReview,
ingame_HUD_PuzzleEditorControls,
ingame_HUD_PuzzleEditorTitle,
@ -133,6 +136,7 @@ body.uiHidden {
#ingame_HUD_GameMenu,
#ingame_HUD_PinnedShapes,
#ingame_HUD_PuzzleBackToMenu,
#ingame_HUD_PuzzleNextPuzzle,
#ingame_HUD_PuzzleEditorReview,
#ingame_HUD_Notifications,
#ingame_HUD_TutorialHints,

View File

@ -550,6 +550,16 @@
}
}
#crosspromo {
position: absolute;
@include S(bottom, 50px);
@include S(right, 20px);
@include S(width, 190px);
@include S(height, 100px);
pointer-events: all;
border: 0;
}
.footer {
display: grid;
flex-grow: 1;
@ -561,10 +571,45 @@
box-sizing: border-box;
@include S(grid-gap, 4px);
&.china {
&.noLinks {
grid-template-columns: auto 1fr;
}
&.wegameDisclaimer {
@include SuperSmallText;
display: grid;
justify-content: center;
grid-template-columns: 1fr auto 1fr;
text-align: center;
> .disclaimer {
grid-column: 2 / 3;
@include DarkThemeOverride {
color: #fff;
}
}
> .rating {
grid-column: 3 / 4;
justify-self: end;
align-self: end;
@include S(width, 32px);
@include S(height, 40px);
background: green;
cursor: pointer !important;
pointer-events: all;
@include S(border-radius, 4px);
overflow: hidden;
& {
/* @load-async */
background: #fff uiResource("wegame_isbn_rating.jpg") center center / contain no-repeat;
}
}
}
.author {
flex-grow: 1;
text-align: right;

View File

@ -15,8 +15,81 @@
}
> .container {
.searchForm {
display: flex;
align-items: center;
justify-content: center;
color: #333;
background: $accentColorBright;
@include S(padding, 5px);
@include S(border-radius, $globalBorderRadius);
flex-wrap: wrap;
@include DarkThemeOverride {
background: $accentColorDark;
}
input.search {
color: #333;
margin: 0;
display: inline-block;
flex-grow: 1;
@include S(padding, 5px, 10px);
@include S(min-width, 50px);
&::placeholder {
color: #aaa;
}
}
select {
color: #333;
border: 0;
@include S(padding, 5px);
@include S(border-radius, $globalBorderRadius);
@include S(padding, 7px, 10px);
@include S(margin-left, 5px);
@include PlainText;
}
.filterCompleted {
@include S(margin-left, 20px);
pointer-events: all;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
text-transform: uppercase;
@include PlainText;
@include S(margin-right, 10px);
@include DarkThemeOverride {
color: #bbbbc4;
}
input {
@include S(width, 15px);
@include S(height, 15px);
@include S(margin-right, 5px);
@include S(border-radius, $globalBorderRadius);
border: 0;
}
}
button[type="submit"] {
@include S(padding, 7px, 10px, 5px);
@include S(margin-left, 20px);
@include S(margin-top, 4px);
@include S(margin-bottom, 4px);
margin-left: auto;
}
}
> .mainContent {
overflow: hidden;
display: flex;
flex-direction: column;
> .categoryChooser {
> .categories {
@ -79,8 +152,8 @@
@include S(grid-gap, 7px);
@include S(margin-top, 10px);
@include S(padding-right, 4px);
@include S(height, 320px);
overflow-y: scroll;
flex-grow: 1;
pointer-events: all;
position: relative;
@ -246,6 +319,9 @@
&.stage--hard {
color: $colorRedBright;
}
&.stage--unknown {
color: #888;
}
}
}

View File

@ -50,7 +50,8 @@
}
button.categoryButton,
button.about {
button.about,
button.privacy {
background-color: $colorCategoryButton;
color: #777a7f;
@ -68,6 +69,10 @@
}
}
button.privacy {
@include S(margin-top, 4px);
}
.versionbar {
@include S(margin-top, 10px);
@ -180,7 +185,8 @@
.container .content {
.sidebar {
button.categoryButton,
button.about {
button.about,
button.privacy {
color: #ccc;
background-color: darken($darkModeControlsBackground, 5);

View File

@ -0,0 +1,38 @@
#state_WegameSplashState {
background: #000 !important;
display: flex;
align-items: center;
justify-content: center;
.wrapper {
opacity: 0;
@include InlineAnimation(5.9s ease-in-out) {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
opacity: 0;
}
}
text-align: center;
color: #fff;
@include Heading;
strong {
display: block;
@include SuperHeading;
@include S(margin-bottom, 20px);
}
div {
@include S(margin-bottom, 10px);
}
}
}

View File

@ -34,6 +34,7 @@ import { RestrictionManager } from "./core/restriction_manager";
import { PuzzleMenuState } from "./states/puzzle_menu";
import { ClientAPI } from "./platform/api";
import { LoginState } from "./states/login";
import { WegameSplashState } from "./states/wegame_splash";
/**
* @typedef {import("./platform/achievement_provider").AchievementProviderInterface} AchievementProviderInterface
@ -155,6 +156,7 @@ export class Application {
registerStates() {
/** @type {Array<typeof GameState>} */
const states = [
WegameSplashState,
PreloadState,
MobileWarningState,
MainMenuState,
@ -330,8 +332,12 @@ export class Application {
Loader.linkAppAfterBoot(this);
if (G_WEGAME_VERSION) {
this.stateMgr.moveToState("WegameSplashState");
}
// Check for mobile
if (IS_MOBILE) {
else if (IS_MOBILE) {
this.stateMgr.moveToState("MobileWarningState");
} else {
this.stateMgr.moveToState("PreloadState");

View File

@ -1,4 +1,27 @@
export const CHANGELOG = [
{
version: "1.4.4",
date: "29.08.2021",
entries: [
"Hotfix: Fixed the balancer not distributing items evenly, caused by the 1.4.3 update. Sorry for any inconveniences!",
],
},
{
version: "1.4.3",
date: "28.08.2021",
entries: [
"You can now hold 'ALT' while hovering a building to see its output! (Thanks to Sense101) (PS: There is now a setting to have it always on!)",
"The map overview should now be much more performant! As a consequence, you can now zoom out farther! (Thanks to PFedak)",
"Puzzle DLC: There is now a 'next puzzle' button!",
"Puzzle DLC: There is now a search function!",
"Edit signal dialog now has the previous signal filled (Thanks to EmeraldBlock)",
"Further performance improvements (Thanks to PFedak)",
"Improved puzzle validation (Thanks to Sense101)",
"Input fields in dialogs should now automatically focus",
"Fix selected building being deselected at level up (Thanks to EmeraldBlock)",
"Updated translations",
],
},
{
version: "1.4.2",
date: "24.06.2021",

View File

@ -167,4 +167,25 @@ export class BufferMaintainer {
});
return canvas;
}
/**
* @param {object} param0
* @param {string} param0.key
* @param {string} param0.subKey
* @returns {HTMLCanvasElement?}
*
*/
getForKeyOrNullNoUpdate({ key, subKey }) {
let parent = this.cache.get(key);
if (!parent) {
return null;
}
// Now search for sub key
const cacheHit = parent.get(subKey);
if (cacheHit) {
return cacheHit.canvas;
}
return null;
}
}

View File

@ -7,7 +7,7 @@ export const IS_DEBUG =
export const SUPPORT_TOUCH = false;
export const IS_MAC = navigator.platform.toLowerCase().indexOf("mac") >= 0;
export const IS_MAC = navigator.platform.toLowerCase().indexOf("mac") >= 0 && !G_IS_DEV;
const smoothCanvas = true;
@ -17,6 +17,8 @@ export const THIRDPARTY_URLS = {
reddit: "https://www.reddit.com/r/shapezio",
shapeViewer: "https://viewer.shapez.io",
privacyPolicy: "https://tobspr.io/privacy.html",
standaloneStorePage: "https://store.steampowered.com/app/1318690/shapezio/",
stanaloneCampaignLink: "https://get.shapez.io",
puzzleDlcStorePage: "https://store.steampowered.com/app/1625400/shapezio__Puzzle_DLC",
@ -55,6 +57,7 @@ export const globalConfig = {
// Map
mapChunkSize: 16,
chunkAggregateSize: 4,
mapChunkOverviewMinZoom: 0.9,
mapChunkWorldSize: null, // COMPUTED

View File

@ -53,7 +53,7 @@ export default {
// Replace all translations with emojis to see which texts are translateable
// testTranslations: true,
// -----------------------------------------------------------------------------------
// Enables an inspector which shows information about the entity below the curosr
// Enables an inspector which shows information about the entity below the cursor
// enableEntityInspector: true,
// -----------------------------------------------------------------------------------
// Enables ads in the local build (normally they are deactivated there)

View File

@ -123,6 +123,4 @@ function catchErrors(message, source, lineno, colno, error) {
return true;
}
if (!G_IS_DEV) {
window.onerror = catchErrors;
}

View File

@ -91,26 +91,6 @@ export class GameState {
}
}
/**
*
* @param {string} nextStateId
* @param {object=} nextStatePayload
*/
watchAdAndMoveToState(nextStateId, nextStatePayload = {}) {
if (this.app.adProvider.getCanShowVideoAd() && this.app.isRenderable()) {
this.moveToState(
"WatchAdState",
{
nextStateId,
nextStatePayload,
},
true
);
} else {
this.moveToState(nextStateId, nextStatePayload);
}
}
/**
* Tracks clicks on a given element and calls the given callback *on this state*.
* If you want to call another function wrap it inside a lambda.

View File

@ -1,6 +1,7 @@
import { BaseItem } from "../game/base_item";
import { ClickDetector } from "./click_detector";
import { Signal } from "./signal";
import { getIPCRenderer } from "./utils";
/*
* ***************************************************
@ -107,6 +108,19 @@ export class FormElementInput extends FormElement {
updateErrorState() {
this.element.classList.toggle("errored", !this.isValid());
// profanity filter
if (G_WEGAME_VERSION) {
const value = String(this.element.value);
getIPCRenderer()
.invoke("profanity-check", value)
.then(newValue => {
if (value !== newValue && this.element) {
this.element.value = newValue;
}
});
}
}
isValid() {
@ -124,6 +138,7 @@ export class FormElementInput extends FormElement {
focus() {
this.element.focus();
this.element.select();
}
}

View File

@ -89,6 +89,11 @@ export class RestrictionManager extends ReadWriteProxy {
return false;
}
if (queryParamOptions.embedProvider === "gamedistribution") {
// also full version on gamedistribution
return false;
}
if (G_IS_DEV) {
return typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0;
}

View File

@ -734,6 +734,10 @@ const romanLiteralsCache = ["0"];
* @returns {string}
*/
export function getRomanNumber(number) {
if (G_WEGAME_VERSION) {
return String(number);
}
number = Math.max(0, Math.round(number));
if (romanLiteralsCache[number]) {
return romanLiteralsCache[number];

View File

@ -11,6 +11,7 @@ import { typeItemSingleton } from "../item_resolver";
* pos: Vector,
* direction: enumDirection,
* item: BaseItem,
* lastItem: BaseItem,
* progress: number?,
* cachedDestSlot?: import("./item_acceptor").ItemAcceptorLocatedSlot,
* cachedBeltPath?: BeltPath,
@ -51,6 +52,7 @@ export class ItemEjectorComponent extends Component {
clear() {
for (const slot of this.slots) {
slot.item = null;
slot.lastItem = null;
slot.progress = 0;
}
}
@ -67,6 +69,7 @@ export class ItemEjectorComponent extends Component {
pos: slot.pos,
direction: slot.direction,
item: null,
lastItem: null,
progress: 0,
cachedDestSlot: null,
cachedTargetEntity: null,
@ -131,6 +134,7 @@ export class ItemEjectorComponent extends Component {
return false;
}
this.slots[slotIndex].item = item;
this.slots[slotIndex].lastItem = item;
this.slots[slotIndex].progress = 0;
return true;
}

View File

@ -73,6 +73,12 @@ export class ItemProcessorComponent extends Component {
// Type of processing requirement
this.processingRequirement = processingRequirement;
/**
* Our current inputs
* @type {Map<number, BaseItem>}
*/
this.inputSlots = new Map();
this.clear();
}
@ -82,11 +88,13 @@ export class ItemProcessorComponent extends Component {
// sure the outputs always match
this.nextOutputSlot = 0;
this.inputSlots.clear();
/**
* Our current inputs
* @type {Array<{ item: BaseItem, sourceSlot: number }>}
* Current input count
* @type {number}
*/
this.inputSlots = [];
this.inputCount = 0;
/**
* What we are currently processing, empty if we don't produce anything rn
@ -115,19 +123,17 @@ export class ItemProcessorComponent extends Component {
this.type === enumItemProcessorTypes.goal
) {
// Hub has special logic .. not really nice but efficient.
this.inputSlots.push({ item, sourceSlot });
this.inputSlots.set(this.inputCount, item);
this.inputCount++;
return true;
}
// Check that we only take one item per slot
for (let i = 0; i < this.inputSlots.length; ++i) {
const slot = this.inputSlots[i];
if (slot.sourceSlot === sourceSlot) {
if (this.inputSlots.has(sourceSlot)) {
return false;
}
}
this.inputSlots.push({ item, sourceSlot });
this.inputSlots.set(sourceSlot, item);
this.inputCount++;
return true;
}
}

View File

@ -119,7 +119,7 @@ export class GameMode extends BasicSerializableObject {
/** @returns {number} */
getMinimumZoom() {
return 0.1;
return 0.06;
}
/** @returns {number} */

View File

@ -16,6 +16,7 @@ import { HUDEntityDebugger } from "./parts/entity_debugger";
import { HUDModalDialogs } from "./parts/modal_dialogs";
import { enumNotificationType } from "./parts/notifications";
import { HUDSettingsMenu } from "./parts/settings_menu";
import { HUDShapeTooltip } from "./parts/shape_tooltip";
import { HUDVignetteOverlay } from "./parts/vignette_overlay";
import { TrailerMaker } from "./trailer_maker";
@ -49,6 +50,8 @@ export class GameHUD {
blueprintPlacer: new HUDBlueprintPlacer(this.root),
buildingPlacer: new HUDBuildingPlacer(this.root),
shapeTooltip: new HUDShapeTooltip(this.root),
// Must always exist
settingsMenu: new HUDSettingsMenu(this.root),
debugInfo: new HUDDebugInfo(this.root),
@ -189,6 +192,7 @@ export class GameHUD {
"colorBlindHelper",
"changesDebugger",
"minerHighlight",
"shapeTooltip",
];
for (let i = 0; i < partsOrder.length; ++i) {

View File

@ -0,0 +1,25 @@
import { makeDiv } from "../../../core/utils";
import { T } from "../../../translations";
import { PuzzlePlayGameMode } from "../../modes/puzzle_play";
import { BaseHUDPart } from "../base_hud_part";
export class HUDPuzzleNextPuzzle extends BaseHUDPart {
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_PuzzleNextPuzzle");
this.button = document.createElement("button");
this.button.classList.add("button");
this.button.innerText = T.ingame.puzzleCompletion.nextPuzzle;
this.element.appendChild(this.button);
this.trackClicks(this.button, this.nextPuzzle);
}
initialize() {}
nextPuzzle() {
const gameMode = /** @type {PuzzlePlayGameMode} */ (this.root.gameMode);
this.root.gameState.moveToState("PuzzleMenuState", {
continueQueue: gameMode.nextPuzzles,
});
}
}

View File

@ -128,7 +128,6 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
this.root.hud.signals.buildingsSelectedForCopy.add(this.abortPlacement, this);
this.root.hud.signals.pasteBlueprintRequested.add(this.abortPlacement, this);
this.root.signals.storyGoalCompleted.add(() => this.signals.variantChanged.dispatch());
this.root.signals.storyGoalCompleted.add(() => this.currentMetaBuilding.set(null));
this.root.signals.upgradePurchased.add(() => this.signals.variantChanged.dispatch());
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);

View File

@ -158,8 +158,13 @@ export class HUDInteractiveTutorial extends BaseHUDPart {
onHintChanged(hintId) {
this.elementDescription.innerHTML = T.ingame.interactiveTutorial.hints[hintId];
const folder = G_WEGAME_VERSION
? "interactive_tutorial.cn.noinline"
: "interactive_tutorial.noinline";
this.elementGif.style.backgroundImage =
"url('" + cachebust("res/ui/interactive_tutorial.noinline/" + hintId + ".gif") + "')";
"url('" + cachebust("res/ui/" + folder + "/" + hintId + ".gif") + "')";
this.element.classList.toggle("animEven");
this.element.classList.toggle("animOdd");
}

View File

@ -6,13 +6,8 @@ import { InputReceiver } from "../../../core/input_receiver";
import { makeDiv } from "../../../core/utils";
import { SOUNDS } from "../../../platform/sound";
import { T } from "../../../translations";
import { enumColors } from "../../colors";
import { ColorItem } from "../../items/color_item";
import { finalGameShape, rocketShape } from "../../modes/regular";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { ShapeItem } from "../../items/shape_item";
import { ShapeDefinition } from "../../shape_definition";
export class HUDPuzzleCompleteNotification extends BaseHUDPart {
initialize() {
@ -68,10 +63,21 @@ export class HUDPuzzleCompleteNotification extends BaseHUDPart {
this.menuBtn.classList.add("menu", "styledButton");
this.menuBtn.innerText = T.ingame.puzzleCompletion.menuBtn;
buttonBar.appendChild(this.menuBtn);
this.trackClicks(this.menuBtn, () => {
this.close(true);
});
const gameMode = /** @type {PuzzlePlayGameMode} */ (this.root.gameMode);
if (gameMode.nextPuzzles.length > 0) {
this.nextPuzzleBtn = document.createElement("button");
this.nextPuzzleBtn.classList.add("nextPuzzle", "styledButton");
this.nextPuzzleBtn.innerText = T.ingame.puzzleCompletion.nextPuzzle;
buttonBar.appendChild(this.nextPuzzleBtn);
this.trackClicks(this.nextPuzzleBtn, () => {
this.nextPuzzle();
});
}
}
updateState() {
@ -93,6 +99,15 @@ export class HUDPuzzleCompleteNotification extends BaseHUDPart {
return this.visible;
}
nextPuzzle() {
const gameMode = /** @type {PuzzlePlayGameMode} */ (this.root.gameMode);
gameMode.trackCompleted(this.userDidLikePuzzle, Math.round(this.timeOfCompletion)).then(() => {
this.root.gameState.moveToState("PuzzleMenuState", {
continueQueue: gameMode.nextPuzzles,
});
});
}
close(toMenu) {
/** @type {PuzzlePlayGameMode} */ (this.root.gameMode)
.trackCompleted(this.userDidLikePuzzle, Math.round(this.timeOfCompletion))

View File

@ -81,7 +81,7 @@ export class HUDPuzzleEditorReview extends BaseHUDPart {
closeLoading();
//if it took so little ticks that it must have autocompeted
if (simulatedTicks <= 300) {
if (simulatedTicks <= 500) {
this.root.hud.parts.dialogs.showWarning(
T.puzzleMenu.validation.title,
T.puzzleMenu.validation.autoComplete

View File

@ -149,8 +149,9 @@ export class HUDPuzzleEditorSettings extends BaseHUDPart {
assertAlways(false, "Failed to re-place building in trim");
}
if (building.components.ConstantSignal) {
result.components.ConstantSignal.signal = building.components.ConstantSignal.signal;
for (const key in building.components) {
/** @type {import("../../../core/global_registries").Component} */ (building
.components[key]).copyAdditionalStateTo(result.components[key]);
}
}
});

View File

@ -0,0 +1,100 @@
import { DrawParameters } from "../../../core/draw_parameters";
import { enumDirectionToVector, Vector } from "../../../core/vector";
import { Entity } from "../../entity";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { THEME } from "../../theme";
import { BaseHUDPart } from "../base_hud_part";
export class HUDShapeTooltip extends BaseHUDPart {
createElements(parent) {}
initialize() {
/** @type {Vector} */
this.currentTile = new Vector(0, 0);
/** @type {Entity} */
this.currentEntity = null;
this.isPlacingBuilding = false;
this.root.signals.entityQueuedForDestroy.add(() => {
this.currentEntity = null;
}, this);
this.root.hud.signals.selectedPlacementBuildingChanged.add(metaBuilding => {
this.isPlacingBuilding = metaBuilding;
}, this);
}
isActive() {
const hudParts = this.root.hud.parts;
const active =
this.root.app.settings.getSetting("shapeTooltipAlwaysOn") ||
this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.showShapeTooltip).pressed;
// return false if any other placer is active
return (
active &&
!this.isPlacingBuilding &&
!hudParts.massSelector.currentSelectionStartWorld &&
hudParts.massSelector.selectedUids.size < 1 &&
!hudParts.blueprintPlacer.currentBlueprint.get()
);
}
/**
*
* @param {DrawParameters} parameters
*/
draw(parameters) {
if (this.isActive()) {
const mousePos = this.root.app.mousePosition;
if (mousePos) {
const tile = this.root.camera.screenToWorld(mousePos.copy()).toTileSpace();
if (!tile.equals(this.currentTile)) {
this.currentTile = tile;
const entity = this.root.map.getLayerContentXY(tile.x, tile.y, this.root.currentLayer);
if (entity && entity.components.ItemProcessor && entity.components.ItemEjector) {
this.currentEntity = entity;
} else {
this.currentEntity = null;
}
}
}
if (!this.currentEntity) {
return;
}
const ejectorComp = this.currentEntity.components.ItemEjector;
const staticComp = this.currentEntity.components.StaticMapEntity;
const bounds = staticComp.getTileSize();
const totalArea = bounds.x * bounds.y;
const maxSlots = totalArea < 2 ? 1 : 1e10;
let slotsDrawn = 0;
for (let i = 0; i < ejectorComp.slots.length; ++i) {
const slot = ejectorComp.slots[i];
if (!slot.lastItem) {
continue;
}
if (++slotsDrawn > maxSlots) {
continue;
}
/** @type {Vector} */
const drawPos = staticComp.localTileToWorld(slot.pos).toWorldSpaceCenterOfTile();
slot.lastItem.drawItemCenteredClipped(drawPos.x, drawPos.y, parameters, 25);
}
}
}
}

View File

@ -45,7 +45,7 @@ export class HUDWaypoints extends BaseHUDPart {
*/
createElements(parent) {
// Create the helper box on the lower right when zooming out
if (this.root.app.settings.getAllSettings().offerHints) {
if (this.root.app.settings.getAllSettings().offerHints && !G_WEGAME_VERSION) {
this.hintElement = makeDiv(
parent,
"ingame_HUD_Waypoints_Hint",
@ -121,10 +121,12 @@ export class HUDWaypoints extends BaseHUDPart {
}
// Catch mouse and key events
if (!G_WEGAME_VERSION) {
this.root.camera.downPreHandler.add(this.onMouseDown, this);
this.root.keyMapper
.getBinding(KEYMAPPINGS.navigation.createMarker)
.add(() => this.requestSaveMarker({}));
}
/**
* Stores at how much opacity the markers should be rendered on the map.

View File

@ -32,6 +32,8 @@ export const KEYMAPPINGS = {
toggleFPSInfo: { keyCode: 115 }, // F4
switchLayers: { keyCode: key("E") },
showShapeTooltip: { keyCode: 18 }, // ALT
},
navigation: {

View File

@ -80,6 +80,15 @@ export class GameLogic {
}
// Perform additional placement checks
if (this.root.gameMode.getIsEditor()) {
const toolbar = this.root.hud.parts.buildingsToolbar;
const id = entity.components.StaticMapEntity.getMetaBuilding().getId();
if (toolbar.buildingHandles[id].puzzleLocked) {
return false;
}
}
if (this.root.signals.prePlacementCheck.dispatch(entity, offset) === STOP_PROPAGATION) {
return false;
}

View File

@ -3,6 +3,7 @@ import { Vector } from "../core/vector";
import { BasicSerializableObject, types } from "../savegame/serialization";
import { BaseItem } from "./base_item";
import { Entity } from "./entity";
import { MapChunkAggregate } from "./map_chunk_aggregate";
import { MapChunkView } from "./map_chunk_view";
import { GameRoot } from "./root";
@ -31,6 +32,11 @@ export class BaseMap extends BasicSerializableObject {
* Mapping of 'X|Y' to chunk
* @type {Map<string, MapChunkView>} */
this.chunksById = new Map();
/**
* Mapping of 'X|Y' to chunk aggregate
* @type {Map<string, MapChunkAggregate>} */
this.aggregatesById = new Map();
}
/**
@ -55,6 +61,39 @@ export class BaseMap extends BasicSerializableObject {
return null;
}
/**
* Returns the chunk aggregate containing a given chunk
* @param {number} chunkX
* @param {number} chunkY
*/
getAggregateForChunk(chunkX, chunkY, createIfNotExistent = false) {
const aggX = Math.floor(chunkX / globalConfig.chunkAggregateSize);
const aggY = Math.floor(chunkY / globalConfig.chunkAggregateSize);
return this.getAggregate(aggX, aggY, createIfNotExistent);
}
/**
* Returns the given chunk aggregate by index
* @param {number} aggX
* @param {number} aggY
*/
getAggregate(aggX, aggY, createIfNotExistent = false) {
const aggIdentifier = aggX + "|" + aggY;
let storedAggregate;
if ((storedAggregate = this.aggregatesById.get(aggIdentifier))) {
return storedAggregate;
}
if (createIfNotExistent) {
const instance = new MapChunkAggregate(this.root, aggX, aggY);
this.aggregatesById.set(aggIdentifier, instance);
return instance;
}
return null;
}
/**
* Gets or creates a new chunk if not existent for the given tile
* @param {number} tileX

View File

@ -0,0 +1,154 @@
import { globalConfig } from "../core/config";
import { DrawParameters } from "../core/draw_parameters";
import { drawSpriteClipped } from "../core/draw_utils";
import { safeModulo } from "../core/utils";
import { GameRoot } from "./root";
export const CHUNK_OVERLAY_RES = 3;
export class MapChunkAggregate {
/**
*
* @param {GameRoot} root
* @param {number} x
* @param {number} y
*/
constructor(root, x, y) {
this.root = root;
this.x = x;
this.y = y;
/**
* Whenever something changes, we increase this number - so we know we need to redraw
*/
this.renderIteration = 0;
this.dirty = false;
/** @type {Array<boolean>} */
this.dirtyList = new Array(globalConfig.chunkAggregateSize ** 2).fill(true);
this.markDirty(0, 0);
}
/**
* Marks this chunk as dirty, rerendering all caches
* @param {number} chunkX
* @param {number} chunkY
*/
markDirty(chunkX, chunkY) {
const relX = safeModulo(chunkX, globalConfig.chunkAggregateSize);
const relY = safeModulo(chunkY, globalConfig.chunkAggregateSize);
this.dirtyList[relY * globalConfig.chunkAggregateSize + relX] = true;
if (this.dirty) {
return;
}
this.dirty = true;
++this.renderIteration;
this.renderKey = this.x + "/" + this.y + "@" + this.renderIteration;
}
/**
*
* @param {HTMLCanvasElement} canvas
* @param {CanvasRenderingContext2D} context
* @param {number} w
* @param {number} h
* @param {number} dpi
*/
generateOverlayBuffer(canvas, context, w, h, dpi) {
const prevKey = this.x + "/" + this.y + "@" + (this.renderIteration - 1);
const prevBuffer = this.root.buffers.getForKeyOrNullNoUpdate({
key: "agg@" + this.root.currentLayer,
subKey: prevKey,
});
const overlaySize = globalConfig.mapChunkSize * CHUNK_OVERLAY_RES;
let onlyDirty = false;
if (prevBuffer) {
context.drawImage(prevBuffer, 0, 0);
onlyDirty = true;
}
for (let x = 0; x < globalConfig.chunkAggregateSize; x++) {
for (let y = 0; y < globalConfig.chunkAggregateSize; y++) {
if (onlyDirty && !this.dirtyList[globalConfig.chunkAggregateSize * y + x]) continue;
this.root.map
.getChunk(
this.x * globalConfig.chunkAggregateSize + x,
this.y * globalConfig.chunkAggregateSize + y,
true
)
.generateOverlayBuffer(
context,
overlaySize,
overlaySize,
x * overlaySize,
y * overlaySize
);
}
}
this.dirty = false;
this.dirtyList.fill(false);
}
/**
* Overlay
* @param {DrawParameters} parameters
*/
drawOverlay(parameters) {
const aggregateOverlaySize =
globalConfig.mapChunkSize * globalConfig.chunkAggregateSize * CHUNK_OVERLAY_RES;
const sprite = this.root.buffers.getForKey({
key: "agg@" + this.root.currentLayer,
subKey: this.renderKey,
w: aggregateOverlaySize,
h: aggregateOverlaySize,
dpi: 1,
redrawMethod: this.generateOverlayBuffer.bind(this),
});
const dims = globalConfig.mapChunkWorldSize * globalConfig.chunkAggregateSize;
const extrude = 0.05;
// Draw chunk "pixel" art
parameters.context.imageSmoothingEnabled = false;
drawSpriteClipped({
parameters,
sprite,
x: this.x * dims - extrude,
y: this.y * dims - extrude,
w: dims + 2 * extrude,
h: dims + 2 * extrude,
originalW: aggregateOverlaySize,
originalH: aggregateOverlaySize,
});
parameters.context.imageSmoothingEnabled = true;
const resourcesScale = this.root.app.settings.getAllSettings().mapResourcesScale;
// Draw patch items
if (
this.root.currentLayer === "regular" &&
resourcesScale > 0.05 &&
this.root.camera.zoomLevel > 0.1
) {
const diameter = (70 / Math.pow(parameters.zoomLevel, 0.35)) * (0.2 + 2 * resourcesScale);
for (let x = 0; x < globalConfig.chunkAggregateSize; x++) {
for (let y = 0; y < globalConfig.chunkAggregateSize; y++) {
this.root.map
.getChunk(
this.x * globalConfig.chunkAggregateSize + x,
this.y * globalConfig.chunkAggregateSize + y,
true
)
.drawOverlayPatches(
parameters,
this.x * dims + x * globalConfig.mapChunkWorldSize,
this.y * dims + y * globalConfig.mapChunkWorldSize,
diameter
);
}
}
}
}
}

View File

@ -33,6 +33,7 @@ export class MapChunkView extends MapChunk {
markDirty() {
++this.renderIteration;
this.renderKey = this.x + "/" + this.y + "@" + this.renderIteration;
this.root.map.getAggregateForChunk(this.x, this.y, true).markDirty(this.x, this.y);
}
/**
@ -82,73 +83,41 @@ export class MapChunkView extends MapChunk {
}
/**
* Overlay
* @param {DrawParameters} parameters
* @param {number} xoffs
* @param {number} yoffs
* @param {number} diameter
*/
drawOverlay(parameters) {
const overlaySize = globalConfig.mapChunkSize * CHUNK_OVERLAY_RES;
const sprite = this.root.buffers.getForKey({
key: "chunk@" + this.root.currentLayer,
subKey: this.renderKey,
w: overlaySize,
h: overlaySize,
dpi: 1,
redrawMethod: this.generateOverlayBuffer.bind(this),
});
const dims = globalConfig.mapChunkWorldSize;
const extrude = 0.05;
// Draw chunk "pixel" art
parameters.context.imageSmoothingEnabled = false;
drawSpriteClipped({
parameters,
sprite,
x: this.x * dims - extrude,
y: this.y * dims - extrude,
w: dims + 2 * extrude,
h: dims + 2 * extrude,
originalW: overlaySize,
originalH: overlaySize,
});
parameters.context.imageSmoothingEnabled = true;
const resourcesScale = this.root.app.settings.getAllSettings().mapResourcesScale;
// Draw patch items
if (this.root.currentLayer === "regular" && resourcesScale > 0.05) {
const diameter = (70 / Math.pow(parameters.zoomLevel, 0.35)) * (0.2 + 2 * resourcesScale);
drawOverlayPatches(parameters, xoffs, yoffs, diameter) {
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 destX = xoffs + patch.pos.x * globalConfig.tileSize;
const destY = yoffs + patch.pos.y * globalConfig.tileSize;
patch.item.drawItemCenteredClipped(destX, destY, parameters, diameter);
}
}
}
}
/**
*
* @param {HTMLCanvasElement} canvas
* @param {CanvasRenderingContext2D} context
* @param {number} w
* @param {number} h
* @param {number} dpi
* @param {number=} xoffs
* @param {number=} yoffs
*/
generateOverlayBuffer(canvas, context, w, h, dpi) {
generateOverlayBuffer(context, w, h, xoffs, yoffs) {
context.fillStyle =
this.containedEntities.length > 0
? THEME.map.chunkOverview.filled
: THEME.map.chunkOverview.empty;
context.fillRect(0, 0, w, h);
context.fillRect(xoffs, yoffs, w, h);
if (this.root.app.settings.getAllSettings().displayChunkBorders) {
context.fillStyle = THEME.map.chunkBorders;
context.fillRect(0, 0, w, 1);
context.fillRect(0, 1, 1, h);
context.fillRect(xoffs, yoffs, w, 1);
context.fillRect(xoffs, yoffs + 1, 1, h);
}
for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
@ -174,8 +143,8 @@ export class MapChunkView extends MapChunk {
if (lowerContent) {
context.fillStyle = lowerContent.getBackgroundColorAsResource();
context.fillRect(
x * CHUNK_OVERLAY_RES,
y * CHUNK_OVERLAY_RES,
xoffs + x * CHUNK_OVERLAY_RES,
yoffs + y * CHUNK_OVERLAY_RES,
CHUNK_OVERLAY_RES,
CHUNK_OVERLAY_RES
);
@ -190,8 +159,8 @@ export class MapChunkView extends MapChunk {
const isFilled = overlayMatrix[dx + dy * 3];
if (isFilled) {
context.fillRect(
x * CHUNK_OVERLAY_RES + dx,
y * CHUNK_OVERLAY_RES + dy,
xoffs + x * CHUNK_OVERLAY_RES + dx,
yoffs + y * CHUNK_OVERLAY_RES + dy,
1,
1
);
@ -206,8 +175,8 @@ export class MapChunkView extends MapChunk {
data.rotationVariant
);
context.fillRect(
x * CHUNK_OVERLAY_RES,
y * CHUNK_OVERLAY_RES,
xoffs + x * CHUNK_OVERLAY_RES,
yoffs + y * CHUNK_OVERLAY_RES,
CHUNK_OVERLAY_RES,
CHUNK_OVERLAY_RES
);
@ -220,8 +189,8 @@ export class MapChunkView extends MapChunk {
if (lowerContent) {
context.fillStyle = lowerContent.getBackgroundColorAsResource();
context.fillRect(
x * CHUNK_OVERLAY_RES,
y * CHUNK_OVERLAY_RES,
xoffs + x * CHUNK_OVERLAY_RES,
yoffs + y * CHUNK_OVERLAY_RES,
CHUNK_OVERLAY_RES,
CHUNK_OVERLAY_RES
);
@ -233,7 +202,7 @@ export class MapChunkView extends MapChunk {
// Draw wires overlay
context.fillStyle = THEME.map.wires.overlayColor;
context.fillRect(0, 0, w, h);
context.fillRect(xoffs, yoffs, w, h);
for (let x = 0; x < globalConfig.mapChunkSize; ++x) {
const wiresArray = this.wireContents[x];
@ -244,8 +213,8 @@ export class MapChunkView extends MapChunk {
}
MapChunkView.drawSingleWiresOverviewTile({
context,
x: x * CHUNK_OVERLAY_RES,
y: y * CHUNK_OVERLAY_RES,
x: xoffs + x * CHUNK_OVERLAY_RES,
y: yoffs + y * CHUNK_OVERLAY_RES,
entity: content,
tileSizePixels: CHUNK_OVERLAY_RES,
});

View File

@ -5,6 +5,7 @@ import { freeCanvas, makeOffscreenBuffer } from "../core/buffer_utils";
import { Entity } from "./entity";
import { THEME } from "./theme";
import { MapChunkView } from "./map_chunk_view";
import { MapChunkAggregate } from "./map_chunk_aggregate";
/**
* This is the view of the map, it extends the map which is the raw model and allows
@ -164,6 +165,40 @@ export class MapView extends BaseMap {
}
}
/**
* Calls a given method on all given chunks
* @param {DrawParameters} parameters
* @param {function} method
*/
drawVisibleAggregates(parameters, method) {
const cullRange = parameters.visibleRect.allScaled(1 / globalConfig.tileSize);
const top = cullRange.top();
const right = cullRange.right();
const bottom = cullRange.bottom();
const left = cullRange.left();
const border = 0;
const minY = top - border;
const maxY = bottom + border;
const minX = left - border;
const maxX = right + border;
const aggregateTiles = globalConfig.chunkAggregateSize * globalConfig.mapChunkSize;
const aggStartX = Math.floor(minX / aggregateTiles);
const aggStartY = Math.floor(minY / aggregateTiles);
const aggEndX = Math.floor(maxX / aggregateTiles);
const aggEndY = Math.floor(maxY / aggregateTiles);
// Render y from top down for proper blending
for (let aggX = aggStartX; aggX <= aggEndX; ++aggX) {
for (let aggY = aggStartY; aggY <= aggEndY; ++aggY) {
const aggregate = this.root.map.getAggregate(aggX, aggY, true);
method.call(aggregate, parameters);
}
}
}
/**
* Draws the wires foreground
* @param {DrawParameters} parameters
@ -177,7 +212,7 @@ export class MapView extends BaseMap {
* @param {DrawParameters} parameters
*/
drawOverlay(parameters) {
this.drawVisibleChunks(parameters, MapChunkView.prototype.drawOverlay);
this.drawVisibleAggregates(parameters, MapChunkAggregate.prototype.drawOverlay);
}
/**

View File

@ -30,6 +30,7 @@ import { HUDPuzzlePlaySettings } from "../hud/parts/puzzle_play_settings";
import { MetaBlockBuilding } from "../buildings/block";
import { MetaBuilding } from "../meta_building";
import { gMetaBuildingRegistry } from "../../core/global_registries";
import { HUDPuzzleNextPuzzle } from "../hud/parts/HUDPuzzleNextPuzzle";
const logger = createLogger("puzzle-play");
const copy = require("clipboard-copy");
@ -43,8 +44,9 @@ export class PuzzlePlayGameMode extends PuzzleGameMode {
* @param {GameRoot} root
* @param {object} payload
* @param {import("../../savegame/savegame_typedefs").PuzzleFullData} payload.puzzle
* @param {Array<number> | undefined} payload.nextPuzzles
*/
constructor(root, { puzzle }) {
constructor(root, { puzzle, nextPuzzles }) {
super(root);
/** @type {Array<typeof MetaBuilding>} */
@ -95,6 +97,15 @@ export class PuzzlePlayGameMode extends PuzzleGameMode {
root.signals.postLoadHook.add(this.loadPuzzle, this);
this.puzzle = puzzle;
/**
* @type {Array<number>}
*/
this.nextPuzzles = nextPuzzles || [];
if (this.nextPuzzles.length > 0) {
this.additionalHudParts.puzzleNext = HUDPuzzleNextPuzzle;
}
}
loadPuzzle() {

View File

@ -344,6 +344,15 @@ export function generateLevelDefinitions(limitedVersion = false) {
reward: enumHubGoalRewards.reward_rotater_ccw,
},
// DEMO STOPS HERE
...(limitedVersion
? [
{
shapes: [{ key: "CrCrCrCr", amount: 0 }],
reward: enumHubGoalRewards.reward_demo_end,
},
]
: [
// 8
{
shapes: [{ key: "RbRb----", amount: 480 }], // painter t2
@ -380,25 +389,16 @@ export function generateLevelDefinitions(limitedVersion = false) {
// 13
// Tunnel Tier 2
{
shapes: [{ key: chinaShapes ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw", amount: 3800 }], // painting t3
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
},
// DEMO STOPS HERE
...(limitedVersion
? [
{
shapes: [
{
key: chinaShapes ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw",
amount: 0,
amount: 3800,
},
],
reward: enumHubGoalRewards.reward_demo_end,
], // painting t3
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
},
]
: [
// 14
// Belt reader
{
@ -585,7 +585,9 @@ export class RegularGameMode extends GameMode {
}
if (this.root.app.settings.getAllSettings().offerHints) {
if (!G_WEGAME_VERSION) {
this.additionalHudParts.tutorialHints = HUDPartTutorialHints;
}
this.additionalHudParts.interactiveTutorial = HUDInteractiveTutorial;
}
@ -595,12 +597,12 @@ export class RegularGameMode extends GameMode {
}
/** @type {(typeof MetaBuilding)[]} */
this.hiddenBuildings = [
MetaConstantProducerBuilding,
MetaGoalAcceptorBuilding,
MetaBlockBuilding,
MetaItemProducerBuilding,
];
this.hiddenBuildings = [MetaConstantProducerBuilding, MetaGoalAcceptorBuilding, MetaBlockBuilding];
// @ts-expect-error
if (!(G_IS_DEV || window.sandboxMode || queryParamOptions.sandboxMode)) {
this.hiddenBuildings.push(MetaItemProducerBuilding);
}
}
/**

View File

@ -49,11 +49,12 @@ export class ConstantSignalSystem extends GameSystemWithFilter {
// Ok, query, but also save the uid because it could get stale
const uid = entity.uid;
const signal = entity.components.ConstantSignal.signal;
const signalValueInput = new FormElementInput({
id: "signalValue",
label: fillInLinkIntoTranslation(T.dialogs.editSignal.descShortKey, THIRDPARTY_URLS.shapeViewer),
placeholder: "",
defaultValue: "",
defaultValue: signal ? signal.getAsCopyableKey() : "",
validator: val => this.parseSignalCode(entity, val),
});

View File

@ -32,8 +32,8 @@ const MAX_QUEUED_CHARGES = 2;
* Type of a processor implementation
* @typedef {{
* entity: Entity,
* items: Array<{ item: BaseItem, sourceSlot: number }>,
* itemsBySlot: Object<number, BaseItem>,
* items: Map<number, BaseItem>,
* inputCount: number,
* outItems: Array<ProducedItem>
* }} ProcessorImplementationPayload
*/
@ -189,7 +189,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
// DEFAULT
// By default, we can start processing once all inputs are there
case null: {
return processorComp.inputSlots.length >= processorComp.inputsPerCharge;
return processorComp.inputCount >= processorComp.inputsPerCharge;
}
// QUAD PAINTER
@ -197,18 +197,12 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
case enumItemProcessorRequirements.painterQuad: {
const pinsComp = entity.components.WiredPins;
/** @type {Object.<number, { item: BaseItem, sourceSlot: number }>} */
const itemsBySlot = {};
for (let i = 0; i < processorComp.inputSlots.length; ++i) {
itemsBySlot[processorComp.inputSlots[i].sourceSlot] = processorComp.inputSlots[i];
}
// First slot is the shape, so if it's not there we can't do anything
if (!itemsBySlot[0]) {
const shapeItem = /** @type {ShapeItem} */ (processorComp.inputSlots.get(0));
if (!shapeItem) {
return false;
}
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
const slotStatus = [];
// Check which slots are enabled
@ -233,7 +227,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
// Check if all colors of the enabled slots are there
for (let i = 0; i < slotStatus.length; ++i) {
if (slotStatus[i] && !itemsBySlot[1 + i]) {
if (slotStatus[i] && !processorComp.inputSlots.get(1 + i)) {
// A slot which is enabled wasn't enabled. Make sure if there is anything on the quadrant,
// it is not possible to paint, but if there is nothing we can ignore it
for (let j = 0; j < 4; ++j) {
@ -262,13 +256,6 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
// First, take items
const items = processorComp.inputSlots;
processorComp.inputSlots = [];
/** @type {Object<string, BaseItem>} */
const itemsBySlot = {};
for (let i = 0; i < items.length; ++i) {
itemsBySlot[items[i].sourceSlot] = items[i].item;
}
/** @type {Array<ProducedItem>} */
const outItems = [];
@ -281,8 +268,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
handler({
entity,
items,
itemsBySlot,
outItems,
inputCount: processorComp.inputCount,
});
// Track produced items
@ -304,6 +291,9 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
items: outItems,
remainingTime: timeToProcess,
});
processorComp.inputSlots.clear();
processorComp.inputCount = 0;
}
/**
@ -317,12 +307,14 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
const availableSlots = payload.entity.components.ItemEjector.slots.length;
const processorComp = payload.entity.components.ItemProcessor;
const nextSlot = processorComp.nextOutputSlot++ % availableSlots;
for (let i = 0; i < payload.items.length; ++i) {
for (let i = 0; i < 2; ++i) {
const item = payload.items.get(i);
if (!item) {
continue;
}
payload.outItems.push({
item: payload.items[i].item,
preferredSlot: (nextSlot + i) % availableSlots,
item,
preferredSlot: processorComp.nextOutputSlot++ % availableSlots,
doNotTrack: true,
});
}
@ -333,49 +325,59 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload
*/
process_CUTTER(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
const inputItem = /** @type {ShapeItem} */ (payload.items.get(0));
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
const inputDefinition = inputItem.definition;
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition);
const ejectorComp = payload.entity.components.ItemEjector;
for (let i = 0; i < cutDefinitions.length; ++i) {
const definition = cutDefinitions[i];
if (!definition.isEntirelyEmpty()) {
if (definition.isEntirelyEmpty()) {
ejectorComp.slots[i].lastItem = null;
continue;
}
payload.outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
requiredSlot: i,
});
}
}
}
/**
* @param {ProcessorImplementationPayload} payload
*/
process_CUTTER_QUAD(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
const inputItem = /** @type {ShapeItem} */ (payload.items.get(0));
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
const inputDefinition = inputItem.definition;
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutQuad(inputDefinition);
const ejectorComp = payload.entity.components.ItemEjector;
for (let i = 0; i < cutDefinitions.length; ++i) {
const definition = cutDefinitions[i];
if (!definition.isEntirelyEmpty()) {
if (definition.isEntirelyEmpty()) {
ejectorComp.slots[i].lastItem = null;
continue;
}
payload.outItems.push({
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
requiredSlot: i,
});
}
}
}
/**
* @param {ProcessorImplementationPayload} payload
*/
process_ROTATER(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
const inputItem = /** @type {ShapeItem} */ (payload.items.get(0));
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition;
@ -389,7 +391,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload
*/
process_ROTATER_CCW(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
const inputItem = /** @type {ShapeItem} */ (payload.items.get(0));
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition;
@ -403,7 +405,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload
*/
process_ROTATER_180(payload) {
const inputItem = /** @type {ShapeItem} */ (payload.items[0].item);
const inputItem = /** @type {ShapeItem} */ (payload.items.get(0));
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
const inputDefinition = inputItem.definition;
@ -417,8 +419,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload
*/
process_STACKER(payload) {
const lowerItem = /** @type {ShapeItem} */ (payload.itemsBySlot[0]);
const upperItem = /** @type {ShapeItem} */ (payload.itemsBySlot[1]);
const lowerItem = /** @type {ShapeItem} */ (payload.items.get(0));
const upperItem = /** @type {ShapeItem} */ (payload.items.get(1));
assert(lowerItem instanceof ShapeItem, "Input for lower stack is not a shape");
assert(upperItem instanceof ShapeItem, "Input for upper stack is not a shape");
@ -444,8 +446,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
*/
process_MIXER(payload) {
// Find both colors and combine them
const item1 = /** @type {ColorItem} */ (payload.items[0].item);
const item2 = /** @type {ColorItem} */ (payload.items[1].item);
const item1 = /** @type {ColorItem} */ (payload.items.get(0));
const item2 = /** @type {ColorItem} */ (payload.items.get(1));
assert(item1 instanceof ColorItem, "Input for color mixer is not a color");
assert(item2 instanceof ColorItem, "Input for color mixer is not a color");
@ -467,8 +469,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload
*/
process_PAINTER(payload) {
const shapeItem = /** @type {ShapeItem} */ (payload.itemsBySlot[0]);
const colorItem = /** @type {ColorItem} */ (payload.itemsBySlot[1]);
const shapeItem = /** @type {ShapeItem} */ (payload.items.get(0));
const colorItem = /** @type {ColorItem} */ (payload.items.get(1));
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
shapeItem.definition,
@ -484,9 +486,9 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload
*/
process_PAINTER_DOUBLE(payload) {
const shapeItem1 = /** @type {ShapeItem} */ (payload.itemsBySlot[0]);
const shapeItem2 = /** @type {ShapeItem} */ (payload.itemsBySlot[1]);
const colorItem = /** @type {ColorItem} */ (payload.itemsBySlot[2]);
const shapeItem1 = /** @type {ShapeItem} */ (payload.items.get(0));
const shapeItem2 = /** @type {ShapeItem} */ (payload.items.get(1));
const colorItem = /** @type {ColorItem} */ (payload.items.get(2));
assert(shapeItem1 instanceof ShapeItem, "Input for painter is not a shape");
assert(shapeItem2 instanceof ShapeItem, "Input for painter is not a shape");
@ -514,14 +516,15 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload
*/
process_PAINTER_QUAD(payload) {
const shapeItem = /** @type {ShapeItem} */ (payload.itemsBySlot[0]);
const shapeItem = /** @type {ShapeItem} */ (payload.items.get(0));
assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape");
/** @type {Array<enumColors>} */
const colors = [null, null, null, null];
for (let i = 0; i < 4; ++i) {
if (payload.itemsBySlot[i + 1]) {
colors[i] = /** @type {ColorItem} */ (payload.itemsBySlot[i + 1]).color;
const colorItem = /** @type {ColorItem} */ (payload.items.get(i + 1));
if (colorItem) {
colors[i] = colorItem.color;
}
}
@ -540,7 +543,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
*/
process_READER(payload) {
// Pass through the item
const item = payload.itemsBySlot[0];
const item = payload.items.get(0);
payload.outItems.push({
item,
doNotTrack: true,
@ -559,8 +562,12 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
const hubComponent = payload.entity.components.Hub;
assert(hubComponent, "Hub item processor has no hub component");
for (let i = 0; i < payload.items.length; ++i) {
const item = /** @type {ShapeItem} */ (payload.items[i].item);
// Hardcoded
for (let i = 0; i < payload.inputCount; ++i) {
const item = /** @type {ShapeItem} */ (payload.items.get(i));
if (!item) {
continue;
}
this.root.hubGoals.handleDefinitionDelivered(item.definition);
}
}
@ -570,7 +577,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
*/
process_GOAL(payload) {
const goalComp = payload.entity.components.GoalAcceptor;
const item = payload.items[0].item;
const item = payload.items.get(0);
const now = this.root.time.now();
if (goalComp.item && !item.equals(goalComp.item)) {
@ -584,7 +591,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
if (this.root.gameMode.getIsEditor()) {
// while playing in editor, assign the item
goalComp.item = payload.items[0].item;
goalComp.item = item;
}
goalComp.lastDelivery = {

View File

@ -59,5 +59,10 @@
"outline": "#111418",
"outlineWidth": 0.75,
"circleBackground": "rgba(20, 30, 40, 0.3)"
},
"shapeTooltip": {
"background": "rgba(242, 245, 254, 0.9)",
"outline": "#44464e"
}
}

View File

@ -60,5 +60,10 @@
"outline": "#55575a",
"outlineWidth": 0.75,
"circleBackground": "rgba(40, 50, 65, 0.1)"
},
"shapeTooltip": {
"background": "#dee1ea",
"outline": "#54565e"
}
}

View File

@ -12,7 +12,9 @@ export const LANGUAGES = {
"zh-CN": {
// simplified chinese
name: "简体中文",
data: require("./built-temp/base-zh-CN.json"),
data: G_WEGAME_VERSION
? require("./built-temp/base-zh-CN-ISBN.json")
: require("./built-temp/base-zh-CN.json"),
code: "zh",
region: "CN",
},

View File

@ -95,6 +95,10 @@ export class GamedistributionAdProvider extends AdProviderInterface {
document.body.classList.add("externalAdOpen");
logger.log("Set sound volume to 0");
this.app.sound.setMusicVolume(0);
this.app.sound.setSoundVolume(0);
return new Promise(resolve => {
// So, wait for the remove call but also remove after N seconds
this.videoAdResolveFunction = () => {
@ -119,6 +123,11 @@ export class GamedistributionAdProvider extends AdProviderInterface {
})
.then(() => {
document.body.classList.remove("externalAdOpen");
logger.log("Restored sound volume");
this.app.sound.setMusicVolume(this.app.settings.getSetting("musicVolume"));
this.app.sound.setSoundVolume(this.app.settings.getSetting("soundVolume"));
});
}
}

View File

@ -143,6 +143,20 @@ export class ClientAPI {
return this._request("/v1/puzzles/list/" + category, {});
}
/**
* @param {{ searchTerm: string; difficulty: string; duration: string }} searchOptions
* @returns {Promise<import("../savegame/savegame_typedefs").PuzzleMetadata[]>}
*/
apiSearchPuzzles(searchOptions) {
if (!this.isLoggedIn()) {
return Promise.reject("not-logged-in");
}
return this._request("/v1/puzzles/search", {
method: "POST",
body: searchOptions,
});
}
/**
* @param {number} puzzleId
* @returns {Promise<import("../savegame/savegame_typedefs").PuzzleFullData>}
@ -169,7 +183,7 @@ export class ClientAPI {
}
/**
* @param {number} shortKey
* @param {string} shortKey
* @returns {Promise<import("../savegame/savegame_typedefs").PuzzleFullData>}
*/
apiDownloadPuzzleByKey(shortKey) {

View File

@ -111,6 +111,10 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
* @returns {Promise<any>}
*/
sendToApi(endpoint, data) {
if (G_WEGAME_VERSION) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => reject("Request to " + endpoint + " timed out"), 20000);

View File

@ -135,15 +135,7 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
openExternalLink(url, force = false) {
logger.log("Opening external:", url);
if (force || this.embedProvider.externalLinks) {
window.open(url);
} else {
// Do nothing
alert(
"This platform does not allow opening external links. You can play on https://shapez.io directly to open them.\n\nClicked Link: " +
url
);
}
}
performRestart() {

View File

@ -257,6 +257,7 @@ export const allApplicationSettings = [
}),
new BoolSetting("enableMousePan", enumCategories.advanced, (app, value) => {}),
new BoolSetting("shapeTooltipAlwaysOn", enumCategories.advanced, (app, value) => {}),
new BoolSetting("alwaysMultiplace", enumCategories.advanced, (app, value) => {}),
new BoolSetting("zoomToCursor", enumCategories.advanced, (app, value) => {}),
new BoolSetting("clearCursorOnDeleteWhilePlacing", enumCategories.advanced, (app, value) => {}),
@ -272,7 +273,7 @@ export const allApplicationSettings = [
new EnumSetting("refreshRate", {
options: refreshRateOptions,
valueGetter: rate => rate,
textGetter: rate => rate + " Hz",
textGetter: rate => T.settings.tickrateHz.replace("<amount>", rate),
category: enumCategories.performance,
restartRequired: false,
changeCb: (app, id) => {},
@ -307,6 +308,7 @@ class SettingsStorage {
this.autosaveInterval = "two_minutes";
this.alwaysMultiplace = false;
this.shapeTooltipAlwaysOn = false;
this.offerHints = true;
this.enableTunnelSmartplace = true;
this.vignette = true;
@ -536,7 +538,7 @@ export class ApplicationSettings extends ReadWriteProxy {
}
getCurrentVersion() {
return 30;
return 31;
}
/** @param {{settings: SettingsStorage, version: number}} data */
@ -683,6 +685,11 @@ export class ApplicationSettings extends ReadWriteProxy {
data.version = 30;
}
if (data.version < 31) {
data.settings.shapeTooltipAlwaysOn = false;
data.version = 31;
}
return ExplainedResult.good();
}
}

View File

@ -64,6 +64,24 @@ export class Savegame extends ReadWriteProxy {
return savegameInterfaces[Savegame.getCurrentVersion()];
}
/**
*
* @param {Application} app
* @returns
*/
static createPuzzleSavegame(app) {
return new Savegame(app, {
internalId: "puzzle",
metaDataRef: {
internalId: "puzzle",
lastUpdate: 0,
version: 0,
level: 0,
name: "puzzle",
},
});
}
/**
* @returns {number}
*/

View File

@ -17,6 +17,7 @@ import {
waitNextFrame,
} from "../core/utils";
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
import { PlatformWrapperImplBrowser } from "../platform/browser/wrapper";
import { PlatformWrapperImplElectron } from "../platform/electron/wrapper";
import { getApplicationSettingById } from "../profile/application_settings";
import { T } from "../translations";
@ -34,35 +35,57 @@ export class MainMenuState extends GameState {
}
getInnerHTML() {
const showLanguageIcon = !G_CHINA_VERSION && !G_WEGAME_VERSION;
const showExitAppButton = G_IS_STANDALONE;
const showUpdateLabel = !G_WEGAME_VERSION;
const showBrowserWarning = !G_IS_STANDALONE && !isSupportedBrowser();
const showPuzzleDLC = !G_WEGAME_VERSION && (G_IS_STANDALONE || G_IS_DEV);
const showWegameFooter = G_WEGAME_VERSION;
let showExternalLinks = true;
if (G_IS_STANDALONE) {
if (G_WEGAME_VERSION || G_CHINA_VERSION) {
showExternalLinks = false;
}
} else {
const wrapper = /** @type {PlatformWrapperImplBrowser} */ (this.app.platformWrapper);
if (!wrapper.embedProvider.externalLinks) {
showExternalLinks = false;
}
}
let showDiscordLink = showExternalLinks;
if (G_CHINA_VERSION) {
showDiscordLink = true;
}
const showCrosspromo = !G_IS_STANDALONE && showExternalLinks;
const showDemoAdvertisement =
showExternalLinks && this.app.restrictionMgr.getIsStandaloneMarketingActive();
const ownsPuzzleDLC =
G_IS_DEV ||
(G_IS_STANDALONE &&
/** @type { PlatformWrapperImplElectron}*/ (this.app.platformWrapper).dlcs.puzzle);
const bannerHtml = `
<h3>${T.demoBanners.title}</h3>
<p>${T.demoBanners.intro}</p>
<a href="#" class="steamLink ${A_B_TESTING_LINK_TYPE}" target="_blank">Get the shapez.io standalone!</a>
`;
const showDemoBadges = this.app.restrictionMgr.getIsStandaloneMarketingActive();
const puzzleDlc =
G_IS_STANDALONE &&
/** @type { PlatformWrapperImplElectron
}*/ (this.app.platformWrapper).dlcs.puzzle;
return `
<div class="topButtons">
${
G_CHINA_VERSION || G_WEGAME_VERSION
? ""
: `<button class="languageChoose" data-languageicon="${this.app.settings.getLanguage()}"></button>`
showLanguageIcon
? `<button class="languageChoose" data-languageicon="${this.app.settings.getLanguage()}"></button>`
: ""
}
<button class="settingsButton"></button>
${
G_IS_STANDALONE || G_IS_DEV
? `
<button class="exitAppButton"></button>
`
: ""
}
${showExitAppButton ? `<button class="exitAppButton"></button>` : ""}
</div>
<video autoplay muted loop class="fullscreenBackgroundVideo">
@ -71,27 +94,25 @@ export class MainMenuState extends GameState {
<div class="logo">
<img src="${cachebust("res/" + getLogoSprite())}" alt="shapez.io Logo">
${G_WEGAME_VERSION ? "" : `<span class="updateLabel">v${G_BUILD_VERSION}!</span>`}
${showUpdateLabel ? `<span class="updateLabel">v${G_BUILD_VERSION}!</span>` : ""}
</div>
<div class="mainWrapper ${showDemoBadges ? "demo" : "noDemo"}" data-columns="${
G_IS_STANDALONE ? 2 : showDemoBadges ? 2 : 1
}">
<div class="mainWrapper" data-columns="${showDemoAdvertisement || showPuzzleDLC ? 2 : 1}">
<div class="sideContainer">
${showDemoBadges ? `<div class="standaloneBanner">${bannerHtml}</div>` : ""}
${showDemoAdvertisement ? `<div class="standaloneBanner">${bannerHtml}</div>` : ""}
</div>
<div class="mainContainer">
${
G_IS_STANDALONE || isSupportedBrowser()
? ""
: `<div class="browserWarning">${T.mainMenu.browserWarning}</div>`
showBrowserWarning
? `<div class="browserWarning">${T.mainMenu.browserWarning}</div>`
: ""
}
<div class="buttons"></div>
</div>
${
(!G_WEGAME_VERSION && G_IS_STANDALONE && puzzleDlc) || G_IS_DEV
showPuzzleDLC && ownsPuzzleDLC
? `
<div class="puzzleContainer">
<img class="dlcLogo" src="${cachebust(
@ -105,7 +126,7 @@ export class MainMenuState extends GameState {
}
${
!G_WEGAME_VERSION && G_IS_STANDALONE && !puzzleDlc
showPuzzleDLC && !ownsPuzzleDLC
? `
<div class="puzzleContainer notOwned">
<span class="badge">
@ -129,40 +150,60 @@ export class MainMenuState extends GameState {
</div>
${
G_WEGAME_VERSION
? "<div class='footer wegame'></div>"
: `
<div class="footer ${G_CHINA_VERSION ? "china" : ""} ">
showWegameFooter
? `
<div class='footer wegameDisclaimer'>
<div class="disclaimer">
健康游戏忠告
<br>
抵制不良游戏,拒绝盗版游戏注意自我保护,谨防受骗上当<br>
适度游戏益脑,沉迷游戏伤身合理安排时间,享受健康生活
</div>
${
G_CHINA_VERSION
? ""
<div class="rating"></div>
</div>
`
: `
<div class="footer ${showExternalLinks ? "" : "noLinks"} ">
${
showExternalLinks
? `
<a class="githubLink boxLink" target="_blank">
${T.mainMenu.openSourceHint}
<span class="thirdpartyLogo githubLogo"></span>
</a>`
: ""
}
<a class="discordLink boxLink" target="_blank">
${
showDiscordLink
? `<a class="discordLink boxLink" target="_blank">
${T.mainMenu.discordLink}
<span class="thirdpartyLogo discordLogo"></span>
</a>
</a>`
: ""
}
<div class="sidelinks">
${G_CHINA_VERSION ? "" : `<a class="redditLink">${T.mainMenu.subreddit}</a>`}
${showExternalLinks ? `<a class="redditLink">${T.mainMenu.subreddit}</a>` : ""}
${G_CHINA_VERSION ? "" : `<a class="changelog">${T.changelog.title}</a>`}
${showExternalLinks ? `<a class="changelog">${T.changelog.title}</a>` : ""}
${G_CHINA_VERSION ? "" : `<a class="helpTranslate">${T.mainMenu.helpTranslate}</a>`}
${showExternalLinks ? `<a class="helpTranslate">${T.mainMenu.helpTranslate}</a>` : ""}
</div>
<div class="author">${T.mainMenu.madeBy.replace(
"<author-link>",
'<a class="producerLink" target="_blank">Tobias Springer</a>'
)}</div>
</div>
${
showCrosspromo
? `<iframe id="crosspromo" src="https://crosspromo.tobspr.io?src=shapez_web"></iframe>`
: ""
}
`
}
`;
@ -251,8 +292,6 @@ export class MainMenuState extends GameState {
);
}
const qs = this.htmlElement.querySelector.bind(this.htmlElement);
if (G_IS_DEV && globalConfig.debug.testPuzzleMode) {
this.onPuzzleModeButtonClicked(true);
return;
@ -276,71 +315,38 @@ export class MainMenuState extends GameState {
}
});
this.trackClicks(qs(".settingsButton"), this.onSettingsButtonClicked);
const clickHandling = {
".settingsButton": this.onSettingsButtonClicked,
".languageChoose": this.onLanguageChooseClicked,
".redditLink": this.onRedditClicked,
".changelog": this.onChangelogClicked,
".helpTranslate": this.onTranslationHelpLinkClicked,
".exitAppButton": this.onExitAppButtonClicked,
".steamLink": this.onSteamLinkClicked,
".discordLink": () => {
this.app.analytics.trackUiClick("main_menu_link_discord");
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.discord);
},
".githubLink": () => {
this.app.analytics.trackUiClick("main_menu_link_github");
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.github);
},
".producerLink": () => this.app.platformWrapper.openExternalLink("https://tobspr.io"),
".puzzleDlcPlayButton": this.onPuzzleModeButtonClicked,
".puzzleDlcGetButton": this.onPuzzleWishlistButtonClicked,
".wegameDisclaimer > .rating": this.onWegameRatingClicked,
};
if (!G_CHINA_VERSION && !G_WEGAME_VERSION) {
this.trackClicks(qs(".languageChoose"), this.onLanguageChooseClicked);
this.trackClicks(qs(".redditLink"), this.onRedditClicked);
this.trackClicks(qs(".changelog"), this.onChangelogClicked);
this.trackClicks(qs(".helpTranslate"), this.onTranslationHelpLinkClicked);
for (const key in clickHandling) {
const handler = clickHandling[key];
const element = this.htmlElement.querySelector(key);
if (element) {
this.trackClicks(element, handler, { preventClick: true });
}
if (G_IS_STANDALONE) {
this.trackClicks(qs(".exitAppButton"), this.onExitAppButtonClicked);
}
this.renderMainMenu();
this.renderSavegames();
const steamLink = this.htmlElement.querySelector(".steamLink");
if (steamLink) {
this.trackClicks(steamLink, () => this.onSteamLinkClicked(), { preventClick: true });
}
const discordLink = this.htmlElement.querySelector(".discordLink");
if (discordLink) {
this.trackClicks(
discordLink,
() => {
this.app.analytics.trackUiClick("main_menu_link_discord");
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.discord);
},
{ preventClick: true }
);
}
const githubLink = this.htmlElement.querySelector(".githubLink");
if (githubLink) {
this.trackClicks(
githubLink,
() => {
this.app.analytics.trackUiClick("main_menu_link_github");
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.github);
},
{ preventClick: true }
);
}
const producerLink = this.htmlElement.querySelector(".producerLink");
if (producerLink) {
this.trackClicks(
producerLink,
() => this.app.platformWrapper.openExternalLink("https://tobspr.io"),
{
preventClick: true,
}
);
}
const puzzleModeButton = qs(".puzzleDlcPlayButton");
if (puzzleModeButton) {
this.trackClicks(puzzleModeButton, () => this.onPuzzleModeButtonClicked());
}
const puzzleWishlistButton = qs(".puzzleDlcGetButton");
if (puzzleWishlistButton) {
this.trackClicks(puzzleWishlistButton, () => this.onPuzzleWishlistButtonClicked());
}
}
renderMainMenu() {
@ -511,9 +517,12 @@ export class MainMenuState extends GameState {
downloadButton.classList.add("styledButton", "downloadGame");
elem.appendChild(downloadButton);
if (!G_WEGAME_VERSION) {
const renameButton = document.createElement("button");
renameButton.classList.add("styledButton", "renameGame");
name.appendChild(renameButton);
this.trackClicks(renameButton, () => this.requestRenameSavegame(games[i]));
}
const resumeButton = document.createElement("button");
resumeButton.classList.add("styledButton", "resumeGame");
@ -522,7 +531,6 @@ export class MainMenuState extends GameState {
this.trackClicks(deleteButton, () => this.deleteGame(games[i]));
this.trackClicks(downloadButton, () => this.downloadGame(games[i]));
this.trackClicks(resumeButton, () => this.resumeGame(games[i]));
this.trackClicks(renameButton, () => this.requestRenameSavegame(games[i]));
}
}
}
@ -675,6 +683,18 @@ export class MainMenuState extends GameState {
});
}
onWegameRatingClicked() {
this.dialogs.showInfo(
"提示说明",
`
1本游戏是一款休闲建造类单机游戏画面简洁而乐趣充足适用于年满8周岁及以上的用户建议未成年人在家长监护下使用游戏产品<br>
2本游戏模拟简单的生产流水线剧情简单且积极向上没有基于真实历史和现实事件的改编内容游戏玩法为摆放简单的部件完成生产目标游戏为单机作品没有基于文字和语音的陌生人社交系统<br>
3本游戏中有用户实名认证系统认证为未成年人的用户将接受以下管理未满8周岁的用户不能付费8周岁以上未满16周岁的未成年人用户单次充值金额不得超过50元人民币每月充值金额累计不得超过200元人民币16周岁以上的未成年人用户单次充值金额不得超过100元人民币每月充值金额累计不得超过400元人民币未成年人用户每日22点到次日8点不得使用法定节假日每天不得使用超过3小时其他时间每天不得使用超过1.5小时<br>
4游戏功能说明一款关于传送带自动化生产特定形状产品的工厂流水线模拟游戏画面简洁而乐趣充足可以让玩家在轻松愉快的氛围下获得各种游戏乐趣体验完成目标的成就感游戏没有失败功能自动存档不存在较强的挫折体验
`
);
}
onContinueButtonClicked() {
let latestLastUpdate = 0;
let latestInternalId;
@ -686,7 +706,10 @@ export class MainMenuState extends GameState {
});
const savegame = this.app.savegameMgr.getSavegameById(latestInternalId);
savegame.readAsync().then(() => {
savegame
.readAsync()
.then(() => this.app.adProvider.showVideoAd())
.then(() => {
this.moveToState("InGameState", {
savegame,
});

View File

@ -81,9 +81,11 @@ export class PreloadState extends GameState {
} catch (ex) {
logger.error("Failed to read/write local storage:", ex);
return new Promise(() => {
alert(`Your brower does not support thirdparty cookies or you have disabled it in your security settings.\n\n
In Chrome this setting is called "Block third-party cookies and site data".\n\n
Please allow third party cookies and then reload the page.`);
alert(
"Your brower does not support thirdparty cookies or you have disabled it in your security settings.\n\n" +
"In Chrome this setting is called 'Block third-party cookies and site data'.\n\n" +
"Please allow third party cookies and then reload the page."
);
// Never return
});
}

View File

@ -13,17 +13,30 @@ const navigation = {
categories: ["official", "top-rated", "trending", "trending-weekly", "new"],
difficulties: ["easy", "medium", "hard"],
account: ["mine", "completed"],
search: ["search"],
};
const logger = createLogger("puzzle-menu");
let lastCategory = "official";
let lastSearchOptions = {
searchTerm: "",
difficulty: "any",
duration: "any",
includeCompleted: false,
};
export class PuzzleMenuState extends TextualGameState {
constructor() {
super("PuzzleMenuState");
this.loading = false;
this.activeCategory = "";
/**
* @type {Array<import("../savegame/savegame_typedefs").PuzzleMetadata>}
*/
this.puzzles = [];
}
getThemeMusic() {
@ -99,13 +112,23 @@ export class PuzzleMenuState extends TextualGameState {
activeCategory.classList.remove("active");
}
this.htmlElement.querySelector(`[data-category="${category}"]`).classList.add("active");
const categoryElement = this.htmlElement.querySelector(`[data-category="${category}"]`);
if (categoryElement) {
categoryElement.classList.add("active");
}
const container = this.htmlElement.querySelector("#mainContainer");
while (container.firstChild) {
container.removeChild(container.firstChild);
}
if (category === "search") {
this.loading = false;
this.startSearch();
return;
}
const loadingElement = document.createElement("div");
loadingElement.classList.add("loader");
loadingElement.innerText = T.global.loading + "...";
@ -160,6 +183,7 @@ export class PuzzleMenuState extends TextualGameState {
}
const children = navigation[rootCategory];
if (children.length > 1) {
for (const category of children) {
const button = document.createElement("button");
button.setAttribute("data-category", category);
@ -168,15 +192,139 @@ export class PuzzleMenuState extends TextualGameState {
this.trackClicks(button, () => this.selectCategory(category));
subContainer.appendChild(button);
}
}
if (rootCategory === "search") {
this.renderSearchForm(subContainer);
}
this.selectCategory(subCategory);
}
renderSearchForm(parent) {
const container = document.createElement("form");
container.classList.add("searchForm");
// Search
const searchField = document.createElement("input");
searchField.value = lastSearchOptions.searchTerm;
searchField.classList.add("search");
searchField.setAttribute("type", "text");
searchField.setAttribute("placeholder", T.puzzleMenu.search.placeholder);
searchField.addEventListener("input", () => {
lastSearchOptions.searchTerm = searchField.value.trim();
});
container.appendChild(searchField);
// Difficulty
const difficultyFilter = document.createElement("select");
for (const difficulty of ["any", "easy", "medium", "hard"]) {
const option = document.createElement("option");
option.value = difficulty;
option.innerText = T.puzzleMenu.search.difficulties[difficulty];
if (option.value === lastSearchOptions.difficulty) {
option.setAttribute("selected", "selected");
}
difficultyFilter.appendChild(option);
}
difficultyFilter.addEventListener("change", () => {
const option = difficultyFilter.value;
lastSearchOptions.difficulty = option;
});
container.appendChild(difficultyFilter);
// Duration
const durationFilter = document.createElement("select");
for (const duration of ["any", "short", "medium", "long"]) {
const option = document.createElement("option");
option.value = duration;
option.innerText = T.puzzleMenu.search.durations[duration];
if (option.value === lastSearchOptions.duration) {
option.setAttribute("selected", "selected");
}
durationFilter.appendChild(option);
}
durationFilter.addEventListener("change", () => {
const option = durationFilter.value;
lastSearchOptions.duration = option;
});
container.appendChild(durationFilter);
// Include completed
const labelCompleted = document.createElement("label");
labelCompleted.classList.add("filterCompleted");
const inputCompleted = document.createElement("input");
inputCompleted.setAttribute("type", "checkbox");
if (lastSearchOptions.includeCompleted) {
inputCompleted.setAttribute("checked", "checked");
}
inputCompleted.addEventListener("change", () => {
lastSearchOptions.includeCompleted = inputCompleted.checked;
});
labelCompleted.appendChild(inputCompleted);
const text = document.createTextNode(T.puzzleMenu.search.includeCompleted);
labelCompleted.appendChild(text);
container.appendChild(labelCompleted);
// Submit
const submitButton = document.createElement("button");
submitButton.classList.add("styledButton");
submitButton.setAttribute("type", "submit");
submitButton.innerText = T.puzzleMenu.search.action;
container.appendChild(submitButton);
container.addEventListener("submit", event => {
event.preventDefault();
console.log("Search:", searchField.value.trim());
this.startSearch();
});
parent.appendChild(container);
}
startSearch() {
if (this.loading) {
return;
}
this.loading = true;
const container = this.htmlElement.querySelector("#mainContainer");
while (container.firstChild) {
container.removeChild(container.firstChild);
}
const loadingElement = document.createElement("div");
loadingElement.classList.add("loader");
loadingElement.innerText = T.global.loading + "...";
container.appendChild(loadingElement);
this.asyncChannel
.watch(this.app.clientApi.apiSearchPuzzles(lastSearchOptions))
.then(
puzzles => this.renderPuzzles(puzzles),
error => {
this.dialogs.showWarning(
T.dialogs.puzzleLoadFailed.title,
T.dialogs.puzzleLoadFailed.desc + " " + error
);
this.renderPuzzles([]);
}
)
.then(() => (this.loading = false));
}
/**
*
* @param {import("../savegame/savegame_typedefs").PuzzleMetadata[]} puzzles
*/
renderPuzzles(puzzles) {
this.puzzles = puzzles;
const container = this.htmlElement.querySelector("#mainContainer");
while (container.firstChild) {
container.removeChild(container.firstChild);
@ -209,10 +357,7 @@ export class PuzzleMenuState extends TextualGameState {
stats.classList.add("stats");
elem.appendChild(stats);
if (
puzzle.downloads > 3 &&
!["official", "easy", "medium", "hard"].includes(this.activeCategory)
) {
if (!["official", "easy", "medium", "hard"].includes(this.activeCategory)) {
const difficulty = document.createElement("div");
difficulty.classList.add("difficulty");
@ -223,15 +368,18 @@ export class PuzzleMenuState extends TextualGameState {
difficulty.innerText = completionPercentage + "%";
stats.appendChild(difficulty);
if (completionPercentage < 40) {
difficulty.classList.add("stage--hard");
difficulty.innerText = T.puzzleMenu.difficulties.hard;
} else if (completionPercentage < 80) {
difficulty.classList.add("stage--medium");
difficulty.innerText = T.puzzleMenu.difficulties.medium;
} else {
if (puzzle.difficulty === null) {
difficulty.classList.add("stage--unknown");
difficulty.innerText = T.puzzleMenu.difficulties.unknown;
} else if (puzzle.difficulty < 0.2) {
difficulty.classList.add("stage--easy");
difficulty.innerText = T.puzzleMenu.difficulties.easy;
} else if (puzzle.difficulty > 0.6) {
difficulty.classList.add("stage--hard");
difficulty.innerText = T.puzzleMenu.difficulties.hard;
} else {
difficulty.classList.add("stage--medium");
difficulty.innerText = T.puzzleMenu.difficulties.medium;
}
}
@ -275,7 +423,7 @@ export class PuzzleMenuState extends TextualGameState {
container.appendChild(elem);
this.trackClicks(elem, () => this.playPuzzle(puzzle));
this.trackClicks(elem, () => this.playPuzzle(puzzle.id));
}
if (puzzles.length === 0) {
@ -328,20 +476,26 @@ export class PuzzleMenuState extends TextualGameState {
/**
*
* @param {import("../savegame/savegame_typedefs").PuzzleMetadata} puzzle
* @param {number} puzzleId
* @param {Array<number>=} nextPuzzles
*/
playPuzzle(puzzle) {
playPuzzle(puzzleId, nextPuzzles) {
const closeLoading = this.dialogs.showLoadingDialog();
this.app.clientApi.apiDownloadPuzzle(puzzle.id).then(
this.asyncChannel.watch(this.app.clientApi.apiDownloadPuzzle(puzzleId)).then(
puzzleData => {
closeLoading();
logger.log("Got puzzle:", puzzleData);
this.startLoadedPuzzle(puzzleData);
nextPuzzles =
nextPuzzles || this.puzzles.filter(puzzle => !puzzle.completed).map(puzzle => puzzle.id);
nextPuzzles = nextPuzzles.filter(id => id !== puzzleId);
logger.log("Got puzzle:", puzzleData, "next puzzles:", nextPuzzles);
this.startLoadedPuzzle(puzzleData, nextPuzzles);
},
err => {
closeLoading();
logger.error("Failed to download puzzle", puzzle.id, ":", err);
logger.error("Failed to download puzzle", puzzleId, ":", err);
this.dialogs.showWarning(
T.dialogs.puzzleDownloadError.title,
T.dialogs.puzzleDownloadError.desc + " " + err
@ -353,19 +507,26 @@ export class PuzzleMenuState extends TextualGameState {
/**
*
* @param {import("../savegame/savegame_typedefs").PuzzleFullData} puzzle
* @param {Array<number>=} nextPuzzles
*/
startLoadedPuzzle(puzzle) {
const savegame = this.createEmptySavegame();
startLoadedPuzzle(puzzle, nextPuzzles) {
const savegame = Savegame.createPuzzleSavegame(this.app);
this.moveToState("InGameState", {
gameModeId: enumGameModeIds.puzzlePlay,
gameModeParameters: {
puzzle,
nextPuzzles,
},
savegame,
});
}
onEnter(payload) {
if (payload.continueQueue) {
logger.log("Continuing puzzle queue:", payload);
this.playPuzzle(payload.continueQueue[0], payload.continueQueue.slice(1));
}
// Find old category
let rootCategory = "categories";
for (const [id, children] of Object.entries(navigation)) {
@ -390,26 +551,13 @@ export class PuzzleMenuState extends TextualGameState {
this.trackClicks(this.htmlElement.querySelector("button.loadPuzzle"), () => this.loadPuzzle());
}
createEmptySavegame() {
return new Savegame(this.app, {
internalId: "puzzle",
metaDataRef: {
internalId: "puzzle",
lastUpdate: 0,
version: 0,
level: 0,
name: "puzzle",
},
});
}
loadPuzzle() {
const shortKeyInput = new FormElementInput({
id: "shortKey",
label: null,
placeholder: "",
defaultValue: "",
validator: val => ShapeDefinition.isValidShortKey(val),
validator: val => ShapeDefinition.isValidShortKey(val) || val.startsWith("/"),
});
const dialog = new DialogWithForm({
@ -422,9 +570,16 @@ export class PuzzleMenuState extends TextualGameState {
this.dialogs.internalShowDialog(dialog);
dialog.buttonSignals.ok.add(() => {
const searchTerm = shortKeyInput.getValue();
if (searchTerm === "/apikey") {
alert("Your api key is: " + this.app.clientApi.token);
return;
}
const closeLoading = this.dialogs.showLoadingDialog();
this.app.clientApi.apiDownloadPuzzleByKey(shortKeyInput.getValue()).then(
this.app.clientApi.apiDownloadPuzzleByKey(searchTerm).then(
puzzle => {
closeLoading();
this.startLoadedPuzzle(puzzle);
@ -451,7 +606,7 @@ export class PuzzleMenuState extends TextualGameState {
return;
}
const savegame = this.createEmptySavegame();
const savegame = Savegame.createPuzzleSavegame(this.app);
this.moveToState("InGameState", {
gameModeId: enumGameModeIds.puzzleEdit,
savegame,

View File

@ -1,3 +1,4 @@
import { THIRDPARTY_URLS } from "../core/config";
import { TextualGameState } from "../core/textual_game_state";
import { formatSecondsToTimeAgo } from "../core/utils";
import { allApplicationSettings, enumCategories } from "../profile/application_settings";
@ -34,6 +35,8 @@ export class SettingsState extends TextualGameState {
? ""
: `
<button class="styledButton about">${T.about.title}</button>
<button class="styledButton privacy">Privacy Policy</button>
`
}
<div class="versionbar">
@ -109,6 +112,9 @@ export class SettingsState extends TextualGameState {
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
preventDefault: false,
});
this.trackClicks(this.htmlElement.querySelector(".privacy"), this.onPrivacyClicked, {
preventDefault: false,
});
}
const keybindingsButton = this.htmlElement.querySelector(".editKeybindings");
@ -180,6 +186,10 @@ export class SettingsState extends TextualGameState {
this.moveToStateAddGoBack("AboutState");
}
onPrivacyClicked() {
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.privacyPolicy);
}
onKeybindingsClicked() {
this.moveToStateAddGoBack("KeybindingsState");
}

View File

@ -0,0 +1,27 @@
import { GameState } from "../core/game_state";
export class WegameSplashState extends GameState {
constructor() {
super("WegameSplashState");
}
getInnerHTML() {
return `
<div class="wrapper">
<strong>健康游戏忠告</strong>
<div>抵制不良游戏,拒绝盗版游戏</div>
<div>注意自我保护,谨防受骗上当</div>
<div>适度游戏益脑,沉迷游戏伤身</div>
<div>合理安排时间,享受健康生活</div>
</div>
`;
}
onEnter() {
setTimeout(
() => {
this.app.stateMgr.moveToState("PreloadState");
},
G_IS_DEV ? 1 : 6000
);
}
}

View File

@ -456,6 +456,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1003,7 +1004,12 @@ settings:
title: Map Resources Size
description: Controls the size of the shapes on the map overview (when zooming
out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Keybindings
hint: "Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different
@ -1085,6 +1091,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: About this Game
body: >-
@ -1212,8 +1219,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -466,6 +466,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1030,7 +1031,12 @@ settings:
title: Map Resources Size
description: Controls the size of the shapes on the map overview (when zooming
out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Combinacions de tecles
hint: "Tip: Assegura't d'emprar CTRL, SHIFT i ALT! Et permeten col·locar
@ -1112,6 +1118,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: Sobre aquest Joc
body: >-
@ -1254,8 +1261,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -457,6 +457,7 @@ ingame:
titleRatingDesc: Vaše hodnocení nám pomůže podat vám v budoucnu lepší návrhy
continueBtn: Hrát dál
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Autor
shortKey: Krátký klíč
@ -994,7 +995,12 @@ settings:
mapResourcesScale:
title: Velikost zdrojů na mapě
description: Určuje velikost ikon tvarů na náhledu mapy (při oddálení).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Klávesové zkratky
hint: "Tip: Nezapomeňte používat CTRL, SHIFT a ALT! Díky nim můžete měnit způsob
@ -1076,6 +1082,7 @@ keybindings:
goal_acceptor: Přijemce cílů
block: Blok
massSelectClear: Vymazat pásy
showShapeTooltip: Show shape output tooltip
about:
title: O hře
body: >-
@ -1213,8 +1220,24 @@ puzzleMenu:
easy: Lehká
medium: Střední
hard: Těžká
unknown: Unrated
dlcHint: Již jste toto DLC zakoupili? Ujistěte se, že je aktivováno kliknutím
pravého tlačítka na shapez.io ve své knihovně, vybráním Vlastnosti > DLC.
pravého tlačítka na shapez.io ve své knihovně, vybráním Vlastnosti >
DLC.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: Provádíte své akce příliš často. Počkejte prosím.
invalid-api-key: Komunikace s back-endem se nezdařila, prosím zkuste

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,6 @@ steamPage:
steam_review_comment: This game has stolen my life and I don't want it back.
Very chill factory game that won't let me stop making my lines more
efficient.
global:
loading: Laden
error: Fehler
@ -55,7 +54,6 @@ global:
escape: ESC
shift: UMSCH
space: LEER
demoBanners:
title: Demoversion
intro: Kauf die Vollversion für alle Features!
@ -71,7 +69,8 @@ mainMenu:
helpTranslate: Hilf beim Übersetzen!
madeBy: Ein Spiel von <author-link>
browserWarning: Sorry, aber das Spiel wird in deinem Browser langsamer laufen!
Kaufe die Vollversion oder verwende Google Chrome für die beste Erfahrung.
Kaufe die Vollversion oder verwende Google Chrome für die beste
Erfahrung.
savegameLevel: Level <x>
savegameLevelUnknown: Unbekanntes Level
savegameUnnamed: Unbenannt
@ -81,7 +80,6 @@ mainMenu:
zu machen? Hol dir das Puzzle-DLC auf Steam für noch mehr Spaß!
puzzleDlcWishlist: Jetzt zur Wunschliste hinzufügen!
puzzleDlcViewNow: DLC anzeigen
puzzleMenu:
play: Spielen
edit: Bearbeiten
@ -92,9 +90,9 @@ puzzleMenu:
validatingPuzzle: Puzzle wird überprüft
submittingPuzzle: Puzzle wird veröffentlicht
noPuzzles: Hier gibt es bisher noch keine Puzzles.
dlcHint: DLC schon gekauft? Stelle sicher, dass es aktiviert ist, indem du in der Steam-Bibliothek
shapez.io rechtsklickst und es unter Eigenschaften > Zusatzinhalte (DLC) aktivierst.
dlcHint: DLC schon gekauft? Stelle sicher, dass es aktiviert ist, indem du in
der Steam-Bibliothek shapez.io rechtsklickst und es unter Eigenschaften
> Zusatzinhalte (DLC) aktivierst.
categories:
levels: Levels
new: Neu
@ -111,26 +109,38 @@ puzzleMenu:
difficulties: Nach Schwierigkeit
account: Meine Puzzles
search: Suche
difficulties:
easy: Einfach
medium: Mittel
hard: Schwer
unknown: Unrated
validation:
title: Ungültiges Puzzle
noProducers: Bitte platziere einen Itemproduzent!
noGoalAcceptors: Bitte platziere einen Zielakzeptor!
goalAcceptorNoItem: Ein oder mehrere Zielakzeptoren haben noch kein
zugewiesenes Item. Beliefere sie mit einer Form, um ein Ziel zu
setzen.
goalAcceptorRateNotMet: Ein oder mehrere Zielakzeptoren bekommen nicht
genügend Items. Stelle sicher, dass alle ihre Indikatoren grün leuchten.
goalAcceptorNoItem: Ein oder mehrere Zielakzeptoren haben noch kein zugewiesenes
Item. Beliefere sie mit einer Form, um ein Ziel zu setzen.
goalAcceptorRateNotMet: Ein oder mehrere Zielakzeptoren bekommen nicht genügend
Items. Stelle sicher, dass alle ihre Indikatoren grün leuchten.
buildingOutOfBounds: Ein oder mehrere Gebäude befinden sich außerhalb des
bebaubaren Bereichs. Vergrößere den Bereich oder entferne die Gebäude.
bebaubaren Bereichs. Vergrößere den Bereich oder entferne die
Gebäude.
autoComplete: Dein Puzzle schließt sich selbst ab! Bitte stelle sicher, dass
deine Itemproduzenten nicht direkt an deine Zielakzeptoren liefern.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
dialogs:
buttons:
ok: OK
@ -190,9 +200,10 @@ dialogs:
desc: "Hier sind die Änderungen, seitdem du das letzte Mal gespielt hast:"
upgradesIntroduction:
title: Upgrades freischalten
desc: Viele deiner Formen können noch benutzt werden, um Upgrades freizuschalten, also
<strong>zerstöre deine alten Fabriken nicht!</strong> Den
Upgrade-Tab findest du oben rechts im Bildschirm.
desc: Viele deiner Formen können noch benutzt werden, um Upgrades
freizuschalten, also <strong>zerstöre deine alten Fabriken
nicht!</strong> Den Upgrade-Tab findest du oben rechts im
Bildschirm.
massDeleteConfirm:
title: Löschen bestätigen
desc: Du löscht viele Gebäude (<count> um genau zu sein)! Bist du dir sicher?
@ -212,7 +223,8 @@ dialogs:
desc: >-
Dieses Spiel hat viele Hotkeys, die den Bau von Fabriken
vereinfachen und beschleunigen. Hier sind ein paar Beispiele, aber
prüfe am besten die <strong>Tastenbelegung</strong> in den Einstellungen!<br><br>
prüfe am besten die <strong>Tastenbelegung</strong> in den
Einstellungen!<br><br>
<code class='keybinding'>STRG</code> + Ziehen: Wähle Bereich aus.<br>
<code class='keybinding'>UMSCH</code>: Halten, um mehrere Gebäude zu platzieren.<br>
<code class='keybinding'>ALT</code>: Invertiere die Platzierungsrichtung der Fließbänder.<br>
@ -220,16 +232,18 @@ dialogs:
title: Neue Markierung
titleEdit: Markierung bearbeiten
desc: Gib ihm einen griffigen Namen. Du kannst auch den
<strong>Kurzschlüssel</strong> einer Form eingeben (<link>Hier</link> geht es zum Generator).
<strong>Kurzschlüssel</strong> einer Form eingeben
(<link>Hier</link> geht es zum Generator).
editSignal:
title: Signal setzen
descItems: "Wähle ein vordefiniertes Item:"
descShortKey: ... oder gib den <strong>Kurzschlüssel</strong> einer Form an (<link>Hier</link> geht es zum Generator).
descShortKey: ... oder gib den <strong>Kurzschlüssel</strong> einer Form an
(<link>Hier</link> geht es zum Generator).
editConstantProducer:
title: Item wählen
markerDemoLimit:
desc: Du kannst nur 2 Markierungen in der Demo benutzen. Hole dir die Vollversion, um
unbegrenzt viele Markierungen zu setzen!
desc: Du kannst nur 2 Markierungen in der Demo benutzen. Hole dir die
Vollversion, um unbegrenzt viele Markierungen zu setzen!
exportScreenshotWarning:
title: Bildschirmfoto exportieren
desc: Hier kannst du ein Bildschirmfoto von deiner ganzen Fabrik erstellen. Für
@ -240,7 +254,8 @@ dialogs:
desc: Hier kannst du deinen Speicherstand umbenennen.
tutorialVideoAvailable:
title: Tutorial verfügbar
desc: Für dieses Level ist ein Anleitungsvideo verfügbar. Willst du es anschauen?
desc: Für dieses Level ist ein Anleitungsvideo verfügbar. Willst du es
anschauen?
tutorialVideoAvailableForeignLanguage:
title: Tutorial verfügbar
desc: Für dieses Level ist ein Anleitungsvideo verfügbar, allerdings nur auf
@ -264,8 +279,9 @@ dialogs:
desc: "Das Puzzle konnte nicht geladen werden:"
offlineMode:
title: Offlinemodus
desc: Die Server konnten nicht erreicht werden, daher läuft das Spiel im Offlinemodus.
Bitte stelle sicher, dass du eine aktive Internetverbindung hast.
desc: Die Server konnten nicht erreicht werden, daher läuft das Spiel im
Offlinemodus. Bitte stelle sicher, dass du eine aktive
Internetverbindung hast.
puzzleDownloadError:
title: Downloadfehler
desc: "Der Download des Puzzles ist fehlgeschlagen:"
@ -275,17 +291,17 @@ dialogs:
puzzleSubmitOk:
title: Puzzle veröffentlicht
desc: Herzlichen Glückwunsch! Dein Puzzle wurde veröffentlicht und kann nun von
anderen gespielt werden. Du kannst es jetzt im Bereich "Meine Puzzles" finden.
anderen gespielt werden. Du kannst es jetzt im Bereich "Meine
Puzzles" finden.
puzzleCreateOffline:
title: Offlinemodus
desc: Da du offline bist, kannst du dein Puzzle nicht speichern
und/oder veröffentlichen. Möchtest du trotzdem fortfahren?
desc: Da du offline bist, kannst du dein Puzzle nicht speichern und/oder
veröffentlichen. Möchtest du trotzdem fortfahren?
puzzlePlayRegularRecommendation:
title: Empfehlung
desc: Ich empfehle dir <strong>sehr</strong>, bis Level 12 zu
spielen, bevor du dich an das Puzzle-DLC wagst. Du stößt sonst
möglicherweise auf dir noch nicht bekannte Mechaniken. Möchtest du
trotzdem fortfahren?
desc: Ich empfehle dir <strong>sehr</strong>, bis Level 12 zu spielen, bevor du
dich an das Puzzle-DLC wagst. Du stößt sonst möglicherweise auf dir
noch nicht bekannte Mechaniken. Möchtest du trotzdem fortfahren?
puzzleShare:
title: Kurzschlüssel kopiert
desc: Der Kurzschlüssel des Puzzles (<key>) wurde in die Zwischenablage kopiert!
@ -309,7 +325,6 @@ dialogs:
title: Puzzle löschen?
desc: Bist du sicher, dass du '<title>' löschen möchtest? Dies kann nicht
rückgängig gemacht werden!
ingame:
keybindingsOverlay:
moveMap: Bewegen
@ -397,9 +412,9 @@ ingame:
waypoints:
waypoints: Markierungen
hub: Hub
description: Linksklick auf eine Markierung, um dort hinzugelangen. Rechtsklick, um
sie zu löschen.<br><br>Drücke <keybinding>, um eine Markierung aus
deinem Blickwinkel, oder <strong>rechtsklicke</strong>, um eine
description: Linksklick auf eine Markierung, um dort hinzugelangen. Rechtsklick,
um sie zu löschen.<br><br>Drücke <keybinding>, um eine Markierung
aus deinem Blickwinkel, oder <strong>rechtsklicke</strong>, um eine
Markierung auf der ausgewählten Position zu erschaffen.
creationSuccessNotification: Markierung wurde erstellt.
shapeViewer:
@ -419,15 +434,16 @@ ingame:
Halte <strong>UMSCH</strong>, um mehrere Gebäude zu platzieren
und nutze <strong>R</strong>, um sie zu rotieren."
2_1_place_cutter: "Platziere nun einen <strong>Schneider</strong>, um die Kreise
zu halbieren.<br><br> Übrigens: Der Schneider
teilt Items immer von <strong>oben nach unten</strong>, unabhängig von
seiner Orientierung!"
zu halbieren.<br><br> Übrigens: Der Schneider teilt Items immer
von <strong>oben nach unten</strong>, unabhängig von seiner
Orientierung!"
2_2_place_trash: Der Schneider kann <strong>verstopfen</strong>!<br><br>Benutze
einen <strong>Mülleimer</strong> um den aktuell (!) nicht
benötigten Rest loszuwerden.
2_3_more_cutters: "Gut gemacht! Platziere noch <strong>zwei andere Schneider</strong>
um das Ganze zu beschleunigen.<br><br> Übrigens: Benutze die
<strong>Hotkeys 0-9</strong> um Gebäude schneller auszuwählen!"
2_3_more_cutters: "Gut gemacht! Platziere noch <strong>zwei andere
Schneider</strong> um das Ganze zu beschleunigen.<br><br>
Übrigens: Benutze die <strong>Hotkeys 0-9</strong> um Gebäude
schneller auszuwählen!"
3_1_rectangles: "Lass uns ein paar Quadrate extrahieren! <strong>Baue vier
Extraktoren</strong> und verbinde sie mit deinem Hub.<br><br>
PS: Halte <strong>SHIFT</strong>, während du ein Fließband
@ -441,8 +457,9 @@ ingame:
21_3_place_button: Perfekt! Platziere jetzt einen <strong>Schalter</strong> und
verbinde ihn mit Signalkabeln.
21_4_press_button: "Drücke den Schalter, damit er ein <strong>wahres
Signal</strong> ausgibt und den Färber aktiviert.<br><br>
PS: Du musst nicht alle Eingänge verbinden! Probiere es auch mal mit zwei."
Signal</strong> ausgibt und den Färber aktiviert.<br><br> PS: Du
musst nicht alle Eingänge verbinden! Probiere es auch mal mit
zwei."
connectedMiners:
one_miner: Ein Extraktor
n_miners: <amount> Extraktoren
@ -492,12 +509,21 @@ ingame:
puzzleEditorControls:
title: Puzzle-Editor
instructions:
- 1. Platziere einen <strong>Itemproduzenten</strong> um Formen und Farben für den Spieler bereitzustellen
- 2. Produziere eine oder mehrere Formen, die der Spieler herstellen soll und liefere diese zu einem oder mehreren <strong>Zielakzeptoren</strong>
- 3. Sobald ein Zielakzeptor eine Form für eine gewisse Zeit erhält, <strong>speichert dieser sie als Ziel</strong> (Angezeigt durch den <strong>grünen Punkt</strong>).
- 4. Klicke auf das <strong>Schloss</strong>, um ein Gebäude für den Spieler zu sperren.
- 5. Sobald du auf Überprüfen gedrückt hast, wird dein Puzzle `validiert und du kannst es veröffentlichen.
- 6. Bei der Freigabe werden <strong>alle Gebäude entfernt</strong>. Ausgenommen sind die Produzenten und Akzeptoren. Den Rest soll der Spieler schließlich selbst herausfinden :)
- 1. Platziere einen <strong>Itemproduzenten</strong> um Formen und
Farben für den Spieler bereitzustellen
- 2. Produziere eine oder mehrere Formen, die der Spieler herstellen
soll und liefere diese zu einem oder mehreren
<strong>Zielakzeptoren</strong>
- 3. Sobald ein Zielakzeptor eine Form für eine gewisse Zeit erhält,
<strong>speichert dieser sie als Ziel</strong> (Angezeigt durch
den <strong>grünen Punkt</strong>).
- 4. Klicke auf das <strong>Schloss</strong>, um ein Gebäude für den
Spieler zu sperren.
- 5. Sobald du auf Überprüfen gedrückt hast, wird dein Puzzle
`validiert und du kannst es veröffentlichen.
- 6. Bei der Freigabe werden <strong>alle Gebäude entfernt</strong>.
Ausgenommen sind die Produzenten und Akzeptoren. Den Rest soll der
Spieler schließlich selbst herausfinden :)
puzzleCompletion:
title: Puzzle geschafft!
titleLike: "Klicke auf das Herz, wenn dir das Puzzle gefallen hat:"
@ -505,13 +531,13 @@ ingame:
titleRatingDesc: Deine Bewertung hilft mir, in Zukunft bessere Vorschläge zu machen
continueBtn: Weiterspielen
menuBtn: Menü
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Ersteller
shortKey: Kurzschlüssel
rating: Schwierigkeitsgrad
averageDuration: Durchschnittliche Dauer
completionRate: Abschlussrate
shopUpgrades:
belt:
name: Fließbänder, Verteiler & Tunnel
@ -525,7 +551,6 @@ shopUpgrades:
painting:
name: Mischer & Färber
description: Geschw. x<currentMult> → x<newMult>
buildings:
hub:
deliver: Liefere
@ -693,9 +718,9 @@ buildings:
reader:
default:
name: Fließbandkontrolle
description: Misst den gemittelten Durchsatz des Fließbandes. Gibt zusätzlich den
zuletzt passierten Gegenstand auf der Wires-Ebene aus (sobald
freigeschaltet).
description: Misst den gemittelten Durchsatz des Fließbandes. Gibt zusätzlich
den zuletzt passierten Gegenstand auf der Wires-Ebene aus
(sobald freigeschaltet).
analyzer:
default:
name: Formanalyse
@ -741,13 +766,15 @@ buildings:
default:
name: Sperrblock
description: Ermöglicht das Blockieren einer Kachel.
storyRewards:
reward_cutter_and_trash:
title: Formen zerschneiden
desc: Du hast gerade den <strong>Schneider</strong> freigeschaltet, der Formen vertikal halbiert, <b>unabhängig von seiner Orientierung</b>!<br><br>
Achte darauf, die Überreste loszuwerden, sonst <b>verstopft und blockiert er</b> - Zu diesem Zweck habe ich
dir den <strong>Mülleimer</strong> gegeben. Er entsorgt alles, was du ihm fütterst!
desc: Du hast gerade den <strong>Schneider</strong> freigeschaltet, der Formen
vertikal halbiert, <b>unabhängig von seiner
Orientierung</b>!<br><br> Achte darauf, die Überreste loszuwerden,
sonst <b>verstopft und blockiert er</b> - Zu diesem Zweck habe ich
dir den <strong>Mülleimer</strong> gegeben. Er entsorgt alles, was
du ihm fütterst!
reward_rotater:
title: Rotieren
desc: Der <strong>Rotierer</strong> wurde freigeschaltet! Er rotiert Formen im
@ -772,8 +799,8 @@ storyRewards:
reward_balancer:
title: Verteiler
desc: Der multifunktionale <strong>Verteiler</strong> wurde freigeschaltet!
Damit kannst du nun endlich größere Fabriken bauen. Er kann Fließbänder
<strong>aufteilen oder zusammenlegen</strong>!
Damit kannst du nun endlich größere Fabriken bauen. Er kann
Fließbänder <strong>aufteilen oder zusammenlegen</strong>!
reward_tunnel:
title: Tunnel
desc: Der <strong>Tunnel</strong> wurde freigeschaltet! Du kannst Items nun
@ -787,9 +814,9 @@ storyRewards:
reward_miner_chainable:
title: Extraktor (Kette)
desc: "Du hast den <strong>Kettenextraktor</strong> freigeschaltet! Er kann
seine Ressourcen an andere Extraktoren
<strong>weitergeben</strong>. <br><br> PS: Der alte Extraktor
wurde jetzt in deiner Symbolleiste ersetzt!"
seine Ressourcen an andere Extraktoren <strong>weitergeben</strong>.
<br><br> PS: Der alte Extraktor wurde jetzt in deiner Symbolleiste
ersetzt!"
reward_underground_belt_tier_2:
title: Tunnel Stufe II
desc: Du hast eine neue Variante des <strong>Tunnels</strong> freigeschaltet!
@ -848,8 +875,8 @@ storyRewards:
<strong>vierfachen Färber</strong>. Schließe die Eingänge, mit denen
du die Quadranten färben möchtest, an ein Signalkabel auf der
Wires-Ebene an!<br><br> Mit <strong>E</strong> wechselst du zwischen
den Ebenen. <br><br>PS: <strong>Aktiviere die Hinweise</strong> in den
Einstellungen, um das Tutorial anzuzeigen!"
den Ebenen. <br><br>PS: <strong>Aktiviere die Hinweise</strong> in
den Einstellungen, um das Tutorial anzuzeigen!"
reward_filter:
title: Itemfilter
desc: Du hast den <strong>Itemfilter</strong> freigeschaltet! Items, die dem
@ -910,11 +937,11 @@ storyRewards:
jetzt einen bestimmten <strong>Durchsatz</strong> benötigt, empfehle
ich dringend, eine Maschine zu bauen, die automatisch die gewünschte
Form liefert!<br><br> Der Hub gibt die gewünschte Form auf der
Wires-Ebene aus, also musst du sie nur analysieren und deine Fabrik dementsprechend konfigurieren (lassen).
Wires-Ebene aus, also musst du sie nur analysieren und deine Fabrik
dementsprechend konfigurieren (lassen).
reward_demo_end:
title: Ende der Demo
desc: Du bist am Ende der Demo angekommen!
settings:
title: Einstellungen
categories:
@ -1022,11 +1049,13 @@ settings:
title: Intelligente Tunnel
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 Tunnel werden ebenfalls entfernt.
Ziehen von Tunneln und überschüssige Tunnel werden ebenfalls
entfernt.
vignette:
title: Vignette
description: Aktiviert den Vignetteneffekt, der den Rand des Bildschirms
zunehmend verdunkelt und damit das Lesen der Textfelder vereinfacht.
zunehmend verdunkelt und damit das Lesen der Textfelder
vereinfacht.
rotationByBuilding:
title: Rotation pro Gebäudetyp
description: Jeder Gebäudetyp merkt sich eigenständig, in welche Richtung er
@ -1052,10 +1081,10 @@ settings:
Außerdem vereinfacht es die Darstellung!
clearCursorOnDeleteWhilePlacing:
title: Abwählen mit Rechtsklick
description: Ist standardmäßig eingeschaltet und wählt das aktuell
ausgewählte Gebäude ab, wenn du die rechte Maustaste drückst.
Wenn du es abschaltest, kannst du mit der rechten Maustaste
Gebäude löschen, während du im Platzierungsmodus bist.
description: Ist standardmäßig eingeschaltet und wählt das aktuell ausgewählte
Gebäude ab, wenn du die rechte Maustaste drückst. Wenn du es
abschaltest, kannst du mit der rechten Maustaste Gebäude
löschen, während du im Platzierungsmodus bist.
lowQualityTextures:
title: Niedrige Texturqualität (Unschön)
description: Das Spiel verwendet eine niedrigere Auflösung bei den Texturen.
@ -1067,8 +1096,9 @@ settings:
anzeigen.
pickMinerOnPatch:
title: Automatisch Extraktor auswählen
description: Ist standardmäßig eingeschaltet und du wählst automatisch den Extraktor,
wenn du mit der Pipette auf einen Ressourcenfleck zeigst.
description: Ist standardmäßig eingeschaltet und du wählst automatisch den
Extraktor, wenn du mit der Pipette auf einen Ressourcenfleck
zeigst.
simplifiedBelts:
title: Minimalistische Fließbänder (Unschön)
description: Zur Verbesserung der Leistung werden die Items auf Fließbändern nur
@ -1088,7 +1118,11 @@ settings:
title: Größe der Ressourcen auf der Karte
description: Legt die Größe der Ressourcen auf der Karte (beim Herauszoomen)
fest.
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
tickrateHz: <amount> Hz
keybindings:
title: Tastenbelegung
hint: "Tipp: Benutze STRG, UMSCH and ALT! Sie aktivieren verschiedene
@ -1170,10 +1204,11 @@ keybindings:
placementDisableAutoOrientation: Automatische Orientierung deaktivieren
placeMultiple: Im Platzierungsmodus bleiben
placeInverse: Automatische Fließbandorientierung invertieren
showShapeTooltip: Show shape output tooltip
about:
title: Über dieses Spiel
body: Dieses Spiel ist quelloffen (Open Source) und wurde von <a href="https://github.com/tobspr" target="_blank">Tobias Springer</a>
body: Dieses Spiel ist quelloffen (Open Source) und wurde von <a
href="https://github.com/tobspr" target="_blank">Tobias Springer</a>
(das bin ich!) entwickelt.<br><br> Wenn du etwas zum Spiel beitragen
möchtest, dann schaue dir <a href="<githublink>"
target="_blank">shapez.io auf GitHub</a> an.<br><br> Das Spiel wurde
@ -1185,10 +1220,8 @@ about:
möchte ich meinem Kumpel <a href="https://github.com/niklas-dahl"
target="_blank">Niklas</a> danken! Ohne unsere etlichen gemeinsamen
Stunden in Factorio wäre dieses Projekt nie zustande gekommen.
changelog:
title: Änderungsprotokoll
demo:
features:
restoringGames: Spielstände wiederherstellen
@ -1197,15 +1230,14 @@ demo:
customizeKeybindings: Tastenbelegung anpassen
exportingBase: Ganze Fabrik als Foto exportieren
settingNotAvailable: Nicht verfügbar in der Demo.
backendErrors:
ratelimit: Du führst deine Aktionen zu schnell aus. Bitte warte kurz.
invalid-api-key: Kommunikation mit dem Back-End fehlgeschlagen. Versuche das
Spiel neu zu starten oder zu updaten (Ungültiger Api-Schlüssel).
unauthorized: Kommunikation mit dem Back-End fehlgeschlagen. Versuche das Spiel
neu zu starten oder zu updaten (Nicht autorisiert).
bad-token: Kommunikation mit dem Back-End fehlgeschlagen. Versuche das Spiel
neu zu starten oder zu updaten (Ungültiger Token).
bad-token: Kommunikation mit dem Back-End fehlgeschlagen. Versuche das Spiel neu
zu starten oder zu updaten (Ungültiger Token).
bad-id: Ungültige Puzzle-ID.
not-found: Das Puzzle konnte nicht gefunden werden.
bad-category: Die Kategorie konnte nicht gefunden werden.
@ -1224,7 +1256,6 @@ backendErrors:
too-many-likes-already: Dieses Puzzle ist in der Community sehr beliebt. Wenn du
es trotzdem löschen möchtest, wende dich bitte an support@shapez.io!
no-permission: Dir fehlt die Berechtigung, um diese Aktion auszuführen.
tips:
- Der Hub akzeptiert alle Formen, nicht nur die aktuell geforderten!
- Stelle sicher, dass deine Fabriken modular sind. Es zahlt sich irgendwann
@ -1290,7 +1321,8 @@ tips:
- Mische alle drei Grundfarben, um Weiß zu erhalten!
- Du hast eine unendlich große Karte, nutze den Platz und expandiere!
- Probier auch mal Factorio! Es ist mein Lieblingsspiel.
- Der vierfache Schneider schneidet im Uhrzeigersinn von oben rechts beginnend!
- Der vierfache Schneider schneidet im Uhrzeigersinn von oben rechts
beginnend!
- Du kannst deine Speicherstände im Hauptmenü herunterladen!
- Diese Spiel hat viele nützliche Tastenbelegungen! Schau sie dir in den
Einstellungen an.

View File

@ -475,6 +475,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1038,7 +1039,12 @@ settings:
title: Map Resources Size
description: Controls the size of the shapes on the map overview (when zooming
out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Συνδιασμοί πλήκτρων
hint: "Συμβουλή: Φρόντισε να χρησιμοποιήσεις τα πλήκτρα CTRL, SHIFT και ALT!
@ -1120,6 +1126,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: Σχετικά με αυτό το παιχνίδι
body: >-
@ -1254,8 +1261,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -155,10 +155,28 @@ puzzleMenu:
account: My Puzzles
search: Search
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
difficulties:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
validation:
title: Invalid Puzzle
@ -657,6 +675,7 @@ ingame:
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
@ -1080,7 +1099,7 @@ settings:
staging: Staging
prod: Production
buildDate: Built <at-date>
tickrateHz: <amount> Hz
rangeSliderPercentage: <amount> %
labels:
@ -1267,6 +1286,11 @@ settings:
description: >-
Controls the size of the shapes on the map overview (when zooming out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: >-
Whether to always show the shape tooltip when hovering buildings, instead of having to hold 'ALT'.
keybindings:
title: Keybindings
hint: >-
@ -1363,6 +1387,8 @@ keybindings:
placeMultiple: Stay in placement mode
placeInverse: Invert automatic belt orientation
showShapeTooltip: Show shape output tooltip
about:
title: About this Game
body: >-

View File

@ -25,8 +25,8 @@ steamPage:
global:
loading: Cargando
error: Error
thousandsDivider: ","
decimalSeparator: .
thousandsDivider: .
decimalSeparator: ","
suffix:
thousands: k
millions: M
@ -78,7 +78,7 @@ mainMenu:
puzzleDlcText: ¿Disfrutas compactando y optimizando fábricas? ¡Consigue ahora el
DLC de Puzles en Steam para aún más diversión!
puzzleDlcWishlist: ¡Añádelo ahora a tu lista de deseos!
puzzleDlcViewNow: View Dlc
puzzleDlcViewNow: Ver Dlc
dialogs:
buttons:
ok: OK
@ -198,7 +198,7 @@ dialogs:
desc: Hay un video tutorial disponible para este nivel, pero solo está
disponible en inglés ¿Te gustaría verlo?
editConstantProducer:
title: Set Item
title: Elegir item
puzzleLoadFailed:
title: Fallo al cargar los Puzles
desc: Desafortunadamente, no se pudieron cargar los puzles.
@ -248,12 +248,12 @@ dialogs:
puzzleReport:
title: Reportar Puzle
options:
profane: Lenguaje soez
profane: Profanidades
unsolvable: Imposible de resolver
trolling: Troll
puzzleReportComplete:
title: ¡Gracias por tu aporte!
desc: El puzle ha sido marcado como abuso.
desc: El puzle ha sido reportado exitosamente.
puzzleReportError:
title: No se pudo reportar
desc: "No pudimos procesar tu informe:"
@ -261,8 +261,8 @@ dialogs:
title: Introducir clave
desc: Introduce la clave del puzle para cargarlo.
puzzleDelete:
title: Delete Puzzle?
desc: Are you sure you want to delete '<title>'? This can not be undone!
title: ¿Eliminar Puzle?
desc: ¿Estas seguro de querer eliminar '<title>'? ¡Esto no se puede deshacer!
ingame:
keybindingsOverlay:
moveMap: Mover
@ -284,7 +284,7 @@ ingame:
clearSelection: Limpiar selección
pipette: Cuentagotas
switchLayers: Cambiar capas
clearBelts: Clear belts
clearBelts: Borrar cintas
colors:
red: Rojo
green: Verde
@ -473,6 +473,7 @@ ingame:
titleRatingDesc: Tu puntuación me ayudará a hacerte mejores sugerencias en el futuro
continueBtn: Continuar Jugando
menuBtn: Menú
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Autor
shortKey: Clave
@ -621,29 +622,29 @@ buildings:
default:
name: Puerta AND
description: Emite el valor booleano "1" si ambas entradas son verdaderas.
(Verdadeas significa una forma, color o valor booleano "1")
(Verdaderas significa una forma, color o valor booleano "1")
not:
name: Puerta NOT
description: Emite el valor booleano "1" si ambas entradas no son verdaderas.
(Verdadeas significa una forma, color o valor booleano "1")
(Verdaderas significa una forma, color o valor booleano "1")
xor:
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")
pero no si ambas lo son. (Verdaderas significa una forma, color
o valor booleano "1")
or:
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")
(Verdaderas significa una forma, color o valor booleano "1")
transistor:
default:
name: Transistor
description: Envia la señal de abajo si la señal del costado es verdadera
(Verdadeas significa una forma, color o valor booleano "1").
(Verdaderas significa una forma, color o valor booleano "1").
mirrored:
name: Transistor
description: Envia la señal de abajo si la señal del costado es verdadera
(Verdadeas significa una forma, color o valor booleano "1").
(Verdaderas significa una forma, color o valor booleano "1").
filter:
default:
name: Filtro
@ -664,7 +665,7 @@ buildings:
analyzer:
default:
name: Analizador de formas
description: analiza el cuadrante de arriba a la derecha de la capa más baja de
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:
@ -1046,7 +1047,12 @@ settings:
title: Tamaño de recursos en el mapa
description: Controla el tamaño de los recursos en la vista de aérea del mapa
(Al hacer zoom mínimo).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Atajos de teclado
hint: "Pista: ¡Asegúrate de usar CTRL, SHIFT y ALT! Habilitan distintas opciones
@ -1128,6 +1134,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: Sobre el juego
body: >-
@ -1244,22 +1251,22 @@ puzzleMenu:
levels: Niveles
new: Nuevos
top-rated: Los mejor valorados
mine: Mis Puzles
mine: Mios
easy: Fáciles
hard: Difíciles
completed: Completados
medium: Medium
official: Official
trending: Trending today
trending-weekly: Trending weekly
categories: Categories
difficulties: By Difficulty
account: My Puzzles
search: Search
medium: Medios
official: Oficiales
trending: Tendencias de hoy
trending-weekly: Tendencias de la semana
categories: Categorías
difficulties: Por dificultad
account: Mis puzles
search: Buscar
validation:
title: Puzle no válido
noProducers: Por favor, ¡pon un Productor de una sola pieza!
noGoalAcceptors: Por favor , ¡pon un Aceptador de objetivos!
noProducers: Por favor, ¡Pon un Productor de una sola pieza!
noGoalAcceptors: Por favor, ¡Pon un Aceptador de objetivos!
goalAcceptorNoItem: Uno o más aceptadores de objetivos no tienen asignado un
elemento. Transporta una forma hacia ellos para poner un objetivo.
goalAcceptorRateNotMet: Uno o más aceptadores de objetivos no están recibiendo
@ -1271,11 +1278,26 @@ puzzleMenu:
solo elemento no están conectados directamente a tus aceptadores de
objetivos.
difficulties:
easy: Fácil
medium: Medio
hard: Dificil
unknown: Unrated
dlcHint: ¿Ya compraste el DLC? Asegurate de tenerlo activado haciendo click
derecho a shapez.io en tu biblioteca, selecionando propiedades > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: Estás haciendo tus acciones con demasiada frecuencia. Por favor,
espera un poco.
@ -1289,7 +1311,7 @@ backendErrors:
not-found: No pudimos encontrar ese puzle.
bad-category: No pudimos encontar esa categoría.
bad-short-key: La clave que nos diste no es válida.
profane-title: El título de tu puzle contiene lenguaje soez.
profane-title: El título de tu puzle contiene lenguaje profano.
bad-title-too-many-spaces: El título de tu puzle es demasiado breve.
bad-shape-key-in-emitter: Un productor de un solo elemento tiene un elemento no válido.
bad-shape-key-in-goal: Un aceptador de objetivos tiene un elemento no válido.
@ -1300,6 +1322,7 @@ backendErrors:
bad-payload: La petición contiene datos no válidos.
bad-building-placement: Tu puzle contiene edificios en posiciones no válidas.
timeout: El tiempo para la solicitud ha expirado.
too-many-likes-already: The puzzle alreay got too many likes. If you still want
to remove it, please contact support@shapez.io!
no-permission: You do not have the permission to perform this action.
too-many-likes-already: El puzle ha recibido demasiados me gusta ¡Si todavía
quieres eliminarlo, por favor contacta a support@shapez.io! (Solo
inglés)
no-permission: No tienes los permisos necesarios para llevar a cabo esta acción.

View File

@ -458,6 +458,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1004,7 +1005,12 @@ settings:
mapResourcesScale:
title: Kartan resurssien koko
description: Määrittää muotojen koon kartalla (loitonnettaessa).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Pikanäppäimet
hint: "Vinkki: Muista käyttää CTRL, SHIFT ja ALT! Ne ottavat käyttöön erilaisia
@ -1086,6 +1092,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: Tietoja tästä pelistä
body: >-
@ -1214,8 +1221,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -11,14 +11,14 @@ steamPage:
Et en plus, vous devrez aussi produire de plus en plus pour satisfaire la demande. La seule solution est de construire en plus grand! Au début vous ne ferez que découper les formes, mais plus tard vous devrez les peindre  et pour ça vous devrez extraire et mélanger des couleurs!
En achetant le jeu sur Steam, vous aurez accès à la version complète, mais vous pouvez aussi jouer à une démo sur shapez.io et vous décider ensuite!
what_others_say: Ce que les gens pensent de shapez.io
nothernlion_comment: This game is great - I'm having a wonderful time playing,
and time has flown by.
what_others_say: Ce que les gens pensent de Shapez.io
nothernlion_comment: Ce jeu est génial - Je passe un merveilleux moment à jouer,
et le temps s'est envolé.
notch_comment: Mince ! Je devrais vraiment me coucher, mais je crois que j'ai
trouvé comment faire un ordinateur dans shapez.io
steam_review_comment: This game has stolen my life and I don't want it back.
Very chill factory game that won't let me stop making my lines more
efficient.
trouvé comment faire un ordinateur dans Shapez.io
steam_review_comment: Ce jeu a volé ma vie et je ne veux pas la récupérer. Jeu
d'usine très cool qui ne me laissera pas arrêter de rendre mes lignes
plus efficaces.
global:
loading: Chargement
error: Erreur
@ -71,11 +71,11 @@ mainMenu:
savegameLevel: Niveau <x>
savegameLevelUnknown: Niveau inconnu
savegameUnnamed: Sans titre
puzzleMode: Puzzle Mode
back: Back
puzzleMode: Mode Puzzle
back: Retour
puzzleDlcText: Vous aimez compacter et optimiser vos usines ? Achetez le DLC sur
Steam dés maintenant pour encore plus d'amusement !
puzzleDlcWishlist: Wishlist now!
Steam dès maintenant pour encore plus d'amusement!
puzzleDlcWishlist: Ajoute à ta liste de souhaits maintenant !
puzzleDlcViewNow: View Dlc
dialogs:
buttons:
@ -90,7 +90,7 @@ dialogs:
viewUpdate: Voir les mises à jour
showUpgrades: Montrer les améliorations
showKeybindings: Montrer les raccourcis
retry: Réesayer
retry: Réessayer
continue: Continuer
playOffline: Jouer Hors-ligne
importSavegameError:
@ -201,62 +201,65 @@ dialogs:
submitPuzzle:
title: Envoyer le Puzzle
descName: "Donnez un nom à votre puzzle:"
descIcon: "Please enter a unique short key, which will be shown as the icon of
your puzzle (You can generate them <link>here</link>, or choose one
of the randomly suggested shapes below):"
placeholderName: Puzzle Title
descIcon: "Veuillez entrer un raccourci de forme unique, qui sera affichée comme
icône de votre puzzle (Vous pouvez générer le raccourci d'une forme
<link>ici</link>, ou en choisir une parmi les formes suggérées
alétoirement ci-dessous):"
placeholderName: Titre du Puzzle
puzzleResizeBadBuildings:
title: Resize not possible
desc: You can't make the zone any smaller, because then some buildings would be
outside the zone.
title: Impossible de redimensionner
desc: Vous ne pouvez pas rétrécir la zone, car certains bâtiments seraient en
dehors de la zone
puzzleLoadError:
title: Mauvais Puzzle
desc: "Le chargement du puzzle a échoué:"
offlineMode:
title: Mode hors-ligne
desc: We couldn't reach the servers, so the game has to run in offline mode.
Please make sure you have an active internet connection.
desc: Nous n'avons pas pu atteindre les serveurs, donc le jeu doit être mis en
mode hors ligne. Veuillez vous assurez que vous disposez d'une
connexion Internet active.
puzzleDownloadError:
title: Erreur de téléchargment
desc: "Le téléchargement à échoué :"
desc: "Le téléchargement a échoué:"
puzzleSubmitError:
title: Erreur d'envoi
desc: "L'envoi à échoué :"
desc: "L'envoi a échoué:"
puzzleSubmitOk:
title: Puzzle envoyé
desc: Félicitation ! Votre puzzle à été envoyé et peut maintenant être joué.
desc: Félicitations ! Votre puzzle a été envoyé et peut maintenant être joué.
Vous pouvez maintenant le retrouver dans la section "Mes Puzzles".
puzzleCreateOffline:
title: Mode Hors-ligne
desc: Since you are offline, you will not be able to save and/or publish your
puzzle. Would you still like to continue?
desc: Puisque vous êtes hors ligne, vous ne pourrez pas enregistrer et/ou
publier votre puzzle. Souhaitez-vous toujours continuer ?
puzzlePlayRegularRecommendation:
title: Recommendation
desc: I <strong>strongly</strong> recommend playing the normal game to level 12
before attempting the puzzle DLC, otherwise you may encounter
mechanics not yet introduced. Do you still want to continue?
title: Recommandation
desc: Je recommande <strong>fortement</strong> de jouer au jeu normal jusqu'au
niveau 12 avant d'essayer le Puzzle DLC, sinon vous risqez de
rencontrer des méchanismes pas encore introduits. Voulez-vous
toujours continuer ?
puzzleShare:
title: Short Key Copied
desc: The short key of the puzzle (<key>) has been copied to your clipboard! It
can be entered in the puzzle menu to access the puzzle.
title: Code copié
desc: Le code du puzzle (<key>) a été copié dans ton presse-papiers ! Il peut
être entré dans le menu des puzzles pour accéder au puzzle.
puzzleReport:
title: Report Puzzle
title: Signaler le Puzzle
options:
profane: Profane
unsolvable: Not solvable
trolling: Trolling
unsolvable: Irrésolvable
trolling: Troll
puzzleReportComplete:
title: Merci pour votre retour!
desc: Le puzzle a été marqué.
puzzleReportError:
title: Failed to report
desc: "Your report could not get processed:"
title: Échec du signalement
desc: "Votre signalement n'a pas pu être effectué:"
puzzleLoadShortKey:
title: Enter short key
desc: Enter the short key of the puzzle to load it.
title: Entrer un code
desc: Entrer le code du puzzle pour le charger.
puzzleDelete:
title: Delete Puzzle?
desc: Are you sure you want to delete '<title>'? This can not be undone!
title: Supprimer le puzzle ?
desc: Êtes-vous sûr de vouloir supprimer '<title>' ? Cela sera irréversible !
ingame:
keybindingsOverlay:
moveMap: Déplacer
@ -430,28 +433,30 @@ ingame:
title: Me soutenir
desc: Je le développe pendant mon temps libre!
achievements:
title: Achievements
desc: Hunt them all!
title: Succès
desc: Débloquez-les tous !
puzzleEditorSettings:
zoneTitle: Zone
zoneWidth: Width
zoneHeight: Height
trimZone: Trim
clearItems: Clear Items
share: Share
report: Report
zoneWidth: Largeur
zoneHeight: Hauteur
trimZone: Optimiser la taille
clearItems: Supprimer les objets
share: Partager
report: Signaler
clearBuildings: Clear Buildings
resetPuzzle: Reset Puzzle
puzzleEditorControls:
title: Puzzle Creator
title: Créateur de Puzzles
instructions:
- 1. Place <strong>Constant Producers</strong> to provide shapes and
colors to the player
- 2. Build one or more shapes you want the player to build later and
deliver it to one or more <strong>Goal Acceptors</strong>
- 3. Once a Goal Acceptor receives a shape for a certain amount of
time, it <strong>saves it as a goal</strong> that the player must
produce later (Indicated by the <strong>green badge</strong>).
- 1. Placez des <strong>Producteurs Constants</strong> pour fournir
des formes et des couleurs au joueur
- 2. Fabriquez une ou plusieurs formes que vous voulez que le joueur
fabrique plus tard et délivrez-la/les à un ou plusieurs
<strong>Récepteurs d'Objectif</strong>
- 3. Une fois qu'un Récépteur d'Objectif a reçu une forme pendant un
certain temps, il <strong>l'enregistre zn tant
qu'objectif</strong> que le joueur devra produire plus tard
(Indiqué par le <strong>badge vert</strong>).
- 4. Click the <strong>lock button</strong> on a building to disable
it.
- 5. Once you click review, your puzzle will be validated and you
@ -460,18 +465,19 @@ ingame:
except for the Producers and Goal Acceptors - That's the part that
the player is supposed to figure out for themselves, after all :)
puzzleCompletion:
title: Puzzle Completed!
titleLike: "Click the heart if you liked the puzzle:"
titleRating: How difficult did you find the puzzle?
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
title: Puzzle Résolu !
titleLike: "Cliquez sur le cœur si vous avez aimé le Puzzle:"
titleRating: À quel point avez-vous trouvé le puzzle diffcile ?
titleRatingDesc: Votre note m'aidera à vous faire de meilleures suggestions à l'avenir
continueBtn: Continuer à jouer
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
author: Auteur
shortKey: Short Key
rating: Difficulty score
averageDuration: Avg. Duration
completionRate: Completion rate
rating: Niveau de difficulté
averageDuration: Durée moyenne
completionRate: Taux de réussite
shopUpgrades:
belt:
name: Convoyeurs, distributeurs et tunnels
@ -691,25 +697,26 @@ buildings:
calque de câblage sur le calque normal.
constant_producer:
default:
name: Constant Producer
description: Constantly outputs a specified shape or color.
name: Producteur Constabnt
description: Sort constamment une forme ou une couleur spécifiée.
goal_acceptor:
default:
name: Goal Acceptor
description: Deliver shapes to the goal acceptor to set them as a goal.
name: Récepteur d'Objetcif
description: Délivrez des formes au récepteur d'objectif pour les définir comme
objectif.
block:
default:
name: Block
description: Allows you to block a tile.
name: Bloc
description: Permet de bloquer une case.
storyRewards:
reward_cutter_and_trash:
title: Découpage de formes
desc: You just unlocked the <strong>cutter</strong>, which cuts shapes in half
from top to bottom <strong>regardless of its
orientation</strong>!<br><br>Be sure to get rid of the waste, or
otherwise <strong>it will clog and stall</strong> - For this purpose
I have given you the <strong>trash</strong>, which destroys
everything you put into it!
desc: Vous venez de déverrouiller le <strong>découpeur</strong>, qui coupe les
formes en deux de haut en bas <strong>indépendamment de son
orientation</strong>!<br><br>Assurez-vous de vous débarrasser des
déchets, ou sinon <strong>il se bouchera et se bloquera</strong> - À
cet effet, Je vous ai donné la <strong>poubelle</strong>, qui
détruit tout ce que vous mettez dedans !
reward_rotater:
title: Rotation
desc: Le <strong>pivoteur</strong> a été débloqué! Il pivote les formes de 90
@ -735,9 +742,10 @@ storyRewards:
<strong>placée au-dessus</strong> de la forme de gauche.
reward_balancer:
title: Répartiteur
desc: The multifunctional <strong>balancer</strong> has been unlocked - It can
be used to build bigger factories by <strong>splitting and merging
items</strong> onto multiple belts!
desc: Le <strong>répartiteur</strong> multifonctionnel a été débloqué - Il peut
être utilisé pour construire de plus grandes usines en
<strong>divisant et en rassemblant des objets</strong> sur plusieurs
convoyeurs !
reward_tunnel:
title: Tunnel
desc: Le <strong>tunnel</strong> a été débloqué. Vous pouvez maintenant faire
@ -843,14 +851,17 @@ storyRewards:
gâteau : je vous donne aussi le <strong>transistor</strong>!"
reward_virtual_processing:
title: Traitement virtuel
desc: I just gave a whole bunch of new buildings which allow you to
<strong>simulate the processing of shapes</strong>!<br><br> You can
now simulate a cutter, rotator, stacker and more on the wires layer!
With this you now have three options to continue the game:<br><br> -
Build an <strong>automated machine</strong> to create any possible
shape requested by the HUB (I recommend to try it!).<br><br> - Build
something cool with wires.<br><br> - Continue to play
normally.<br><br> Whatever you choose, remember to have fun!
desc: Je viens de vous donner tout un tas de nouveaux bâtiments qui vous
permettent de <strong>simuler le traitement des
formes</strong>!<br><br> Vous pouvez maintenant simuler un
découpeur, un pivoteur, un assembleur et plus encore sur la couche
des fils ! Avec cela vous avez maintenant trois options pour
continuer le jeu:<br><br> - Construire une <strong>machine
automatique</strong> pour créer toute forme possible demandée par le
HUB (Je recommande d'essayer de le faire !).<br><br> - Construire
quelque chose de cool avec les fils.<br><br> - Continuer à jouer
normalement.<br><br> Quoi que vous choisissiez, n'oubliez pas de
vous amuser !
no_reward:
title: Niveau suivant
desc: "Ce niveau na pas de récompense mais le prochain, si!<br><br> PS : Ne
@ -1049,6 +1060,11 @@ settings:
title: Taille des ressources sur la carte
description: Contrôle la taille des formes sur la vue densemble de la carte
visible en dézoomant.
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
tickrateHz: <amount> Hz
keybindings:
title: Contrôles
hint: "Astuce : Noubliez pas dutiliser CTRL, MAJ et ALT! Ces touches activent
@ -1127,10 +1143,11 @@ keybindings:
rotateToDown: "Rotate: Point Down"
rotateToRight: "Rotate: Point Right"
rotateToLeft: "Rotate: Point Left"
constant_producer: Constant Producer
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
constant_producer: Producteur Constant
goal_acceptor: Récepteur d'Objectif
block: Bloc
massSelectClear: Vider les convoyeurs
showShapeTooltip: Show shape output tooltip
about:
title: À propos de ce jeu
body: >-
@ -1156,7 +1173,7 @@ demo:
exportingBase: Exporter une image de toute la base
settingNotAvailable: Indisponible dans la démo.
tips:
- Le centre nimporte quelle forme, pas seulement la forme actuelle!
- Le centre accepte nimporte quelle forme, pas seulement la forme actuelle!
- Assurez-vous que vos usines soient modulaires, cela paiera!
- Ne construisez pas trop près du centre, ou ce sera un énorme chaos!
- Si lempilement ne fonctionne pas, essayez déchanger les entrées.
@ -1237,7 +1254,7 @@ puzzleMenu:
edit: Éditer
title: Mode Puzzle
createPuzzle: Créer un Puzzle
loadPuzzle: charger
loadPuzzle: Charger
reviewPuzzle: Revoir & Publier
validatingPuzzle: Validation du Puzzle
submittingPuzzle: Publication du Puzzle
@ -1245,19 +1262,19 @@ puzzleMenu:
categories:
levels: Niveaux
new: Nouveau
top-rated: Les-mieux notés
top-rated: Les mieux notés
mine: Mes puzzles
easy: Facile
hard: Difficile
completed: Complété
medium: Medium
official: Official
official: Officiel
trending: Trending today
trending-weekly: Trending weekly
categories: Categories
difficulties: By Difficulty
account: My Puzzles
search: Search
categories: Catégories
difficulties: Par Difficulté
account: Mes Puzzles
search: Rechercher
validation:
title: Puzzle invalide
noProducers: Veuillez placer un producteur constant !
@ -1276,8 +1293,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: Vous effectuez vos actions trop fréquemment. Veuillez attendre un peu
s'il vous plait.
@ -1302,6 +1334,6 @@ backendErrors:
bad-payload: La demande contient des données invalides.
bad-building-placement: Votre puzzle contient des bâtiments placés non valides.
timeout: La demande a expiré.
too-many-likes-already: The puzzle alreay got too many likes. If you still want
too-many-likes-already: The puzzle already got too many likes. If you still want
to remove it, please contact support@shapez.io!
no-permission: You do not have the permission to perform this action.

View File

@ -444,6 +444,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -952,6 +953,11 @@ settings:
mapResourcesScale:
title: גודל המשאבים במפה
description: .שולט על הגודל של הצורות על המפה (בתצוגה המוקטנת)
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
tickrateHz: <amount> Hz
keybindings:
title: מקשים
hint: ".הם מאפשרים הרבה אפשרויות השמה !ALTו SHIFT ,CTRLטיפ: השתמש ב"
@ -1032,6 +1038,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: בנוגע למשחק הזה
body: >-
@ -1157,8 +1164,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -458,6 +458,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -998,7 +999,12 @@ settings:
title: Map Resources Size
description: Controls the size of the shapes on the map overview (when zooming
out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Tipka
hint: "Savjet: Be sure to make use of CTRL, SHIFT and ALT! They enable different
@ -1080,6 +1086,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: O Igri
body: >-
@ -1207,8 +1214,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -464,6 +464,7 @@ ingame:
jövőben
continueBtn: Játék Folytatása
menuBtn: Menü
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Szerző
shortKey: Gyorskód
@ -1025,7 +1026,12 @@ settings:
title: Erőforrások Mérete a Térképen
description: Kizoomolt állapotban a térképen megjelenő erőforrások (alakzatok és
színek) méretét állítja.
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Gyorsbillentyűk
hint: "Tipp: Használd ki a CTRL, SHIFT és ALT billentyűket, amelyek különféle
@ -1107,6 +1113,7 @@ keybindings:
goal_acceptor: Elfogadó
block: Blokkolás
massSelectClear: Futószalagok Kiürítése
showShapeTooltip: Show shape output tooltip
about:
title: A Játékról
body: >-
@ -1242,8 +1249,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: Túl gyorsan csinálsz dolgokat. Kérlek, várj egy kicsit.
invalid-api-key: Valami nem oké a játékkal. Próbáld meg frissíteni vagy

View File

@ -467,6 +467,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1057,7 +1058,12 @@ settings:
title: Ukuran Sumber Daya Peta
description: Mengontrol ukuran bentuk-bentuk pada gambaran peta (ketika zoom
out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Tombol Pintas
hint: "Petunjuk: Pastikan kamu menggunakan CTRL, SHIFT and ALT! Mereka
@ -1139,6 +1145,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: Tentang permainan ini
body: >-
@ -1288,8 +1295,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -447,7 +447,7 @@ ingame:
clearItems: Elimina oggetti
share: Condividi
report: Segnala
clearBuildings: Clear Buildings
clearBuildings: Cancella edifici
resetPuzzle: Reset Puzzle
puzzleEditorControls:
title: Creazione puzzle
@ -477,6 +477,7 @@ ingame:
in futuro
continueBtn: Continua a giocare
menuBtn: Menù
nextPuzzle: Puzzle successivo
puzzleMetadata:
author: Autore
shortKey: Codice
@ -745,7 +746,7 @@ storyRewards:
reward_rotater_ccw:
title: Rotazione antioraria
desc: Hai sbloccato una variante del <strong>ruotatore</strong>! Consente di
ruotare in senso antiorario! Per costruirla, seleziona la ruotatrice
ruotare in senso antiorario! Per costruirla, seleziona il ruotatore
e <strong>premi 'T' per cambiare variante</strong>!
reward_miner_chainable:
title: Estrattore a catena
@ -823,7 +824,7 @@ storyRewards:
la portata di un nastro.<br><br>E aspetta di sbloccare i cavi,
allora sì che sarà molto utile!
reward_rotater_180:
title: Ruotatrice (180 gradi)
title: Ruotatore (180 gradi)
desc: Hai appena sbloccato il <strong>ruotatore</strong> a 180 gradi! Consente
di ruotare una forma di 180 gradi (Sorpresa! :D)
reward_display:
@ -833,7 +834,7 @@ storyRewards:
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
title: Segnale costante
desc: Hai sbloccato l'edificio <strong>segnale costante</strong> sul livello
elettrico! È utile collegarlo ai <strong>filtri di oggetti</strong>
per esempio.<br><br> Il segnale costante può emettere una
@ -859,7 +860,7 @@ storyRewards:
normalmente. <br><br> Qualsiasi cosa tu scelga, ricordati di
divertirti!
reward_wires_painter_and_levers:
title: Cavi e Verniciatrice quadrupla
title: Cavi e Verniciatore quadruplo
desc: "Hai appena sbloccato il <strong>Livello Elettrico</strong>: è un livello
separato dal livelo normale e introduce molte altre meccaniche di
gioco!<br><br> Per il momento ti ho sbloccato il
@ -1048,7 +1049,12 @@ settings:
title: Grandezza delle Risorse sulla Mappa
description: Controlla la grandezza delle forme visualizzate sulla mappa (quando
si fa lo zoom indietro).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Determina se mostrare sempre la forma in uscita da un edificio quando si passa sopra di esso col cursore,
invece di dover premere 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Comandi
hint: "Suggerimento: Usa spesso CTRL, MAIUSC e ALT! Abilitano opzioni di
@ -1065,7 +1071,7 @@ keybindings:
mappings:
confirm: Conferma
back: Indietro
mapMoveUp: Spostati sù
mapMoveUp: Spostati su
mapMoveRight: Spostati a destra
mapMoveDown: Spostati giù
mapMoveLeft: Spostati a sinistra
@ -1130,6 +1136,7 @@ keybindings:
goal_acceptor: Accettore di obiettivi
block: Blocco
massSelectClear: Sgombra nastri
showShapeTooltip: Mostra forma di uscita di un edificio
about:
title: Riguardo questo gioco
body: >-
@ -1272,8 +1279,23 @@ puzzleMenu:
easy: Facile
medium: Medio
hard: Difficile
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
unknown: Non classificato
dlcHint: Hai già acquistato il DLC? Assicurati che sia attivo facendo clic destro
su shapez.io nella tua libreria e selezionando Proprietà > DLC.
search:
action: Cerca
placeholder: Inserisci il nome di un puzzle o di un autore
includeCompleted: Include Completed
difficulties:
any: Qualsiasi difficoltà
easy: Facile
medium: Medio
hard: Difficile
durations:
any: Qualsiasi durata
short: Breve (< 2 minuti)
medium: Normale
long: Lunga (> 10 minuti)
backendErrors:
ratelimit: Stai facendo troppe azioni velocemente. Per favore attendi un attimo.
invalid-api-key: Comunicazione con il backend fallita, per favore prova ad

View File

@ -422,6 +422,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -868,6 +869,11 @@ settings:
mapResourcesScale:
title: 資源アイコンのサイズ
description: ズームアウトしたときの図形のサイズを調節します。
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
tickrateHz: <amount> Hz
keybindings:
title: キー設定
hint: "Tip: CTRL, SHIFT, ALTを活用してください。建造物配置の際の追加機能がそれぞれ割り当てられています。"
@ -948,6 +954,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: このゲームについて
body: >-
@ -1070,8 +1077,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -58,8 +58,7 @@ mainMenu:
openSourceHint: 이 게임은 오픈 소스입니다!
discordLink: 공식 디스코드 서버
helpTranslate: 번역을 도와주세요!
browserWarning:
이 게임은 현재 브라우저에서 느리게 작동하는 것으로 알려져 있습니다! 더 좋은 성능을 위해 정식 버전을 구매하거나
browserWarning: 이 게임은 현재 브라우저에서 느리게 작동하는 것으로 알려져 있습니다! 더 좋은 성능을 위해 정식 버전을 구매하거나
Google Chrome 브라우저를 다운로드하세요.
savegameLevel: 레벨 <x>
savegameLevelUnknown: 미확인 레벨
@ -128,8 +127,7 @@ dialogs:
desc: 지난번 플레이 이후 변경 사항은 다음과 같습니다.
upgradesIntroduction:
title: 업그레이드 하기
desc:
<strong>기존의 공장을 허물지 마세요!</strong> 여러분이 그동안 만들어 수집한 모든 도형은 업그레이드에 사용됩니다.
desc: <strong>기존의 공장을 허물지 마세요!</strong> 여러분이 그동안 만들어 수집한 모든 도형은 업그레이드에 사용됩니다.
업그레이드 버튼은 화면의 오른쪽 위에 있습니다.
massDeleteConfirm:
title: 삭제 확인
@ -142,8 +140,7 @@ dialogs:
desc: 12 레벨부터 청사진 기능이 해금됩니다!
keybindingsIntroduction:
title: 유용한 조작법
desc:
"이 게임에는 거대한 공장을 수월하게 세우기 위한 많은 조작법이 있습니다. 아래는 그 대표적인 것이며, 자세한 조작법은
desc: "이 게임에는 거대한 공장을 수월하게 세우기 위한 많은 조작법이 있습니다. 아래는 그 대표적인 것이며, 자세한 조작법은
<strong>조작법 설정</strong>을 참고해주세요!<br><br> <code
class='keybinding'>CTRL</code> + 드래그: 영역을 선택합니다.<br> <code
class='keybinding'>SHIFT</code>: 누르는 동안 같은 건물을 여러개 배치할 수 있습니다.<br>
@ -157,8 +154,7 @@ dialogs:
desc: 체험판 버전에서는 마커를 2개 까지만 배치할 수 있습니다. 정식 버전을 구입하면 마커를 무제한으로 배치할 수 있습니다!
exportScreenshotWarning:
title: 스크린샷 내보내기
desc:
당신의 공장을 스크린샷으로 내보내려 합니다. 매우 거대한 크기의 공장이라면 그 처리 시간이 상당히 오래 걸릴 것이며, 최악의 경우
desc: 당신의 공장을 스크린샷으로 내보내려 합니다. 매우 거대한 크기의 공장이라면 그 처리 시간이 상당히 오래 걸릴 것이며, 최악의 경우
게임이 중단될 수 있습니다!
massCutInsufficientConfirm:
title: 자르기 확인
@ -184,8 +180,7 @@ dialogs:
submitPuzzle:
title: 퍼즐 보내기
descName: "퍼즐에 이름을 지어 주세요:"
descIcon:
"퍼즐의 아이콘으로 보여지게 될 짧은 단어를 지정해 주세요. (<link>이곳</link>에서 생성하시거나, 아래 랜덤한 모양
descIcon: "퍼즐의 아이콘으로 보여지게 될 짧은 단어를 지정해 주세요. (<link>이곳</link>에서 생성하시거나, 아래 랜덤한 모양
중 하나를 선택하세요):"
placeholderName: 퍼즐 제목
puzzleResizeBadBuildings:
@ -211,8 +206,7 @@ dialogs:
desc: 오프라인 모드임으로 퍼즐을 저장하거나 업로드할 수 없습니다. 그래도 계속하시겠습니까?
puzzlePlayRegularRecommendation:
title: 권장 사항
desc:
퍼즐 DLC 플레이시 소개되지 않은 요소를 접하시게 될 수 있으므로, 적어도 일반 게임을 12레벨까지 플레이하시는것을
desc: 퍼즐 DLC 플레이시 소개되지 않은 요소를 접하시게 될 수 있으므로, 적어도 일반 게임을 12레벨까지 플레이하시는것을
<strong>강력히</strong> 권장드립니다. 그래도 계속하시겠습니까?
puzzleShare:
title: 짧은 키 복사됨
@ -256,7 +250,7 @@ ingame:
clearSelection: 지우기
pipette: 피펫
switchLayers: 레이어 전환
clearBelts: Clear belts
clearBelts: 벨트 청소하기
buildingPlacement:
cycleBuildingVariants: <key> 키를 눌러 변형 전환
hotkeyLabel: "단축키: <key>"
@ -312,31 +306,25 @@ ingame:
waypoints:
waypoints: 마커
hub: 허브
description:
마커를 좌클릭하여 그곳으로 이동하고, 우클릭으로 삭제할 수 있습니다.<br><br>마커를 배치하기 위해
description: 마커를 좌클릭하여 그곳으로 이동하고, 우클릭으로 삭제할 수 있습니다.<br><br>마커를 배치하기 위해
<keybinding> 키로 지금 있는 위치에, 또는 <strong>우클릭</strong>하여 원하는 위치에 배치할 수
있습니다.
creationSuccessNotification: 마커가 성공적으로 생성되었습니다.
interactiveTutorial:
title: 튜토리얼
hints:
1_1_extractor:
<strong>원형 도형</strong>을 추출하기 위해 그 위에 <strong>추출기</strong>를 선택한 뒤
1_1_extractor: <strong>원형 도형</strong>을 추출하기 위해 그 위에 <strong>추출기</strong>를 선택한 뒤
배치하여 추출하세요!
1_2_conveyor:
"이제 <strong>컨베이어 벨트</strong>를 추출기와 허브를 서로 연결하세요!<br><br> 팁: 벨트를
1_2_conveyor: "이제 <strong>컨베이어 벨트</strong>를 추출기와 허브를 서로 연결하세요!<br><br> 팁: 벨트를
마우스로 <strong>클릭한 뒤 드래그</strong>하세요!"
1_3_expand:
"이 게임은 방치형 게임이 <strong>아닙니다</strong>! 더 많은 추출기와 벨트를 만들어 지정된 목표를 빨리
1_3_expand: "이 게임은 방치형 게임이 <strong>아닙니다</strong>! 더 많은 추출기와 벨트를 만들어 지정된 목표를 빨리
달성하세요.<br><br> 팁: <strong>SHIFT</strong> 키를 누른 상태에서는 빠르게 배치할 수
있고, <strong>R</strong> 키를 눌러 회전할 수 있습니다."
2_1_place_cutter:
"이제 <strong>절단기</strong>를 배치해 원형 도형을 반으로 잘라보세요!<br><br> 참고:
2_1_place_cutter: "이제 <strong>절단기</strong>를 배치해 원형 도형을 반으로 잘라보세요!<br><br> 참고:
절단기는 놓는 방향에 상관없이 항상 <strong>위에서 아래로만</strong> 자릅니다."
2_2_place_trash: 절단기가 <strong>막히거나 멈출 수 있습니다</strong>!<br><br>
<strong>휴지통</strong>을 사용하여 현재 필요없는 쓰레기 도형 (!)을 제거하세요.
2_3_more_cutters:
"잘하셨습니다! 느린 처리 속도를 보완하기 위해 <strong>절단기를 두 개</strong> 이상
2_3_more_cutters: "잘하셨습니다! 느린 처리 속도를 보완하기 위해 <strong>절단기를 두 개</strong> 이상
배치해보세요!<br><br> 추신: <strong>상단 숫자 단축키 (0~9)</strong>를 사용하여 건물을
빠르게 선택할 수 있습니다!"
3_1_rectangles: "이제 사각형 도형을 추출해 볼까요! <strong>추출기 네 개를 배치</strong>하고 허브와
@ -344,12 +332,10 @@ ingame:
누른 채 드래그하세요!"
21_1_place_quad_painter: <strong>4단 색칠기</strong>를 배치하여 <strong>흰색</strong>과
<strong>빨간색</strong>이 칠해진 <strong>원형 도형</strong>을 만들어보세요!
21_2_switch_to_wires:
<strong>E 키</strong>를 눌러 전선 레이어 로 전환하세요!<br><br> 그 후 색칠기의
21_2_switch_to_wires: <strong>E 키</strong>를 눌러 전선 레이어 로 전환하세요!<br><br> 그 후 색칠기의
<strong>네 입력 부분</strong>을 모두 케이블로 연결하세요!
21_3_place_button: 훌륭해요! 이제 <strong>스위치</strong>를 배치하고 전선으로 연결하세요!
21_4_press_button:
"스위치를 눌러서 색칠기에 <strong>참 신호를 보내</strong> 활성화해보세요.<br><br> 추신:
21_4_press_button: "스위치를 눌러서 색칠기에 <strong>참 신호를 보내</strong> 활성화해보세요.<br><br> 추신:
모든 입력을 연결할 필요는 없습니다! 두개만 연결해 보세요."
colors:
red: 빨간색
@ -429,6 +415,7 @@ ingame:
titleRatingDesc: 당신의 평가는 제가 미래에 더 나은 평가를 만들수 있도록 도울 수 있습니다.
continueBtn: 계속 플레이하기
menuBtn: 메뉴
nextPuzzle: Next Puzzle
puzzleMetadata:
author: 제작자
shortKey: 짧은 키
@ -475,13 +462,11 @@ buildings:
cutter:
default:
name: 절단기
description:
도형을 수직으로 잘라 두 가지 도형으로 나눕니다. <strong>한쪽만 사용할 경우라면 다른 부분을 파괴하지 않을 경우
description: 도형을 수직으로 잘라 두 가지 도형으로 나눕니다. <strong>한쪽만 사용할 경우라면 다른 부분을 파괴하지 않을 경우
절단기가 막혀 멈추게 됩니다!</strong>
quad:
name: 4단 절단기
description:
도형을 즉시 네 개로 자릅니다. <strong>한쪽만 사용할 경우라면 다른 부분을 파괴하지 않을 경우 절단기가 막혀
description: 도형을 즉시 네 개로 자릅니다. <strong>한쪽만 사용할 경우라면 다른 부분을 파괴하지 않을 경우 절단기가 막혀
멈추게 됩니다!</strong>
rotater:
default:
@ -496,8 +481,7 @@ buildings:
stacker:
default:
name: 결합기
description:
도형을 서로 결합하고 쌓습니다. 서로 결합할 수 있다면 두 도형을 붙여 하나로 만들고, 그렇지 않으면 오른쪽 도형이 왼쪽
description: 도형을 서로 결합하고 쌓습니다. 서로 결합할 수 있다면 두 도형을 붙여 하나로 만들고, 그렇지 않으면 오른쪽 도형이 왼쪽
도형 위에 쌓이게 됩니다.
mixer:
default:
@ -512,8 +496,7 @@ buildings:
description: 색소를 이용해 도형을 색칠합니다. 위쪽에서 받는 색소로 왼쪽에서 받는 도형 전체를 색칠합니다.
quad:
name: 4단 색칠기
description:
도형의 각 사분면에 개별적으로 색상을 칠할 수 있습니다. 전선 레이어를 통해 <strong>참 신호</strong>가
description: 도형의 각 사분면에 개별적으로 색상을 칠할 수 있습니다. 전선 레이어를 통해 <strong>참 신호</strong>가
있는 슬롯만 칠해집니다!
mirrored:
name: 색칠기
@ -560,8 +543,7 @@ buildings:
lever:
default:
name: 스위치
description:
전선 레이어에서 불 값 (1 또는 0)을 방출하도록 전환할 수 있으며, 그 후 아이템 선별같은 구성 요소를 제어하는 데
description: 전선 레이어에서 불 값 (1 또는 0)을 방출하도록 전환할 수 있으며, 그 후 아이템 선별같은 구성 요소를 제어하는 데
사용될 수 있습니다.
logic_gate:
default:
@ -572,8 +554,7 @@ buildings:
description: 입력이 거짓일 경우 불 값 "1"을 내보냅니다 (참은 도형, 색상, 불 값 "1"을 의미합니다).
xor:
name: XOR 회로
description:
입력 중 하나만 참이고 둘 다 같지 않을 경우 불 값 "1"을 내보냅니다 (참은 도형, 색상, 불 값 "1"을
description: 입력 중 하나만 참이고 둘 다 같지 않을 경우 불 값 "1"을 내보냅니다 (참은 도형, 색상, 불 값 "1"을
의미합니다).
or:
name: OR 회로
@ -640,8 +621,7 @@ buildings:
storyRewards:
reward_cutter_and_trash:
title: 절단기
desc:
<strong>절단기</strong>가 잠금 해제되었습니다! 절단기는 들어오는 도형이 어떤 모양을 하고 있던 수직으로 잘라
desc: <strong>절단기</strong>가 잠금 해제되었습니다! 절단기는 들어오는 도형이 어떤 모양을 하고 있던 수직으로 잘라
<strong>반으로 나눕니다</strong>!<br><br> 쓰지 않는 도형은 쓰레기로 처리하세요, 그렇지 않으면
<strong>작동을 멈출 것입니다</strong>! 이러한 목적을 위해 <strong>휴지통</strong>도 함께
지급되었습니다. 휴지통에 들어간 것은 모두 파괴됩니다!
@ -650,8 +630,7 @@ storyRewards:
desc: <strong>회전기</strong>가 잠금 해제되었습니다! 회전기는 들어오는 도형을 시계 방향으로 90도 회전시켜줍니다.
reward_painter:
title: 색칠기
desc:
"<strong>색칠기</strong>가 잠금 해제되었습니다! 도형과 마찬가지로 색소를 추출하고 색칠기에 넣거 도형과 결합하여 색칠된
desc: "<strong>색칠기</strong>가 잠금 해제되었습니다! 도형과 마찬가지로 색소를 추출하고 색칠기에 넣거 도형과 결합하여 색칠된
도형을 만들도록 하세요!<br><br>추신: 만약 당신이 색맹이라면, 설정에서 <strong>색맹 모드</strong>를
활성화하세요!"
reward_mixer:
@ -660,28 +639,24 @@ storyRewards:
색소</strong>를 얻을 수 있습니다!
reward_stacker:
title: 결합기
desc:
<strong>결합기</strong>가 잠금 해제되었습니다! 이제 결합기를 통해 여러 도형을 붙이고 결합할 수 있습니다! 들어오는 두
desc: <strong>결합기</strong>가 잠금 해제되었습니다! 이제 결합기를 통해 여러 도형을 붙이고 결합할 수 있습니다! 들어오는 두
도형의 모양이 서로 나란히 붙일 수 있다면, 하나의 도형으로 <strong>결합</strong>됩니다. 만약 서로
겹쳐진다면, 오른쪽 도형이 왼쪽 도형의 <strong>위에 쌓이게</strong> 됩니다!
reward_splitter:
title: 압축형 분배기
desc:
<strong>밸런서</strong>의 새로운 형태인 <strong>분배기</strong>가 잠금 해제되었습니다! 이제 벨트 한 줄을
desc: <strong>밸런서</strong>의 새로운 형태인 <strong>분배기</strong>가 잠금 해제되었습니다! 이제 벨트 한 줄을
즉시 두 줄로 분배합니다!
reward_tunnel:
title: 터널
desc: <strong>터널</strong>이 잠금 해제되었습니다! 이제 벨트와 건물 아래로 공간을 만들어내 옮길 수 있습니다!
reward_rotater_ccw:
title: 반시계 방향 회전기
desc:
<strong>반시계 방향 회전기</strong>가 잠금 해제되었습니다! 반시계 방향 회전기는 회전기의 다른 형태로, 이름처럼
desc: <strong>반시계 방향 회전기</strong>가 잠금 해제되었습니다! 반시계 방향 회전기는 회전기의 다른 형태로, 이름처럼
들어오는 도형을 반시계 방향으로 90도만큼 회전시킵니다! 제작하려면 회전기를 선택한 후 <strong>'T' 키를 눌러
다른 형태로 전환</strong>하세요!
reward_miner_chainable:
title: 연쇄 추출기
desc:
"<strong>연쇄 추출기</strong>가 잠금 해제되었습니다! 자원을 보다 더욱 효율적으로 추출할 수 있도록 <strong>앞에
desc: "<strong>연쇄 추출기</strong>가 잠금 해제되었습니다! 자원을 보다 더욱 효율적으로 추출할 수 있도록 <strong>앞에
있는 추출기로 자원을 보낼 수 있습니다</strong>!<br><br> 추신: 이제 툴바에 있는 기존 추출기는 연쇄
추출기로 대체되었습니다!"
reward_underground_belt_tier_2:
@ -690,18 +665,15 @@ storyRewards:
거리</strong>를 운송할 수 있고 기존 터널과 겹쳐지지 않고도 자원을 보낼 수 있습니다!
reward_cutter_quad:
title: 4단 절단기
desc:
새로운 종류의 <strong>절단기</strong>가 잠금 해제되었습니다! 4단 절단기는 도형을 두 조각이 아닌 <strong>네
desc: 새로운 종류의 <strong>절단기</strong>가 잠금 해제되었습니다! 4단 절단기는 도형을 두 조각이 아닌 <strong>네
조각</strong>으로 자를 수 있습니다!
reward_painter_double:
title: 2단 색칠기
desc:
새로운 종류의 <strong>절단기</strong>가 잠금 해제되었습니다! 일반적인 색칠기와 거의 동일하지만, 하나의 색소를 사용하여
desc: 새로운 종류의 <strong>절단기</strong>가 잠금 해제되었습니다! 일반적인 색칠기와 거의 동일하지만, 하나의 색소를 사용하여
<strong>동시에 두 개의 도형을 색칠</strong>할 수 있습니다!
reward_storage:
title: 저장고
desc:
<strong>저장고</strong>가 잠금 해제되었습니다! 저장고는 최대 용량까지 도형을 저장할 수 있습니다!<br><br> 왼쪽
desc: <strong>저장고</strong>가 잠금 해제되었습니다! 저장고는 최대 용량까지 도형을 저장할 수 있습니다!<br><br> 왼쪽
출력이 우선되므로 <strong>오버플로 회로</strong>로도 활용될 수 있습니다!
reward_freeplay:
title: 자유플레이
@ -711,38 +683,32 @@ storyRewards:
레이어를 통해 내보내므로 이를 분석하는 구조를 기반으로 하여 공장을 자동으로 구성하기만 하면 됩니다.
reward_blueprints:
title: 청사진
desc:
이제 공장의 일부를 <strong>복사하고 붙여넣는 기능</strong>을 사용할 수 있습니다! 영역을 선택 (CTRL 키를 누른 채
desc: 이제 공장의 일부를 <strong>복사하고 붙여넣는 기능</strong>을 사용할 수 있습니다! 영역을 선택 (CTRL 키를 누른 채
마우스로 드래그)한 뒤 'C' 키를 눌러 복사할 수 있습니다.<br><br>하지만 <strong>공짜는
아닙니다</strong>, <strong>청사진 모양 도형</strong>을 허브에 저장하고 그것을 일부 사용해 붙여넣기
기능을 사용할 수 있습니다! (방금 당신이 만든 것입니다.)
no_reward:
title: 다음 레벨
desc:
"이번 레벨의 보상은 없네요. 대신 다음 레벨에서 줄겁니다!<br><br> 추신: 기존 공장을 파괴하지는 마세요. 후에
desc: "이번 레벨의 보상은 없네요. 대신 다음 레벨에서 줄겁니다!<br><br> 추신: 기존 공장을 파괴하지는 마세요. 후에
<strong>업그레이드 잠금 해제</strong>되면 <strong>기존의 모든</strong> 도형이 필요합니다!"
no_reward_freeplay:
title: 다음 레벨
desc: 축하드립니다!
reward_balancer:
title: 밸런서
desc:
<strong>밸런서</strong>가 잠금 해제되었습니다! 다목적 밸런서를 통해 여러 벨트의 아이템을 서로 <strong>다른
desc: <strong>밸런서</strong>가 잠금 해제되었습니다! 다목적 밸런서를 통해 여러 벨트의 아이템을 서로 <strong>다른
벨트로 분할하거나 합침</strong>으로써 더욱 거대한 공장을 만들 수 있습니다!
reward_merger:
title: 압축형 병합기
desc:
<strong>밸런서</strong>의 새로운 형태인 <strong>병합기</strong>가 잠금 해제되었습니다! 이제 벨트 두 줄을
desc: <strong>밸런서</strong>의 새로운 형태인 <strong>병합기</strong>가 잠금 해제되었습니다! 이제 벨트 두 줄을
즉시 한 줄로 병합합니다!
reward_belt_reader:
title: 벨트 판독기
desc:
<strong>벨트 판독기</strong>가 잠금 해제되었습니다! 이제 벨트의 처리량을 확인할 수 있습니다.<br><br>그리고,
desc: <strong>벨트 판독기</strong>가 잠금 해제되었습니다! 이제 벨트의 처리량을 확인할 수 있습니다.<br><br>그리고,
전선이 잠금 해제될 때 까지 기다리신다면 정말 유용하게 사용할 수 있을 겁니다!
reward_rotater_180:
title: 180도 회전기
desc:
<strong>180도 회전기</strong>가 잠금 해제되었습니다! 이제 도형을 바로 180도로 회전시킬 수 있습니다. (짜잔!
desc: <strong>180도 회전기</strong>가 잠금 해제되었습니다! 이제 도형을 바로 180도로 회전시킬 수 있습니다. (짜잔!
:D)
reward_display:
title: 디스플레이
@ -750,37 +716,32 @@ storyRewards:
있습니다.<br><br> 추신: 벨트 판독기와 저장고가 마지막으로 읽은 아이템을 출력했나요? 디스플레이로 한번 봐보세요!"
reward_constant_signal:
title: 일정 신호기
desc:
전선 레이어에서 구축할 수 있는 <strong>일정 신호기</strong>가 잠금 해제되었습니다! 간단한 예시로,
desc: 전선 레이어에서 구축할 수 있는 <strong>일정 신호기</strong>가 잠금 해제되었습니다! 간단한 예시로,
<strong>아이템 선별</strong>에 연결하여 사용하는 데 유용합니다.<br><br> 일정 신호기는
<strong>도형</strong>, <strong>색상</strong>, 또는 <strong>불 값</strong> (1
또는 0)을 출력할 수 있습니다.
reward_logic_gates:
title: 논리 회로
desc:
<strong>논리 회로</strong>가 잠금 해제되었습니다! 굳이 흥분할 필요는 없지만, 진짜 멋진 기술입니다!<br><br>
desc: <strong>논리 회로</strong>가 잠금 해제되었습니다! 굳이 흥분할 필요는 없지만, 진짜 멋진 기술입니다!<br><br>
논리 회로를 통해 이제 AND, OR, XOR, NOT 논리 연산을 할 수 있습니다.<br><br> 보너스로,
<strong>트랜지스터</strong>도 지급되었습니다!
reward_virtual_processing:
title: 가상 처리
desc:
<strong>도형의 처리를 시뮬레이션</strong>할 수 있는 다양한 새로운 건물이 잠금 해제되었습니다!<br><br> 이제 전선
desc: <strong>도형의 처리를 시뮬레이션</strong>할 수 있는 다양한 새로운 건물이 잠금 해제되었습니다!<br><br> 이제 전선
레이어에서 도형에 대한 절단기, 회전기, 결합기 등을 가상으로 시뮬레이션할 수 있습니다! 이제 게임 진행에 있어 다음 세
가지의 방법이 존재합니다:<br><br> - <strong>완전 자동화된 기계</strong>를 구축하고 허브에서 요구되는
도형을 제작합니다. (먼저 시도해볼 것을 권합니다!).<br><br> - 전선을 통해 멋진 것들 만듭니다.<br><br>
- 평소처럼 게임을 진행합니다.<br><br> 어떤 방식으로든, 재미있게 게임을 플레이해주시길 바랍니다!
reward_wires_painter_and_levers:
title: 전선과 4단 색칠기
desc:
" 방금 <strong>전선 레이어</strong>를 활성화하셨습니다: 이것은 일반 레이어 위에 존재하는 별개의 레이어로 수많은
desc: " 방금 <strong>전선 레이어</strong>를 활성화하셨습니다: 이것은 일반 레이어 위에 존재하는 별개의 레이어로 수많은
새로운 요소를 사용할 수 있습니다!<br><br> <strong>4단 색칠기</strong>를 활성화해 드리겠습니다 -
전선 레이어에서 색을 칠할 부분에 연결해 보세요!<br><br> 전선 레이어로 전환하시려면
<strong>E</strong>키를 눌러주세요.<br><br> 추신: <strong>힌트를 활성화</strong>해서
전선 튜토리얼을 활성화해 보세요!"
reward_filter:
title: 아이템 선별기
desc:
<strong>아이템 선별기</strong>가 잠금 해제되었습니다! 전선 레이어의 신호와 일치하는지에 대한 여부로 아이템을 위쪽
desc: <strong>아이템 선별기</strong>가 잠금 해제되었습니다! 전선 레이어의 신호와 일치하는지에 대한 여부로 아이템을 위쪽
출력이나 오른쪽 출력으로 보냅니다.<br><br> 불 값 (1 또는 0)을 전달하여 완전히 활성화과 비활성화를 전환할 수
있습니다.
reward_demo_end:
@ -801,8 +762,7 @@ settings:
labels:
uiScale:
title: UI 크기
description:
사용자 인터페이스의 크기를 변경합니다. 인터페이스는 당신의 해상도에 따라 확장되는데 이 설정은 그 확장의 정도를
description: 사용자 인터페이스의 크기를 변경합니다. 인터페이스는 당신의 해상도에 따라 확장되는데 이 설정은 그 확장의 정도를
제어합니다.
scales:
super_small: 매우 작게
@ -849,18 +809,15 @@ settings:
light: 라이트
refreshRate:
title: 틱 빈도
description:
이것은 초당 발생하는 게임 틱 수를 결정합니다. 일반적으로 틱 속도가 높을수록 정밀도는 향상되나 성능은 낮아집니다. 낮은
description: 이것은 초당 발생하는 게임 틱 수를 결정합니다. 일반적으로 틱 속도가 높을수록 정밀도는 향상되나 성능은 낮아집니다. 낮은
틱 빈도에서는 처리량이 정확하지 않을 수 있습니다.
alwaysMultiplace:
title: 다수 배치 항시 켜기
description:
활성화할 경우 모든 건물은 배치한 후 취소할 때 까지 커서에 선택된 상태를 유지합니다. 이 기능은 SHIFT 키를 계속
description: 활성화할 경우 모든 건물은 배치한 후 취소할 때 까지 커서에 선택된 상태를 유지합니다. 이 기능은 SHIFT 키를 계속
누르는 것과 같습니다.
offerHints:
title: 힌트와 튜토리얼
description:
게임 플레이하는 동안 힌트와 튜토리얼을 보여줄 지를 결정합니다. 또한 게임에 더 쉽게 빠져들 수 있도록 특정 레벨까지
description: 게임 플레이하는 동안 힌트와 튜토리얼을 보여줄 지를 결정합니다. 또한 게임에 더 쉽게 빠져들 수 있도록 특정 레벨까지
특정한 UI 요소를 숨깁니다.
enableTunnelSmartplace:
title: 지능적인 터널 배치
@ -889,8 +846,7 @@ settings:
description: 색맹 사용자를 위해 게임을 플레이하는 데 도움을 주는 다양한 도구를 활성화합니다.
rotationByBuilding:
title: 건물 유형에 따른 방향
description:
각 건물 유형마다 개별적으로 마지막으로 설정했던 방향을 기억하도록 합니다. 다른 건물 변형을 자주 전환하는 경우 이
description: 각 건물 유형마다 개별적으로 마지막으로 설정했던 방향을 기억하도록 합니다. 다른 건물 변형을 자주 전환하는 경우 이
방법이 더욱 편할 수 있습니다.
soundVolume:
title: 효과음 볼륨
@ -906,8 +862,7 @@ settings:
description: 성능 향상을 위해 타일 그리드를 비활성화할 수 있습니다. 이 역시 게임을 더욱 깨끗하게 보여줍니다!
clearCursorOnDeleteWhilePlacing:
title: 우클릭 시 커서 지우기
description:
기본적으로 활성화되어 있으며, 배치할 건물을 선택한 상태에서 마우스 우클릭 시 커서를 지웁니다. 비활성화할 경우, 건물을
description: 기본적으로 활성화되어 있으며, 배치할 건물을 선택한 상태에서 마우스 우클릭 시 커서를 지웁니다. 비활성화할 경우, 건물을
커서에 선택한 채로 우클릭하면 바로 건물을 삭제할 수 있습니다.
lowQualityTextures:
title: 저품질 텍스처 (못생김)
@ -920,8 +875,7 @@ settings:
description: 기본적으로 활성화되어 있으며, 자원 패치에서 피펫 기능을 사용 시 즉시 추출기를 선택합니다.
simplifiedBelts:
title: 벨트 단순화 (못생김)
description:
성능 향상을 위해 벨트를 가리킬 때를 제외한 모든 상황에서 벨트 아이템을 렌더링하지 않습니다. 이 기능을 사용할 정도로
description: 성능 향상을 위해 벨트를 가리킬 때를 제외한 모든 상황에서 벨트 아이템을 렌더링하지 않습니다. 이 기능을 사용할 정도로
심각한 성능 문제가 일어나지 않는 한, 이 설정을 사용할 필요는 없습니다.
enableMousePan:
title: 화면 가장자리 패닝
@ -932,7 +886,12 @@ settings:
mapResourcesScale:
title: 지도 자원 크기
description: 지도를 축소할 때 나타나는 도형의 크기를 제어합니다.
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: 조작법
hint: "팁: CTRL, SHIFT, ALT를 적절히 사용하세요! 건물을 배치할 때 유용합니다."
@ -1013,6 +972,7 @@ keybindings:
goal_acceptor: 목표 수집기
block: 블록
massSelectClear: 벨트 초기화
showShapeTooltip: Show shape output tooltip
about:
title: 게임 정보
body: >-
@ -1131,8 +1091,23 @@ puzzleMenu:
easy: 쉬움
medium: 중간
hard: 어려움
dlcHint: DLC를 이미 구입하셨나요? 라이브러리에서 shapez.io를 오른쪽 클릭한 다음
속성… > DLC 메뉴를 선택해서 활성화되었는지 확인해주세요.
unknown: Unrated
dlcHint: DLC를 이미 구입하셨나요? 라이브러리에서 shapez.io를 오른쪽 클릭한 다음 속성… > DLC 메뉴를 선택해서
활성화되었는지 확인해주세요.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: 너무 빠른 시간 내 작업을 반복하고 있습니다. 조금만 기다려 주세요.
invalid-api-key: 백엔드 서버와 통신할 수 없습니다. 게임을 업데이트하거나 재시작해 주세요 (잘못된 API 키).

View File

@ -457,6 +457,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1003,7 +1004,12 @@ settings:
title: Map Resources Size
description: Controls the size of the shapes on the map overview (when zooming
out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Keybindings
hint: "Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different
@ -1085,6 +1091,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: About this Game
body: >-
@ -1212,8 +1219,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -14,7 +14,7 @@ steamPage:
Ondanks het feit dat je in het begin alleen vormen maakt, komt er een punt waarop je ze gaat kleuren. Deze kleuren kun 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 om over te schakelen zonder voortgang te verliezen.
what_others_say: What people say about shapez.io
what_others_say: Wat anderen vinden van shapez.io
nothernlion_comment: This game is great - I'm having a wonderful time playing,
and time has flown by.
notch_comment: Oh crap. I really should sleep, but I think I just figured out
@ -475,6 +475,7 @@ ingame:
te geven
continueBtn: Blijf Spelen
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Auteur
shortKey: Vorm Sleutel
@ -1033,7 +1034,12 @@ settings:
title: Kaartbronnen schaal
description: Controleert de grootte van de vormen op het map overzicht (wanneer
je uitzoomt).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Sneltoetsen
hint: "Tip: Maak gebruik van CTRL, SHIFT en ALT! Hiermee kun je dingen anders en
@ -1115,6 +1121,7 @@ keybindings:
goal_acceptor: Ontvanger
block: Blokkade
massSelectClear: Lopende banden leeg maken
showShapeTooltip: Show shape output tooltip
about:
title: Over dit spel
body: >-
@ -1166,14 +1173,12 @@ tips:
wordt de planner geactiveerd, zodat je gemakkelijk lange rijen kunt
plaatsen.
- Knippers knippen altijd verticaal, ongeacht hun oriëntatie.
- Meng alle drie de kleuren om wit te krijgen.
- De opslagbuffer geeft prioriteit aan de eerste uitvoer.
- Investeer tijd om herhaalbare ontwerpen te maken - het is het waard!
- Door <b>SHIFT</b> ingedrukt te houden, kunnen meerdere gebouwen worden
geplaatst.
- Invest time to build repeatable designs - it's worth it!
- Je kunt <b>ALT</b> ingedrukt houden om de richting van de geplaatste
lopende banden om te keren.
- Efficiëntie is de sleutel!
- You can hold <b>ALT</b> to invert the direction of placed belts.
- Vormontginningen die verder van de HUB verwijderd zijn, zijn complexer.
- Machines hebben een beperkte snelheid, verdeel ze voor maximale
efficiëntie.
@ -1196,8 +1201,8 @@ tips:
mannen.
- Maak een aparte blueprint fabriek. Ze zijn belangrijk voor modules.
- Bekijk de kleurenmixer eens wat beter, en je vragen worden beantwoord.
- Gebruik <b>CTRL</b> + klik om een gebied te selecteren.
- Te dicht bij de HUB bouwen kan latere projecten in de weg staan.
- Have a closer look at the color mixer, and your questions will be answered.
- Use <b>CTRL</b> + Click to select an area.
- Met het speldpictogram naast elke vorm in de upgradelijst zet deze vast op
het scherm.
- Meng alle primaire kleuren door elkaar om wit te maken!
@ -1216,6 +1221,7 @@ tips:
- Druk twee keer op F4 om de tegel van je muis en camera weer te geven.
- Je kan aan de linkerkant op een vastgezette vorm klikken om deze los te
maken.
- You can click a pinned shape on the left side to unpin it.
puzzleMenu:
play: Spelen
edit: Bewerken
@ -1261,6 +1267,21 @@ puzzleMenu:
easy: Makkelijk
medium: Medium
hard: Moeilijk
unknown: Unrated
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: Je voert je handelingen te vaak uit. Wacht alstublieft even.
invalid-api-key: Kan niet communiceren met de servers, probeer alstublieft het

View File

@ -464,6 +464,7 @@ ingame:
fremtiden
continueBtn: Fortsett å spill
menuBtn: Meny
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Laget av
shortKey: Kort Kode
@ -1022,7 +1023,12 @@ settings:
title: Kart Ressursser Størrelse
description: Kontrollerer størrelsen på former på kartoversikten (når zoomet
ut).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Hurtigtaster
hint: "Tips: Husk å bruke CTRL, SHIFT and ALT! De gir deg flere
@ -1104,6 +1110,7 @@ keybindings:
goal_acceptor: Mål Mottaker
block: Blokker
massSelectClear: Tøm Belter
showShapeTooltip: Show shape output tooltip
about:
title: Om dette spillet
body: >-
@ -1236,8 +1243,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: Du gjør en handling for ofte. Vennligst vent litt.
invalid-api-key: Kunne ikke kommunisere med kjernen, vennligst prøv å

View File

@ -465,6 +465,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1029,7 +1030,12 @@ settings:
title: Rozmiar mapy zasobów
description: Steruje rozmiarem kształtów w przeglądzie mapy (podczas
pomniejszenia).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Klawiszologia
hint: "Wskazówka: Upewnij się, że wykorzystujesz CTRL, SHIFT i ALT! Pozwalają na
@ -1111,6 +1117,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: O Grze
body: 'Ta gra jest open-source. Rozwijana jest przez <a
@ -1251,8 +1258,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -466,6 +466,7 @@ ingame:
titleRatingDesc: Sua avaliação me ajuda a te fazer sugestões melhores no futuro!
continueBtn: Continuar jogando
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Autor
shortKey: Código
@ -1038,7 +1039,12 @@ settings:
title: Tamanho do Mapa de Recursos
description: Controla o tamanho das formas no mapa de panorama (quando afasta o
zoom).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Controles
hint: "Dica: Certifique-se de usar CTRL, SHIFT e ALT! Eles permitem diferentes
@ -1120,6 +1126,7 @@ keybindings:
goal_acceptor: Receptor de Objetivo
block: Bloco
massSelectClear: Limpar esteiras
showShapeTooltip: Show shape output tooltip
about:
title: Sobre o jogo
body: >-
@ -1257,8 +1264,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: Você está fazendo coisas muito rapidamente. Por favor espere um pouco.
invalid-api-key: Falha ao comunicar com o backend, por favor tente

View File

@ -476,6 +476,7 @@ ingame:
titleRatingDesc: A tua avaliação ajudar-me-á a fazer melhores sugestões no futuro
continueBtn: Continua a Jogar
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Autor
shortKey: Pequeno Código
@ -1047,7 +1048,12 @@ settings:
title: Tamanho de Recursos no Mapa
description: Controla o tamanho das formas na visão geral do mapa (aplicando
zoom out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Atalhos
hint: "Dica: Utiliza o CTRL, o SHIFT e o ALT! Eles permitem diferentes opções de
@ -1129,6 +1135,7 @@ keybindings:
goal_acceptor: Recetor de Objetivo
block: Bloqueador
massSelectClear: Limpar tapetes rolante
showShapeTooltip: Show shape output tooltip
about:
title: Sobre o Jogo
body: >-
@ -1268,8 +1275,23 @@ puzzleMenu:
easy: Fácil
medium: Médio
hard: Difícil
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: Estás a realizar as tuas ações demasiado rápido. Aguarda um pouco.
invalid-api-key: Falha ao cominucar com o backend, por favor tenta

View File

@ -466,6 +466,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1024,7 +1025,12 @@ settings:
title: Map Resources Size
description: Controls the size of the shapes on the map overview (when zooming
out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Tastele setate
hint: "Indiciu: Asigură-te că foloseșto CTRL, SHIFT și ALT! Ele activează
@ -1106,6 +1112,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: Despre acest joc
body: >-
@ -1233,8 +1240,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

View File

@ -468,6 +468,7 @@ ingame:
titleRatingDesc: Ваша оценка поможет мне в будущем делать вам лучшие предложения
continueBtn: Продолжить игру
menuBtn: Меню
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Автор
shortKey: Короткий ключ
@ -1031,6 +1032,11 @@ settings:
mapResourcesScale:
title: Размер ресурсов на карте
description: Устанавливает размер фигур на карте (когда вид достаточно отдалён).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
tickrateHz: <amount> Hz
keybindings:
title: Настройки управления
hint: "Подсказка: Обязательно используйте CTRL, SHIFT и ALT! Они дают разные
@ -1108,10 +1114,11 @@ keybindings:
placementDisableAutoOrientation: Отключить автоопределение направления
placeMultiple: Оставаться в режиме размещения
placeInverse: Инвертировать автоопределение направления конвейеров
constant_producer: Constant Producer
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
constant_producer: Постоянный генератор
goal_acceptor: Приёмник предметов
block: Блок
massSelectClear: Очистить конвейеры
showShapeTooltip: Show shape output tooltip
about:
title: Об игре
body: >-
@ -1245,11 +1252,26 @@ puzzleMenu:
постоянные производители не доставляют фигуры напрямую приемникам
цели.
difficulties:
easy: Лего
easy: Легко
medium: Средне
hard: Сложно
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
unknown: Unrated
dlcHint: Уже купили DLC? Проверьте, что оно активировано, нажав правый клик на
shapez.io в своей библиотеке, и далее Свойства > Доп. Контент
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: Вы слишком часто выполняете свои действия. Подождите немного.
invalid-api-key: Не удалось связаться с сервером, попробуйте

View File

@ -459,6 +459,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1006,7 +1007,12 @@ settings:
title: Map Resources Size
description: Controls the size of the shapes on the map overview (when zooming
out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Keybindings
hint: "Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different
@ -1088,6 +1094,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: About this Game
body: >-
@ -1215,8 +1222,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

File diff suppressed because it is too large Load Diff

View File

@ -463,6 +463,7 @@ ingame:
titleRatingDesc: Your rating will help me to make you better suggestions in the future
continueBtn: Keep Playing
menuBtn: Menu
nextPuzzle: Next Puzzle
puzzleMetadata:
author: Author
shortKey: Short Key
@ -1014,7 +1015,12 @@ settings:
title: Map Resources Size
description: Controls the size of the shapes on the map overview (when zooming
out).
shapeTooltipAlwaysOn:
title: Shape Tooltip - Show Always
description: Whether to always show the shape tooltip when hovering buildings,
instead of having to hold 'ALT'.
rangeSliderPercentage: <amount> %
tickrateHz: <amount> Hz
keybindings:
title: Snabbtangenter
hint: "Tips: Se till att använda CTRL, SKIFT, och ALT! De låter dig använda
@ -1096,6 +1102,7 @@ keybindings:
goal_acceptor: Goal Acceptor
block: Block
massSelectClear: Clear belts
showShapeTooltip: Show shape output tooltip
about:
title: Om detta spel
body: >-
@ -1223,8 +1230,23 @@ puzzleMenu:
easy: Easy
medium: Medium
hard: Hard
unknown: Unrated
dlcHint: Purchased the DLC already? Make sure it is activated by right clicking
shapez.io in your library, selecting Properties > DLCs.
search:
action: Search
placeholder: Enter a puzzle or author name
includeCompleted: Include Completed
difficulties:
any: Any Difficulty
easy: Easy
medium: Medium
hard: Hard
durations:
any: Any Duration
short: Short (< 2 min)
medium: Normal
long: Long (> 10 min)
backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit.
invalid-api-key: Failed to communicate with the backend, please try to

Some files were not shown because too many files have changed in this diff Show More