8
.editorconfig
Executable file
@ -0,0 +1,8 @@
|
||||
root = true
|
||||
|
||||
[{src, translations}/*]
|
||||
end_of_line = crlf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
charset = utf-8
|
||||
18
.github/workflows/ci.yml
vendored
@ -35,19 +35,23 @@ jobs:
|
||||
cd gulp/
|
||||
yarn
|
||||
cd ..
|
||||
|
||||
- name: Lint
|
||||
run: |
|
||||
yarn lint
|
||||
|
||||
- name: YAML Lint
|
||||
uses: ibiqlik/action-yamllint@v1.0.0
|
||||
with:
|
||||
file_or_dir: translations/*.yaml
|
||||
|
||||
- name: TSLint
|
||||
run: |
|
||||
cd gulp
|
||||
yarn gulp translations.fullBuild
|
||||
cd ..
|
||||
yarn tslint
|
||||
|
||||
yaml-lint:
|
||||
name: yaml-lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
- name: YAML Lint
|
||||
uses: ibiqlik/action-yamllint@v1.0.0
|
||||
with:
|
||||
file_or_dir: translations/*.yaml
|
||||
|
||||
@ -4,3 +4,4 @@ rules:
|
||||
line-length:
|
||||
level: warning
|
||||
max: 200
|
||||
document-start: disable
|
||||
|
||||
31
Dockerfile
Normal file
@ -0,0 +1,31 @@
|
||||
FROM node:12 as base
|
||||
|
||||
EXPOSE 3001 3005
|
||||
|
||||
WORKDIR /shapez.io
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ffmpeg default-jre \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY package.json yarn.lock ./
|
||||
RUN yarn
|
||||
|
||||
COPY gulp ./gulp
|
||||
WORKDIR /shapez.io/gulp
|
||||
RUN yarn
|
||||
|
||||
WORKDIR /shapez.io
|
||||
COPY res ./res
|
||||
COPY src/html ./src/html
|
||||
COPY src/css ./src/css
|
||||
COPY version ./version
|
||||
COPY sync-translations.js ./
|
||||
COPY translations ./translations
|
||||
COPY src/js ./src/js
|
||||
COPY res_raw ./res_raw
|
||||
COPY .git ./.git
|
||||
|
||||
WORKDIR /shapez.io/gulp
|
||||
ENTRYPOINT ["yarn", "gulp"]
|
||||
@ -86,8 +86,16 @@ gulp.task("utils.cleanBuildTempFolder", () => {
|
||||
.src(path.join(__dirname, "..", "src", "js", "built-temp"), { read: false, allowEmpty: true })
|
||||
.pipe($.clean({ force: true }));
|
||||
});
|
||||
gulp.task("utils.cleanImageBuildFolder", () => {
|
||||
return gulp
|
||||
.src(path.join(__dirname, "res_built"), { read: false, allowEmpty: true })
|
||||
.pipe($.clean({ force: true }));
|
||||
});
|
||||
|
||||
gulp.task("utils.cleanup", gulp.series("utils.cleanBuildFolder", "utils.cleanBuildTempFolder"));
|
||||
gulp.task(
|
||||
"utils.cleanup",
|
||||
gulp.series("utils.cleanBuildFolder", "utils.cleanImageBuildFolder", "utils.cleanBuildTempFolder")
|
||||
);
|
||||
|
||||
// Requires no uncomitted files
|
||||
gulp.task("utils.requireCleanWorkingTree", cb => {
|
||||
@ -234,12 +242,13 @@ gulp.task(
|
||||
"build.standalone.dev",
|
||||
gulp.series(
|
||||
"utils.cleanup",
|
||||
"imgres.buildAtlas",
|
||||
"imgres.atlasToJson",
|
||||
"imgres.atlas",
|
||||
"sounds.dev",
|
||||
"imgres.copyImageResources",
|
||||
"imgres.copyNonImageResources",
|
||||
"translations.fullBuild",
|
||||
"js.standalone-dev",
|
||||
"css.dev",
|
||||
"html.standalone-dev"
|
||||
)
|
||||
|
||||
@ -173,6 +173,8 @@ function gulptasksImageResources($, gulp, buildFolder) {
|
||||
gulp.task(
|
||||
"imgres.allOptimized",
|
||||
gulp.parallel(
|
||||
"imgres.buildAtlas",
|
||||
"imgres.atlasToJson",
|
||||
"imgres.atlasOptimized",
|
||||
"imgres.copyNonImageResources",
|
||||
"imgres.copyImageResourcesOptimized"
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 8.5 KiB |
@ -17,13 +17,10 @@
|
||||
grid-template-rows: 1fr 1fr;
|
||||
@include S(margin-bottom, 4px);
|
||||
color: #333438;
|
||||
// text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.2);
|
||||
|
||||
&.unpinable {
|
||||
> canvas {
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
}
|
||||
&.removable {
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
> canvas {
|
||||
@ -31,16 +28,9 @@
|
||||
@include S(height, 25px);
|
||||
grid-column: 1 / 2;
|
||||
grid-row: 1 / 3;
|
||||
pointer-events: all;
|
||||
transition: transform 0.1s ease-in-out;
|
||||
transform-origin: D(2px) center;
|
||||
will-change: transform;
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
z-index: 20;
|
||||
&:hover {
|
||||
transform: scale(2);
|
||||
z-index: 21;
|
||||
}
|
||||
position: relative;
|
||||
}
|
||||
|
||||
> .amountLabel,
|
||||
|
||||
@ -29,6 +29,7 @@ import { MobileWarningState } from "./states/mobile_warning";
|
||||
import { PreloadState } from "./states/preload";
|
||||
import { SettingsState } from "./states/settings";
|
||||
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
|
||||
import { RestrictionManager } from "./core/restriction_manager";
|
||||
|
||||
/**
|
||||
* @typedef {import("./platform/game_analytics").GameAnalyticsInterface} GameAnalyticsInterface
|
||||
@ -70,6 +71,9 @@ export class Application {
|
||||
this.inputMgr = new InputDistributor(this);
|
||||
this.backgroundResourceLoader = new BackgroundResourcesLoader(this);
|
||||
|
||||
// Restrictions (Like demo etc)
|
||||
this.restrictionMgr = new RestrictionManager(this);
|
||||
|
||||
// Platform dependent stuff
|
||||
|
||||
/** @type {StorageInterface} */
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import { queryParamOptions } from "./query_parameters";
|
||||
|
||||
export const IS_DEBUG =
|
||||
G_IS_DEV &&
|
||||
typeof window !== "undefined" &&
|
||||
@ -7,13 +5,10 @@ export const IS_DEBUG =
|
||||
(window.location.host.indexOf("localhost:") >= 0 || window.location.host.indexOf("192.168.0.") >= 0) &&
|
||||
window.location.search.indexOf("nodebug") < 0;
|
||||
|
||||
export const IS_DEMO = queryParamOptions.fullVersion
|
||||
? false
|
||||
: (!G_IS_DEV && !G_IS_STANDALONE) ||
|
||||
(typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0);
|
||||
|
||||
export const SUPPORT_TOUCH = false;
|
||||
|
||||
export const IS_MAC = navigator.platform.toLowerCase().indexOf("mac") >= 0;
|
||||
|
||||
const smoothCanvas = true;
|
||||
|
||||
export const THIRDPARTY_URLS = {
|
||||
@ -64,7 +59,7 @@ export const globalConfig = {
|
||||
|
||||
undergroundBeltMaxTilesByTier: [5, 9],
|
||||
|
||||
readerAnalyzeIntervalSeconds: G_IS_DEV ? 3 : 10,
|
||||
readerAnalyzeIntervalSeconds: 10,
|
||||
|
||||
buildingSpeeds: {
|
||||
cutter: 1 / 4,
|
||||
|
||||
@ -81,10 +81,6 @@ export class ReadWriteProxy {
|
||||
return this.writeAsync();
|
||||
}
|
||||
|
||||
getCurrentData() {
|
||||
return this.currentData;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} obj
|
||||
|
||||
155
src/js/core/restriction_manager.js
Normal file
@ -0,0 +1,155 @@
|
||||
/* typehints:start */
|
||||
import { Application } from "../application";
|
||||
/* typehints:end */
|
||||
import { IS_MAC } from "./config";
|
||||
import { ExplainedResult } from "./explained_result";
|
||||
import { queryParamOptions } from "./query_parameters";
|
||||
import { ReadWriteProxy } from "./read_write_proxy";
|
||||
|
||||
export class RestrictionManager extends ReadWriteProxy {
|
||||
/**
|
||||
* @param {Application} app
|
||||
*/
|
||||
constructor(app) {
|
||||
super(app, "restriction-flags.bin");
|
||||
|
||||
this.currentData = this.getDefaultData();
|
||||
}
|
||||
|
||||
// -- RW Proxy Impl
|
||||
|
||||
/**
|
||||
* @param {any} data
|
||||
*/
|
||||
verify(data) {
|
||||
return ExplainedResult.good();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
getDefaultData() {
|
||||
return {
|
||||
version: this.getCurrentVersion(),
|
||||
savegameV1119Imported: false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
getCurrentVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} data
|
||||
*/
|
||||
migrate(data) {
|
||||
// Todo
|
||||
return ExplainedResult.good();
|
||||
}
|
||||
|
||||
initialize() {
|
||||
return this.readAsync().then(() => {
|
||||
if (this.currentData.savegameV1119Imported) {
|
||||
console.warn("Levelunlock is granted to current user due to past savegame");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// -- End RW Proxy Impl
|
||||
|
||||
/**
|
||||
* Checks if there are any savegames from the 1.1.19 version
|
||||
*/
|
||||
onHasLegacySavegamesChanged(has119Savegames = false) {
|
||||
if (has119Savegames && !this.currentData.savegameV1119Imported) {
|
||||
this.currentData.savegameV1119Imported = true;
|
||||
console.warn("Current user now has access to all levels due to 1119 savegame");
|
||||
return this.writeAsync();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the app is currently running as the limited version
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isLimitedVersion() {
|
||||
if (IS_MAC) {
|
||||
// On mac, the full version is always active
|
||||
return false;
|
||||
}
|
||||
|
||||
if (G_IS_STANDALONE) {
|
||||
// Standalone is never limited
|
||||
return false;
|
||||
}
|
||||
|
||||
if (queryParamOptions.fullVersion) {
|
||||
// Full version is activated via flag
|
||||
return false;
|
||||
}
|
||||
|
||||
if (G_IS_DEV) {
|
||||
return typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the app markets the standalone version on steam
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getIsStandaloneMarketingActive() {
|
||||
return this.isLimitedVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if exporting the base as a screenshot is possible
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getIsExportingScreenshotsPossible() {
|
||||
return !this.isLimitedVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of supported waypoints
|
||||
* @returns {number}
|
||||
*/
|
||||
getMaximumWaypoints() {
|
||||
return this.isLimitedVersion() ? 2 : 1e20;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the user has unlimited savegames
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getHasUnlimitedSavegames() {
|
||||
return !this.isLimitedVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the app has all settings available
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getHasExtendedSettings() {
|
||||
return !this.isLimitedVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if all upgrades are available
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getHasExtendedUpgrades() {
|
||||
return !this.isLimitedVersion() || this.currentData.savegameV1119Imported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if all levels & freeplay is available
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getHasExtendedLevelsAndFreeplay() {
|
||||
return !this.isLimitedVersion() || this.currentData.savegameV1119Imported;
|
||||
}
|
||||
}
|
||||
@ -108,17 +108,6 @@ export class RandomNumberGenerator {
|
||||
assert(max > min, "rng: max <= min");
|
||||
return Math.floor(this.next() * (max - min) + min);
|
||||
}
|
||||
/**
|
||||
* @param {number} min
|
||||
* @param {number} max
|
||||
* @returns {number} Integer in range [min, max]
|
||||
*/
|
||||
nextIntRangeInclusive(min, max) {
|
||||
assert(Number.isFinite(min), "Minimum is no integer");
|
||||
assert(Number.isFinite(max), "Maximum is no integer");
|
||||
assert(max > min, "rng: max <= min");
|
||||
return Math.round(this.next() * (max - min) + min);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} min
|
||||
|
||||
@ -681,3 +681,72 @@ export function fillInLinkIntoTranslation(translation, link) {
|
||||
.replace("<link>", "<a href='" + link + "' target='_blank'>")
|
||||
.replace("</link>", "</a>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a file download
|
||||
* @param {string} filename
|
||||
* @param {string} text
|
||||
*/
|
||||
export function generateFileDownload(filename, text) {
|
||||
var element = document.createElement("a");
|
||||
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text));
|
||||
element.setAttribute("download", filename);
|
||||
|
||||
element.style.display = "none";
|
||||
document.body.appendChild(element);
|
||||
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a file chooser
|
||||
* @param {string} acceptedType
|
||||
*/
|
||||
export function startFileChoose(acceptedType = ".bin") {
|
||||
var input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = acceptedType;
|
||||
|
||||
return new Promise(resolve => {
|
||||
input.onchange = _ => resolve(input.files[0]);
|
||||
input.click();
|
||||
});
|
||||
}
|
||||
|
||||
const romanLiterals = [
|
||||
"0", // NULL
|
||||
"I",
|
||||
"II",
|
||||
"III",
|
||||
"IV",
|
||||
"V",
|
||||
"VI",
|
||||
"VII",
|
||||
"VIII",
|
||||
"IX",
|
||||
"X",
|
||||
"XI",
|
||||
"XII",
|
||||
"XIII",
|
||||
"XIV",
|
||||
"XV",
|
||||
"XVI",
|
||||
"XVII",
|
||||
"XVIII",
|
||||
"XIX",
|
||||
"XX",
|
||||
];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} number
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getRomanNumber(number) {
|
||||
number = Math.max(0, Math.round(number));
|
||||
if (number < romanLiterals.length) {
|
||||
return romanLiterals[number];
|
||||
}
|
||||
return String(number);
|
||||
}
|
||||
|
||||
@ -1111,7 +1111,7 @@ export class BeltPath extends BasicSerializableObject {
|
||||
|
||||
isFirstItemProcessed = false;
|
||||
this.spacingToFirstItem += clampedProgress;
|
||||
if (remainingVelocity < 0.01) {
|
||||
if (remainingVelocity < 1e-7) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
import { globalConfig } from "../core/config";
|
||||
import { DrawParameters } from "../core/draw_parameters";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { findNiceIntegerValue } from "../core/utils";
|
||||
import { Vector } from "../core/vector";
|
||||
import { Entity } from "./entity";
|
||||
import { GameRoot } from "./root";
|
||||
import { blueprintShape } from "./upgrades";
|
||||
|
||||
const logger = createLogger("blueprint");
|
||||
|
||||
export class Blueprint {
|
||||
/**
|
||||
@ -142,7 +138,7 @@ export class Blueprint {
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
canAfford(root) {
|
||||
return root.hubGoals.getShapesStoredByKey(blueprintShape) >= this.getCost();
|
||||
return root.hubGoals.getShapesStoredByKey(root.gameMode.getBlueprintShapeKey()) >= this.getCost();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -110,12 +110,7 @@ export class MetaVirtualProcessorBuilding extends MetaBuilding {
|
||||
pinComp.setSlots([
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.left,
|
||||
type: enumPinSlotType.logicalEjector,
|
||||
},
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.right,
|
||||
direction: enumDirection.top,
|
||||
type: enumPinSlotType.logicalEjector,
|
||||
},
|
||||
{
|
||||
|
||||
@ -511,7 +511,11 @@ export class Camera extends BasicSerializableObject {
|
||||
this.clampZoomLevel();
|
||||
this.desiredZoom = null;
|
||||
|
||||
const mousePosition = this.root.app.mousePosition;
|
||||
let mousePosition = this.root.app.mousePosition;
|
||||
if (!this.root.app.settings.getAllSettings().zoomToCursor) {
|
||||
mousePosition = new Vector(this.root.gameWidth / 2, this.root.gameHeight / 2);
|
||||
}
|
||||
|
||||
if (mousePosition) {
|
||||
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||
const worldDelta = worldPos.sub(this.center);
|
||||
|
||||
@ -31,6 +31,7 @@ import { KeyActionMapper } from "./key_action_mapper";
|
||||
import { GameLogic } from "./logic";
|
||||
import { MapView } from "./map_view";
|
||||
import { defaultBuildingVariant } from "./meta_building";
|
||||
import { RegularGameMode } from "./modes/regular";
|
||||
import { ProductionAnalytics } from "./production_analytics";
|
||||
import { GameRoot } from "./root";
|
||||
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
||||
@ -101,6 +102,9 @@ export class GameCore {
|
||||
// Needs to come first
|
||||
root.dynamicTickrate = new DynamicTickrate(root);
|
||||
|
||||
// Init game mode
|
||||
root.gameMode = new RegularGameMode(root);
|
||||
|
||||
// Init classes
|
||||
root.camera = new Camera(root);
|
||||
root.map = new MapView(root);
|
||||
|
||||
71
src/js/game/game_mode.js
Normal file
@ -0,0 +1,71 @@
|
||||
/* typehints:start */
|
||||
import { enumHubGoalRewards } from "./tutorial_goals";
|
||||
/* typehints:end */
|
||||
|
||||
import { GameRoot } from "./root";
|
||||
|
||||
/** @typedef {{
|
||||
* shape: string,
|
||||
* amount: number
|
||||
* }} UpgradeRequirement */
|
||||
|
||||
/** @typedef {{
|
||||
* required: Array<UpgradeRequirement>
|
||||
* improvement?: number,
|
||||
* excludePrevious?: boolean
|
||||
* }} TierRequirement */
|
||||
|
||||
/** @typedef {Array<TierRequirement>} UpgradeTiers */
|
||||
|
||||
/** @typedef {{
|
||||
* shape: string,
|
||||
* required: number,
|
||||
* reward: enumHubGoalRewards,
|
||||
* throughputOnly?: boolean
|
||||
* }} LevelDefinition */
|
||||
|
||||
export class GameMode {
|
||||
/**
|
||||
*
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
constructor(root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return all available upgrades
|
||||
* @returns {Object<string, UpgradeTiers>}
|
||||
*/
|
||||
getUpgrades() {
|
||||
abstract;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the blueprint shape key
|
||||
* @returns {string}
|
||||
*/
|
||||
getBlueprintShapeKey() {
|
||||
abstract;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the goals for all levels including their reward
|
||||
* @returns {Array<LevelDefinition>}
|
||||
*/
|
||||
getLevelDefinitions() {
|
||||
abstract;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return whether free play is available or if the game stops
|
||||
* after the predefined levels
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getIsFreeplayAvailable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,13 @@
|
||||
import { globalConfig, IS_DEMO } from "../core/config";
|
||||
import { globalConfig } from "../core/config";
|
||||
import { RandomNumberGenerator } from "../core/rng";
|
||||
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
|
||||
import { clamp } from "../core/utils";
|
||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||
import { enumColors } from "./colors";
|
||||
import { enumItemProcessorTypes } from "./components/item_processor";
|
||||
import { enumAnalyticsDataSource } from "./production_analytics";
|
||||
import { GameRoot } from "./root";
|
||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
||||
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
|
||||
import { UPGRADES } from "./upgrades";
|
||||
import { enumHubGoalRewards } from "./tutorial_goals";
|
||||
|
||||
export class HubGoals extends BasicSerializableObject {
|
||||
static getId() {
|
||||
@ -23,27 +22,36 @@ export class HubGoals extends BasicSerializableObject {
|
||||
};
|
||||
}
|
||||
|
||||
deserialize(data) {
|
||||
/**
|
||||
*
|
||||
* @param {*} data
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
deserialize(data, root) {
|
||||
const errorCode = super.deserialize(data);
|
||||
if (errorCode) {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
if (IS_DEMO) {
|
||||
this.level = Math.min(this.level, tutorialGoals.length);
|
||||
const levels = root.gameMode.getLevelDefinitions();
|
||||
|
||||
// If freeplay is not available, clamp the level
|
||||
if (!root.gameMode.getIsFreeplayAvailable()) {
|
||||
this.level = Math.min(this.level, levels.length);
|
||||
}
|
||||
|
||||
// Compute gained rewards
|
||||
for (let i = 0; i < this.level - 1; ++i) {
|
||||
if (i < tutorialGoals.length) {
|
||||
const reward = tutorialGoals[i].reward;
|
||||
if (i < levels.length) {
|
||||
const reward = levels[i].reward;
|
||||
this.gainedRewards[reward] = (this.gainedRewards[reward] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute upgrade improvements
|
||||
for (const upgradeId in UPGRADES) {
|
||||
const tiers = UPGRADES[upgradeId];
|
||||
const upgrades = this.root.gameMode.getUpgrades();
|
||||
for (const upgradeId in upgrades) {
|
||||
const tiers = upgrades[upgradeId];
|
||||
const level = this.upgradeLevels[upgradeId] || 0;
|
||||
let totalImprovement = 1;
|
||||
for (let i = 0; i < level; ++i) {
|
||||
@ -84,17 +92,16 @@ export class HubGoals extends BasicSerializableObject {
|
||||
*/
|
||||
this.upgradeLevels = {};
|
||||
|
||||
// Reset levels
|
||||
for (const key in UPGRADES) {
|
||||
this.upgradeLevels[key] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the improvements for all upgrades
|
||||
* @type {Object<string, number>}
|
||||
*/
|
||||
this.upgradeImprovements = {};
|
||||
for (const key in UPGRADES) {
|
||||
|
||||
// Reset levels first
|
||||
const upgrades = this.root.gameMode.getUpgrades();
|
||||
for (const key in upgrades) {
|
||||
this.upgradeLevels[key] = 0;
|
||||
this.upgradeImprovements[key] = 1;
|
||||
}
|
||||
|
||||
@ -120,7 +127,10 @@ export class HubGoals extends BasicSerializableObject {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isEndOfDemoReached() {
|
||||
return IS_DEMO && this.level >= tutorialGoals.length;
|
||||
return (
|
||||
!this.root.gameMode.getIsFreeplayAvailable() &&
|
||||
this.level >= this.root.gameMode.getLevelDefinitions().length
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -215,8 +225,9 @@ export class HubGoals extends BasicSerializableObject {
|
||||
*/
|
||||
computeNextGoal() {
|
||||
const storyIndex = this.level - 1;
|
||||
if (storyIndex < tutorialGoals.length) {
|
||||
const { shape, required, reward, throughputOnly } = tutorialGoals[storyIndex];
|
||||
const levels = this.root.gameMode.getLevelDefinitions();
|
||||
if (storyIndex < levels.length) {
|
||||
const { shape, required, reward, throughputOnly } = levels[storyIndex];
|
||||
this.currentGoal = {
|
||||
/** @type {ShapeDefinition} */
|
||||
definition: this.root.shapeDefinitionMgr.getShapeFromShortKey(shape),
|
||||
@ -254,7 +265,7 @@ export class HubGoals extends BasicSerializableObject {
|
||||
* Returns whether we are playing in free-play
|
||||
*/
|
||||
isFreePlay() {
|
||||
return this.level >= tutorialGoals.length;
|
||||
return this.level >= this.root.gameMode.getLevelDefinitions().length;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,7 +273,7 @@ export class HubGoals extends BasicSerializableObject {
|
||||
* @param {string} upgradeId
|
||||
*/
|
||||
canUnlockUpgrade(upgradeId) {
|
||||
const tiers = UPGRADES[upgradeId];
|
||||
const tiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||
const currentLevel = this.getUpgradeLevel(upgradeId);
|
||||
|
||||
if (currentLevel >= tiers.length) {
|
||||
@ -270,11 +281,6 @@ export class HubGoals extends BasicSerializableObject {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IS_DEMO && currentLevel >= 4) {
|
||||
// DEMO
|
||||
return false;
|
||||
}
|
||||
|
||||
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
|
||||
return true;
|
||||
}
|
||||
@ -296,7 +302,7 @@ export class HubGoals extends BasicSerializableObject {
|
||||
*/
|
||||
getAvailableUpgradeCount() {
|
||||
let count = 0;
|
||||
for (const upgradeId in UPGRADES) {
|
||||
for (const upgradeId in this.root.gameMode.getUpgrades()) {
|
||||
if (this.canUnlockUpgrade(upgradeId)) {
|
||||
++count;
|
||||
}
|
||||
@ -314,7 +320,7 @@ export class HubGoals extends BasicSerializableObject {
|
||||
return false;
|
||||
}
|
||||
|
||||
const upgradeTiers = UPGRADES[upgradeId];
|
||||
const upgradeTiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||
const currentLevel = this.getUpgradeLevel(upgradeId);
|
||||
|
||||
const tierData = upgradeTiers[currentLevel];
|
||||
@ -363,7 +369,7 @@ export class HubGoals extends BasicSerializableObject {
|
||||
if (allowUncolored) {
|
||||
universalColors.push(enumColors.uncolored);
|
||||
}
|
||||
const index = rng.nextIntRangeInclusive(0, colorWheel.length - 3);
|
||||
const index = rng.nextIntRange(0, colorWheel.length - 2);
|
||||
const pickedColors = colorWheel.slice(index, index + 3);
|
||||
pickedColors.push(rng.choice(universalColors));
|
||||
return pickedColors;
|
||||
|
||||
@ -15,7 +15,7 @@ import { HUDKeybindingOverlay } from "./parts/keybinding_overlay";
|
||||
import { HUDUnlockNotification } from "./parts/unlock_notification";
|
||||
import { HUDGameMenu } from "./parts/game_menu";
|
||||
import { HUDShop } from "./parts/shop";
|
||||
import { IS_MOBILE, globalConfig, IS_DEMO } from "../../core/config";
|
||||
import { IS_MOBILE, globalConfig } from "../../core/config";
|
||||
import { HUDMassSelector } from "./parts/mass_selector";
|
||||
import { HUDVignetteOverlay } from "./parts/vignette_overlay";
|
||||
import { HUDStatistics } from "./parts/statistics";
|
||||
@ -46,7 +46,6 @@ import { HUDEditConstantSignal } from "./parts/edit_constant_signal";
|
||||
import { HUDLayerPreview } from "./parts/layer_preview";
|
||||
import { HUDMinerHighlight } from "./parts/miner_highlight";
|
||||
import { HUDBetaOverlay } from "./parts/beta_overlay";
|
||||
import { HUDPerformanceWarning } from "./parts/performance_warning";
|
||||
import { HUDStandaloneAdvantages } from "./parts/standalone_advantages";
|
||||
import { HUDCatMemes } from "./parts/cat_memes";
|
||||
|
||||
@ -90,7 +89,6 @@ export class GameHUD {
|
||||
layerPreview: new HUDLayerPreview(this.root),
|
||||
|
||||
minerHighlight: new HUDMinerHighlight(this.root),
|
||||
performanceWarning: new HUDPerformanceWarning(this.root),
|
||||
|
||||
// Typing hints
|
||||
/* typehints:start */
|
||||
@ -118,7 +116,7 @@ export class GameHUD {
|
||||
this.parts.entityDebugger = new HUDEntityDebugger(this.root);
|
||||
}
|
||||
|
||||
if (IS_DEMO) {
|
||||
if (this.root.app.restrictionMgr.getIsStandaloneMarketingActive()) {
|
||||
this.parts.watermark = new HUDWatermark(this.root);
|
||||
this.parts.standaloneAdvantages = new HUDStandaloneAdvantages(this.root);
|
||||
this.parts.catMemes = new HUDCatMemes(this.root);
|
||||
|
||||
@ -7,7 +7,7 @@ export class HUDBetaOverlay extends BaseHUDPart {
|
||||
parent,
|
||||
"ingame_HUD_BetaOverlay",
|
||||
[],
|
||||
"<h2>UNSTABLE BETA VERSION</h2><span>Steam Release: 9th October 2020!</span>"
|
||||
"<h2>UNSTABLE BETA VERSION</h2><span>Unfinalized & potential buggy content!</span>"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,202 +1,203 @@
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { STOP_PROPAGATION } from "../../../core/signal";
|
||||
import { TrackedState } from "../../../core/tracked_state";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { T } from "../../../translations";
|
||||
import { enumMouseButton } from "../../camera";
|
||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { blueprintShape } from "../../upgrades";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { Blueprint } from "../../blueprint";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
|
||||
export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
const blueprintCostShape = this.root.shapeDefinitionMgr.getShapeFromShortKey(blueprintShape);
|
||||
const blueprintCostShapeCanvas = blueprintCostShape.generateAsCanvas(80);
|
||||
|
||||
this.costDisplayParent = makeDiv(parent, "ingame_HUD_BlueprintPlacer", [], ``);
|
||||
|
||||
makeDiv(this.costDisplayParent, null, ["label"], T.ingame.blueprintPlacer.cost);
|
||||
const costContainer = makeDiv(this.costDisplayParent, null, ["costContainer"], "");
|
||||
this.costDisplayText = makeDiv(costContainer, null, ["costText"], "");
|
||||
costContainer.appendChild(blueprintCostShapeCanvas);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this);
|
||||
|
||||
/** @type {TypedTrackedState<Blueprint?>} */
|
||||
this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this);
|
||||
/** @type {Blueprint?} */
|
||||
this.lastBlueprintUsed = null;
|
||||
|
||||
const keyActionMapper = this.root.keyMapper;
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.pipette).add(this.abortPlacement, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.massSelect.pasteLastBlueprint).add(this.pasteBlueprint, this);
|
||||
|
||||
this.root.camera.downPreHandler.add(this.onMouseDown, this);
|
||||
this.root.camera.movePreHandler.add(this.onMouseMove, this);
|
||||
|
||||
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this);
|
||||
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
|
||||
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent);
|
||||
this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this);
|
||||
}
|
||||
|
||||
abortPlacement() {
|
||||
if (this.currentBlueprint.get()) {
|
||||
this.currentBlueprint.set(null);
|
||||
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the layer was changed
|
||||
* @param {Layer} layer
|
||||
*/
|
||||
onEditModeChanged(layer) {
|
||||
// Check if the layer of the blueprint differs and thus we have to deselect it
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (blueprint) {
|
||||
if (blueprint.layer !== layer) {
|
||||
this.currentBlueprint.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the blueprint is now affordable or not
|
||||
* @param {boolean} canAfford
|
||||
*/
|
||||
onCanAffordChanged(canAfford) {
|
||||
this.costDisplayParent.classList.toggle("canAfford", canAfford);
|
||||
}
|
||||
|
||||
update() {
|
||||
const currentBlueprint = this.currentBlueprint.get();
|
||||
this.domAttach.update(currentBlueprint && currentBlueprint.getCost() > 0);
|
||||
this.trackedCanAfford.set(currentBlueprint && currentBlueprint.canAfford(this.root));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the blueprint was changed
|
||||
* @param {Blueprint} blueprint
|
||||
*/
|
||||
onBlueprintChanged(blueprint) {
|
||||
if (blueprint) {
|
||||
this.lastBlueprintUsed = blueprint;
|
||||
this.costDisplayText.innerText = "" + blueprint.getCost();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mouse down pre handler
|
||||
* @param {Vector} pos
|
||||
* @param {enumMouseButton} button
|
||||
*/
|
||||
onMouseDown(pos, button) {
|
||||
if (button === enumMouseButton.right) {
|
||||
if (this.currentBlueprint.get()) {
|
||||
this.abortPlacement();
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blueprint.canAfford(this.root)) {
|
||||
this.root.soundProxy.playUiError();
|
||||
return;
|
||||
}
|
||||
|
||||
const worldPos = this.root.camera.screenToWorld(pos);
|
||||
const tile = worldPos.toTileSpace();
|
||||
if (blueprint.tryPlace(this.root, tile)) {
|
||||
const cost = blueprint.getCost();
|
||||
this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
|
||||
this.root.soundProxy.playUi(SOUNDS.placeBuilding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mose move handler
|
||||
*/
|
||||
onMouseMove() {
|
||||
// Prevent movement while blueprint is selected
|
||||
if (this.currentBlueprint.get()) {
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an array of bulidings was selected
|
||||
* @param {Array<number>} uids
|
||||
*/
|
||||
createBlueprintFromBuildings(uids) {
|
||||
if (uids.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to rotate the current blueprint
|
||||
*/
|
||||
rotateBlueprint() {
|
||||
if (this.currentBlueprint.get()) {
|
||||
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
|
||||
this.currentBlueprint.get().rotateCcw();
|
||||
} else {
|
||||
this.currentBlueprint.get().rotateCw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to paste the last blueprint
|
||||
*/
|
||||
pasteBlueprint() {
|
||||
if (this.lastBlueprintUsed !== null) {
|
||||
if (this.lastBlueprintUsed.layer !== this.root.currentLayer) {
|
||||
// Not compatible
|
||||
this.root.soundProxy.playUiError();
|
||||
return;
|
||||
}
|
||||
|
||||
this.root.hud.signals.pasteBlueprintRequested.dispatch();
|
||||
this.currentBlueprint.set(this.lastBlueprintUsed);
|
||||
} else {
|
||||
this.root.soundProxy.playUiError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
draw(parameters) {
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
const mousePosition = this.root.app.mousePosition;
|
||||
if (!mousePosition) {
|
||||
// Not on screen
|
||||
return;
|
||||
}
|
||||
|
||||
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||
const tile = worldPos.toTileSpace();
|
||||
blueprint.draw(parameters, tile);
|
||||
}
|
||||
}
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { STOP_PROPAGATION } from "../../../core/signal";
|
||||
import { TrackedState } from "../../../core/tracked_state";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
import { T } from "../../../translations";
|
||||
import { Blueprint } from "../../blueprint";
|
||||
import { enumMouseButton } from "../../camera";
|
||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
const blueprintCostShape = this.root.shapeDefinitionMgr.getShapeFromShortKey(
|
||||
this.root.gameMode.getBlueprintShapeKey()
|
||||
);
|
||||
const blueprintCostShapeCanvas = blueprintCostShape.generateAsCanvas(80);
|
||||
|
||||
this.costDisplayParent = makeDiv(parent, "ingame_HUD_BlueprintPlacer", [], ``);
|
||||
|
||||
makeDiv(this.costDisplayParent, null, ["label"], T.ingame.blueprintPlacer.cost);
|
||||
const costContainer = makeDiv(this.costDisplayParent, null, ["costContainer"], "");
|
||||
this.costDisplayText = makeDiv(costContainer, null, ["costText"], "");
|
||||
costContainer.appendChild(blueprintCostShapeCanvas);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this);
|
||||
|
||||
/** @type {TypedTrackedState<Blueprint?>} */
|
||||
this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this);
|
||||
/** @type {Blueprint?} */
|
||||
this.lastBlueprintUsed = null;
|
||||
|
||||
const keyActionMapper = this.root.keyMapper;
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.pipette).add(this.abortPlacement, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
|
||||
keyActionMapper.getBinding(KEYMAPPINGS.massSelect.pasteLastBlueprint).add(this.pasteBlueprint, this);
|
||||
|
||||
this.root.camera.downPreHandler.add(this.onMouseDown, this);
|
||||
this.root.camera.movePreHandler.add(this.onMouseMove, this);
|
||||
|
||||
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this);
|
||||
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
|
||||
|
||||
this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent);
|
||||
this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this);
|
||||
}
|
||||
|
||||
abortPlacement() {
|
||||
if (this.currentBlueprint.get()) {
|
||||
this.currentBlueprint.set(null);
|
||||
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the layer was changed
|
||||
* @param {Layer} layer
|
||||
*/
|
||||
onEditModeChanged(layer) {
|
||||
// Check if the layer of the blueprint differs and thus we have to deselect it
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (blueprint) {
|
||||
if (blueprint.layer !== layer) {
|
||||
this.currentBlueprint.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the blueprint is now affordable or not
|
||||
* @param {boolean} canAfford
|
||||
*/
|
||||
onCanAffordChanged(canAfford) {
|
||||
this.costDisplayParent.classList.toggle("canAfford", canAfford);
|
||||
}
|
||||
|
||||
update() {
|
||||
const currentBlueprint = this.currentBlueprint.get();
|
||||
this.domAttach.update(currentBlueprint && currentBlueprint.getCost() > 0);
|
||||
this.trackedCanAfford.set(currentBlueprint && currentBlueprint.canAfford(this.root));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the blueprint was changed
|
||||
* @param {Blueprint} blueprint
|
||||
*/
|
||||
onBlueprintChanged(blueprint) {
|
||||
if (blueprint) {
|
||||
this.lastBlueprintUsed = blueprint;
|
||||
this.costDisplayText.innerText = "" + blueprint.getCost();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mouse down pre handler
|
||||
* @param {Vector} pos
|
||||
* @param {enumMouseButton} button
|
||||
*/
|
||||
onMouseDown(pos, button) {
|
||||
if (button === enumMouseButton.right) {
|
||||
if (this.currentBlueprint.get()) {
|
||||
this.abortPlacement();
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blueprint.canAfford(this.root)) {
|
||||
this.root.soundProxy.playUiError();
|
||||
return;
|
||||
}
|
||||
|
||||
const worldPos = this.root.camera.screenToWorld(pos);
|
||||
const tile = worldPos.toTileSpace();
|
||||
if (blueprint.tryPlace(this.root, tile)) {
|
||||
const cost = blueprint.getCost();
|
||||
this.root.hubGoals.takeShapeByKey(this.root.gameMode.getBlueprintShapeKey(), cost);
|
||||
this.root.soundProxy.playUi(SOUNDS.placeBuilding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mose move handler
|
||||
*/
|
||||
onMouseMove() {
|
||||
// Prevent movement while blueprint is selected
|
||||
if (this.currentBlueprint.get()) {
|
||||
return STOP_PROPAGATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an array of bulidings was selected
|
||||
* @param {Array<number>} uids
|
||||
*/
|
||||
createBlueprintFromBuildings(uids) {
|
||||
if (uids.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to rotate the current blueprint
|
||||
*/
|
||||
rotateBlueprint() {
|
||||
if (this.currentBlueprint.get()) {
|
||||
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
|
||||
this.currentBlueprint.get().rotateCcw();
|
||||
} else {
|
||||
this.currentBlueprint.get().rotateCw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to paste the last blueprint
|
||||
*/
|
||||
pasteBlueprint() {
|
||||
if (this.lastBlueprintUsed !== null) {
|
||||
if (this.lastBlueprintUsed.layer !== this.root.currentLayer) {
|
||||
// Not compatible
|
||||
this.root.soundProxy.playUiError();
|
||||
return;
|
||||
}
|
||||
|
||||
this.root.hud.signals.pasteBlueprintRequested.dispatch();
|
||||
this.currentBlueprint.set(this.lastBlueprintUsed);
|
||||
} else {
|
||||
this.root.soundProxy.playUiError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
draw(parameters) {
|
||||
const blueprint = this.currentBlueprint.get();
|
||||
if (!blueprint) {
|
||||
return;
|
||||
}
|
||||
const mousePosition = this.root.app.mousePosition;
|
||||
if (!mousePosition) {
|
||||
// Not on screen
|
||||
return;
|
||||
}
|
||||
|
||||
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||
const tile = worldPos.toTileSpace();
|
||||
blueprint.draw(parameters, tile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
import { T } from "../../../translations";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
|
||||
export class HUDPerformanceWarning extends BaseHUDPart {
|
||||
initialize() {
|
||||
this.warningShown = false;
|
||||
this.root.signals.entityManuallyPlaced.add(this.checkAfterPlace, this);
|
||||
}
|
||||
|
||||
checkAfterPlace() {
|
||||
if (!this.warningShown && this.root.entityMgr.entities.length > 10000) {
|
||||
this.root.hud.parts.dialogs.showInfo(T.dialogs.entityWarning.title, T.dialogs.entityWarning.desc);
|
||||
this.warningShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,11 @@
|
||||
import { ClickDetector } from "../../../core/click_detector";
|
||||
import { formatBigNumber, makeDiv, arrayDeleteValue } from "../../../core/utils";
|
||||
import { ShapeDefinition } from "../../shape_definition";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { blueprintShape, UPGRADES } from "../../upgrades";
|
||||
import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||
import { enumAnalyticsDataSource } from "../../production_analytics";
|
||||
import { T } from "../../../translations";
|
||||
import { globalConfig } from "../../../core/config";
|
||||
import { arrayDeleteValue, formatBigNumber, makeDiv } from "../../../core/utils";
|
||||
import { T } from "../../../translations";
|
||||
import { enumAnalyticsDataSource } from "../../production_analytics";
|
||||
import { ShapeDefinition } from "../../shape_definition";
|
||||
import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
|
||||
/**
|
||||
* Manages the pinned shapes on the left side of the screen
|
||||
@ -82,7 +81,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
updateShapesAfterUpgrade() {
|
||||
for (let i = 0; i < this.pinnedShapes.length; ++i) {
|
||||
const key = this.pinnedShapes[i];
|
||||
if (key === blueprintShape) {
|
||||
if (key === this.root.gameMode.getBlueprintShapeKey()) {
|
||||
// Ignore blueprint shapes
|
||||
continue;
|
||||
}
|
||||
@ -107,13 +106,14 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
if (key === this.root.hubGoals.currentGoal.definition.getHash()) {
|
||||
return this.root.hubGoals.currentGoal.required;
|
||||
}
|
||||
if (key === blueprintShape) {
|
||||
if (key === this.root.gameMode.getBlueprintShapeKey()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if this shape is required for any upgrade
|
||||
for (const upgradeId in UPGRADES) {
|
||||
const upgradeTiers = UPGRADES[upgradeId];
|
||||
const upgrades = this.root.gameMode.getUpgrades();
|
||||
for (const upgradeId in upgrades) {
|
||||
const upgradeTiers = upgrades[upgradeId];
|
||||
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||
const tierHandle = upgradeTiers[currentTier];
|
||||
|
||||
@ -138,7 +138,10 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
* @param {string} key
|
||||
*/
|
||||
isShapePinned(key) {
|
||||
if (key === this.root.hubGoals.currentGoal.definition.getHash() || key === blueprintShape) {
|
||||
if (
|
||||
key === this.root.hubGoals.currentGoal.definition.getHash() ||
|
||||
key === this.root.gameMode.getBlueprintShapeKey()
|
||||
) {
|
||||
// This is a "special" shape which is always pinned
|
||||
return true;
|
||||
}
|
||||
@ -178,7 +181,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
// Pin blueprint shape as well
|
||||
if (this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_blueprints)) {
|
||||
this.internalPinShape({
|
||||
key: blueprintShape,
|
||||
key: this.root.gameMode.getBlueprintShapeKey(),
|
||||
canUnpin: false,
|
||||
className: "blueprint",
|
||||
});
|
||||
@ -214,11 +217,11 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
|
||||
let detector = null;
|
||||
if (canUnpin) {
|
||||
element.classList.add("unpinable");
|
||||
element.classList.add("removable");
|
||||
detector = new ClickDetector(element, {
|
||||
consumeEvents: true,
|
||||
preventDefault: true,
|
||||
targetOnly: true,
|
||||
targetOnly: false,
|
||||
});
|
||||
detector.click.add(() => this.unpinShape(key));
|
||||
} else {
|
||||
@ -291,6 +294,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
* @param {string} key
|
||||
*/
|
||||
unpinShape(key) {
|
||||
console.log("unpin", key);
|
||||
arrayDeleteValue(this.pinnedShapes, key);
|
||||
this.rerenderFull();
|
||||
}
|
||||
@ -306,7 +310,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === blueprintShape) {
|
||||
if (key === this.root.gameMode.getBlueprintShapeKey()) {
|
||||
// Can not pin the blueprint shape
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { blueprintShape, UPGRADES } from "../../upgrades";
|
||||
import { enumNotificationType } from "./notifications";
|
||||
import { tutorialGoals } from "../../tutorial_goals";
|
||||
|
||||
export class HUDSandboxController extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
@ -75,10 +73,11 @@ export class HUDSandboxController extends BaseHUDPart {
|
||||
}
|
||||
|
||||
giveBlueprints() {
|
||||
if (!this.root.hubGoals.storedShapes[blueprintShape]) {
|
||||
this.root.hubGoals.storedShapes[blueprintShape] = 0;
|
||||
const shape = this.root.gameMode.getBlueprintShapeKey();
|
||||
if (!this.root.hubGoals.storedShapes[shape]) {
|
||||
this.root.hubGoals.storedShapes[shape] = 0;
|
||||
}
|
||||
this.root.hubGoals.storedShapes[blueprintShape] += 1e9;
|
||||
this.root.hubGoals.storedShapes[shape] += 1e9;
|
||||
}
|
||||
|
||||
maxOutAll() {
|
||||
@ -89,7 +88,7 @@ export class HUDSandboxController extends BaseHUDPart {
|
||||
}
|
||||
|
||||
modifyUpgrade(id, amount) {
|
||||
const upgradeTiers = UPGRADES[id];
|
||||
const upgradeTiers = this.root.gameMode.getUpgrades()[id];
|
||||
const maxLevel = upgradeTiers.length;
|
||||
|
||||
this.root.hubGoals.upgradeLevels[id] = Math.max(
|
||||
@ -122,9 +121,10 @@ export class HUDSandboxController extends BaseHUDPart {
|
||||
|
||||
// Compute gained rewards
|
||||
hubGoals.gainedRewards = {};
|
||||
const levels = this.root.gameMode.getLevelDefinitions();
|
||||
for (let i = 0; i < hubGoals.level - 1; ++i) {
|
||||
if (i < tutorialGoals.length) {
|
||||
const reward = tutorialGoals[i].reward;
|
||||
if (i < levels.length) {
|
||||
const reward = levels[i].reward;
|
||||
hubGoals.gainedRewards[reward] = (hubGoals.gainedRewards[reward] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { IS_DEMO, globalConfig } from "../../../core/config";
|
||||
import { T } from "../../../translations";
|
||||
import { createLogger } from "../../../core/logging";
|
||||
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
||||
import { globalConfig } from "../../../core/config";
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { createLogger } from "../../../core/logging";
|
||||
import { Rectangle } from "../../../core/rectangle";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { T } from "../../../translations";
|
||||
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
|
||||
const logger = createLogger("screenshot_exporter");
|
||||
|
||||
@ -19,7 +19,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
||||
}
|
||||
|
||||
startExport() {
|
||||
if (IS_DEMO) {
|
||||
if (!this.root.app.restrictionMgr.getIsExportingScreenshotsPossible()) {
|
||||
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(T.demo.features.exportingBase);
|
||||
return;
|
||||
}
|
||||
@ -87,7 +87,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
||||
const parameters = new DrawParameters({
|
||||
context,
|
||||
visibleRect,
|
||||
desiredAtlasScale: chunkScale,
|
||||
desiredAtlasScale: 0.25,
|
||||
root: this.root,
|
||||
zoomLevel: chunkScale,
|
||||
});
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import { ClickDetector } from "../../../core/click_detector";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { formatBigNumber, makeDiv } from "../../../core/utils";
|
||||
import { formatBigNumber, getRomanNumber, makeDiv } from "../../../core/utils";
|
||||
import { T } from "../../../translations";
|
||||
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { UPGRADES } from "../../upgrades";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
@ -21,7 +20,7 @@ export class HUDShop extends BaseHUDPart {
|
||||
this.upgradeToElements = {};
|
||||
|
||||
// Upgrades
|
||||
for (const upgradeId in UPGRADES) {
|
||||
for (const upgradeId in this.root.gameMode.getUpgrades()) {
|
||||
const handle = {};
|
||||
handle.requireIndexToElement = [];
|
||||
|
||||
@ -59,7 +58,7 @@ export class HUDShop extends BaseHUDPart {
|
||||
rerenderFull() {
|
||||
for (const upgradeId in this.upgradeToElements) {
|
||||
const handle = this.upgradeToElements[upgradeId];
|
||||
const upgradeTiers = UPGRADES[upgradeId];
|
||||
const upgradeTiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||
|
||||
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||
const currentTierMultiplier = this.root.hubGoals.upgradeImprovements[upgradeId];
|
||||
@ -68,7 +67,7 @@ export class HUDShop extends BaseHUDPart {
|
||||
// Set tier
|
||||
handle.elemTierLabel.innerText = T.ingame.shop.tier.replace(
|
||||
"<x>",
|
||||
"" + T.ingame.shop.tierLabels[currentTier]
|
||||
getRomanNumber(currentTier + 1)
|
||||
);
|
||||
|
||||
handle.elemTierLabel.setAttribute("data-tier", currentTier);
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { globalConfig } from "../../../core/config";
|
||||
import { gMetaBuildingRegistry } from "../../../core/global_registries";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
import { T } from "../../../translations";
|
||||
import { defaultBuildingVariant } from "../../meta_building";
|
||||
import { enumHubGoalRewards, tutorialGoals } from "../../tutorial_goals";
|
||||
import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { enumNotificationType } from "./notifications";
|
||||
|
||||
export class HUDUnlockNotification extends BaseHUDPart {
|
||||
@ -53,7 +53,9 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||
showForLevel(level, reward) {
|
||||
this.root.soundProxy.playUi(SOUNDS.levelComplete);
|
||||
|
||||
if (level > tutorialGoals.length) {
|
||||
const levels = this.root.gameMode.getLevelDefinitions();
|
||||
// Don't use getIsFreeplay() because we want the freeplay level up to show
|
||||
if (level > levels.length) {
|
||||
this.root.hud.signals.notification.dispatch(
|
||||
T.ingame.notifications.freeplayLevelComplete.replace("<level>", String(level)),
|
||||
enumNotificationType.success
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
||||
import { globalConfig, IS_DEMO, THIRDPARTY_URLS } from "../../../core/config";
|
||||
import { globalConfig, THIRDPARTY_URLS } from "../../../core/config";
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { Loader } from "../../../core/loader";
|
||||
import { DialogWithForm } from "../../../core/modal_dialog_elements";
|
||||
@ -302,7 +302,7 @@ export class HUDWaypoints extends BaseHUDPart {
|
||||
// Show info that you can have only N markers in the demo,
|
||||
// actually show this *after* entering the name so you want the
|
||||
// standalone even more (I'm evil :P)
|
||||
if (IS_DEMO && this.waypoints.length > 2) {
|
||||
if (this.waypoints.length > this.root.app.restrictionMgr.getMaximumWaypoints()) {
|
||||
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(
|
||||
"",
|
||||
T.dialogs.markerDemoLimit.desc
|
||||
|
||||
@ -248,6 +248,8 @@ export function getStringForKeyCode(code) {
|
||||
return ",";
|
||||
case 189:
|
||||
return "-";
|
||||
case 190:
|
||||
return ".";
|
||||
case 191:
|
||||
return "/";
|
||||
case 219:
|
||||
@ -260,7 +262,9 @@ export function getStringForKeyCode(code) {
|
||||
return "'";
|
||||
}
|
||||
|
||||
return String.fromCharCode(code);
|
||||
return (48 <= code && code <= 57) || (65 <= code && code <= 90)
|
||||
? String.fromCharCode(code)
|
||||
: "[" + code + "]";
|
||||
}
|
||||
|
||||
export class Keybinding {
|
||||
|
||||
480
src/js/game/modes/regular.js
Normal file
@ -0,0 +1,480 @@
|
||||
import { findNiceIntegerValue } from "../../core/utils";
|
||||
import { GameMode } from "../game_mode";
|
||||
import { ShapeDefinition } from "../shape_definition";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
|
||||
const rocketShape = "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw";
|
||||
const finalGameShape = "RuCw--Cw:----Ru--";
|
||||
const preparementShape = "CpRpCp--:SwSwSwSw";
|
||||
const blueprintShape = "CbCbCbRb:CwCwCwCw";
|
||||
|
||||
// Tiers need % of the previous tier as requirement too
|
||||
const tierGrowth = 2.5;
|
||||
|
||||
/**
|
||||
* Generates all upgrades
|
||||
* @returns {Object<string, import("../game_mode").UpgradeTiers>} */
|
||||
function generateUpgrades(limitedVersion = false) {
|
||||
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 1, 1];
|
||||
const numEndgameUpgrades = limitedVersion ? 0 : 1000 - fixedImprovements.length - 1;
|
||||
|
||||
function generateInfiniteUnlocks() {
|
||||
return new Array(numEndgameUpgrades).fill(null).map((_, i) => ({
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 30000 + i * 10000 },
|
||||
{ shape: finalGameShape, amount: 20000 + i * 5000 },
|
||||
{ shape: rocketShape, amount: 20000 + i * 5000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
}));
|
||||
}
|
||||
|
||||
// Fill in endgame upgrades
|
||||
for (let i = 0; i < numEndgameUpgrades; ++i) {
|
||||
if (i < 20) {
|
||||
fixedImprovements.push(0.1);
|
||||
} else if (i < 50) {
|
||||
fixedImprovements.push(0.05);
|
||||
} else if (i < 100) {
|
||||
fixedImprovements.push(0.025);
|
||||
} else {
|
||||
fixedImprovements.push(0.0125);
|
||||
}
|
||||
}
|
||||
|
||||
const upgrades = {
|
||||
belt: [
|
||||
{
|
||||
required: [{ shape: "CuCuCuCu", amount: 60 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "--CuCu--", amount: 500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CpCpCpCp", amount: 1000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "SrSrSrSr:CyCyCyCy", amount: 6000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", amount: 25000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: preparementShape, amount: 25000 }],
|
||||
excludePrevious: true,
|
||||
},
|
||||
{
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 25000 },
|
||||
{ shape: finalGameShape, amount: 50000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
},
|
||||
...generateInfiniteUnlocks(),
|
||||
],
|
||||
|
||||
miner: [
|
||||
{
|
||||
required: [{ shape: "RuRuRuRu", amount: 300 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "Cu------", amount: 800 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "ScScScSc", amount: 3500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CwCwCwCw:WbWbWbWb", amount: 23000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", amount: 50000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: preparementShape, amount: 25000 }],
|
||||
excludePrevious: true,
|
||||
},
|
||||
{
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 25000 },
|
||||
{ shape: finalGameShape, amount: 50000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
},
|
||||
...generateInfiniteUnlocks(),
|
||||
],
|
||||
|
||||
processors: [
|
||||
{
|
||||
required: [{ shape: "SuSuSuSu", amount: 500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "RuRu----", amount: 600 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CgScScCg", amount: 3500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CwCrCwCr:SgSgSgSg", amount: 25000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", amount: 50000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: preparementShape, amount: 25000 }],
|
||||
excludePrevious: true,
|
||||
},
|
||||
{
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 25000 },
|
||||
{ shape: finalGameShape, amount: 50000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
},
|
||||
...generateInfiniteUnlocks(),
|
||||
],
|
||||
|
||||
painting: [
|
||||
{
|
||||
required: [{ shape: "RbRb----", amount: 600 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "WrWrWrWr", amount: 3800 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "RpRpRpRp:CwCwCwCw", amount: 6500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp", amount: 25000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp:CwCwCwCw", amount: 50000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: preparementShape, amount: 25000 }],
|
||||
excludePrevious: true,
|
||||
},
|
||||
{
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 25000 },
|
||||
{ shape: finalGameShape, amount: 50000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
},
|
||||
...generateInfiniteUnlocks(),
|
||||
],
|
||||
};
|
||||
|
||||
// Automatically generate tier levels
|
||||
for (const upgradeId in upgrades) {
|
||||
const upgradeTiers = upgrades[upgradeId];
|
||||
|
||||
let currentTierRequirements = [];
|
||||
for (let i = 0; i < upgradeTiers.length; ++i) {
|
||||
const tierHandle = upgradeTiers[i];
|
||||
tierHandle.improvement = fixedImprovements[i];
|
||||
const originalRequired = tierHandle.required.slice();
|
||||
|
||||
for (let k = currentTierRequirements.length - 1; k >= 0; --k) {
|
||||
const oldTierRequirement = currentTierRequirements[k];
|
||||
if (!tierHandle.excludePrevious) {
|
||||
tierHandle.required.unshift({
|
||||
shape: oldTierRequirement.shape,
|
||||
amount: oldTierRequirement.amount,
|
||||
});
|
||||
}
|
||||
}
|
||||
currentTierRequirements.push(
|
||||
...originalRequired.map(req => ({
|
||||
amount: req.amount,
|
||||
shape: req.shape,
|
||||
}))
|
||||
);
|
||||
currentTierRequirements.forEach(tier => {
|
||||
tier.amount = findNiceIntegerValue(tier.amount * tierGrowth);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// VALIDATE
|
||||
if (G_IS_DEV) {
|
||||
for (const upgradeId in upgrades) {
|
||||
upgrades[upgradeId].forEach(tier => {
|
||||
tier.required.forEach(({ shape }) => {
|
||||
try {
|
||||
ShapeDefinition.fromShortKey(shape);
|
||||
} catch (ex) {
|
||||
throw new Error("Invalid upgrade goal: '" + ex + "' for shape" + shape);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return upgrades;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the level definitions
|
||||
* @param {boolean} limitedVersion
|
||||
*/
|
||||
export function generateLevelDefinitions(limitedVersion = false) {
|
||||
const levelDefinitions = [
|
||||
// 1
|
||||
// Circle
|
||||
{
|
||||
shape: "CuCuCuCu", // belts t1
|
||||
required: 30,
|
||||
reward: enumHubGoalRewards.reward_cutter_and_trash,
|
||||
},
|
||||
|
||||
// 2
|
||||
// Cutter
|
||||
{
|
||||
shape: "----CuCu", //
|
||||
required: 40,
|
||||
reward: enumHubGoalRewards.no_reward,
|
||||
},
|
||||
|
||||
// 3
|
||||
// Rectangle
|
||||
{
|
||||
shape: "RuRuRuRu", // miners t1
|
||||
required: 70,
|
||||
reward: enumHubGoalRewards.reward_balancer,
|
||||
},
|
||||
|
||||
// 4
|
||||
{
|
||||
shape: "RuRu----", // processors t2
|
||||
required: 70,
|
||||
reward: enumHubGoalRewards.reward_rotater,
|
||||
},
|
||||
|
||||
// 5
|
||||
// Rotater
|
||||
{
|
||||
shape: "Cu----Cu", // belts t2
|
||||
required: 170,
|
||||
reward: enumHubGoalRewards.reward_tunnel,
|
||||
},
|
||||
|
||||
// 6
|
||||
{
|
||||
shape: "Cu------", // miners t2
|
||||
required: 270,
|
||||
reward: enumHubGoalRewards.reward_painter,
|
||||
},
|
||||
|
||||
// 7
|
||||
// Painter
|
||||
{
|
||||
shape: "CrCrCrCr", // unused
|
||||
required: 300,
|
||||
reward: enumHubGoalRewards.reward_rotater_ccw,
|
||||
},
|
||||
|
||||
// 8
|
||||
{
|
||||
shape: "RbRb----", // painter t2
|
||||
required: 480,
|
||||
reward: enumHubGoalRewards.reward_mixer,
|
||||
},
|
||||
|
||||
// 9
|
||||
// Mixing (purple)
|
||||
{
|
||||
shape: "CpCpCpCp", // belts t3
|
||||
required: 600,
|
||||
reward: enumHubGoalRewards.reward_merger,
|
||||
},
|
||||
|
||||
// 10
|
||||
// STACKER: Star shape + cyan
|
||||
{
|
||||
shape: "ScScScSc", // miners t3
|
||||
required: 800,
|
||||
reward: enumHubGoalRewards.reward_stacker,
|
||||
},
|
||||
|
||||
// 11
|
||||
// Chainable miner
|
||||
{
|
||||
shape: "CgScScCg", // processors t3
|
||||
required: 1000,
|
||||
reward: enumHubGoalRewards.reward_miner_chainable,
|
||||
},
|
||||
|
||||
// 12
|
||||
// Blueprints
|
||||
{
|
||||
shape: "CbCbCbRb:CwCwCwCw",
|
||||
required: 1000,
|
||||
reward: enumHubGoalRewards.reward_blueprints,
|
||||
},
|
||||
|
||||
// 13
|
||||
// Tunnel Tier 2
|
||||
{
|
||||
shape: "RpRpRpRp:CwCwCwCw", // painting t3
|
||||
required: 3800,
|
||||
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
|
||||
},
|
||||
|
||||
// DEMO STOPS HERE
|
||||
...(limitedVersion
|
||||
? [
|
||||
{
|
||||
shape: "RpRpRpRp:CwCwCwCw",
|
||||
required: 0,
|
||||
reward: enumHubGoalRewards.reward_demo_end,
|
||||
},
|
||||
]
|
||||
: [
|
||||
// 14
|
||||
// Belt reader
|
||||
{
|
||||
shape: "--Cg----:--Cr----", // unused
|
||||
required: 16, // Per second!
|
||||
reward: enumHubGoalRewards.reward_belt_reader,
|
||||
throughputOnly: true,
|
||||
},
|
||||
|
||||
// 15
|
||||
// Storage
|
||||
{
|
||||
shape: "SrSrSrSr:CyCyCyCy", // unused
|
||||
required: 10000,
|
||||
reward: enumHubGoalRewards.reward_storage,
|
||||
},
|
||||
|
||||
// 16
|
||||
// Quad Cutter
|
||||
{
|
||||
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
|
||||
required: 6000,
|
||||
reward: enumHubGoalRewards.reward_cutter_quad,
|
||||
},
|
||||
|
||||
// 17
|
||||
// Double painter
|
||||
{
|
||||
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
|
||||
required: 20000,
|
||||
reward: enumHubGoalRewards.reward_painter_double,
|
||||
},
|
||||
|
||||
// 18
|
||||
// Rotater (180deg)
|
||||
{
|
||||
shape: "Sg----Sg:CgCgCgCg:--CyCy--", // unused
|
||||
required: 20000,
|
||||
reward: enumHubGoalRewards.reward_rotater_180,
|
||||
},
|
||||
|
||||
// 19
|
||||
// Compact splitter
|
||||
{
|
||||
shape: "CpRpCp--:SwSwSwSw",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_splitter,
|
||||
},
|
||||
|
||||
// 20
|
||||
// WIRES
|
||||
{
|
||||
shape: finalGameShape,
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_wires_painter_and_levers,
|
||||
},
|
||||
|
||||
// 21
|
||||
// Filter
|
||||
{
|
||||
shape: "CrCwCrCw:CwCrCwCr:CrCwCrCw:CwCrCwCr",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_filter,
|
||||
},
|
||||
|
||||
// 22
|
||||
// Constant signal
|
||||
{
|
||||
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_constant_signal,
|
||||
},
|
||||
|
||||
// 23
|
||||
// Display
|
||||
{
|
||||
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_display,
|
||||
},
|
||||
|
||||
// 24 Logic gates
|
||||
{
|
||||
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_logic_gates,
|
||||
},
|
||||
|
||||
// 25 Virtual Processing
|
||||
{
|
||||
shape: "Rg--Rg--:CwRwCwRw:--Rg--Rg",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_virtual_processing,
|
||||
},
|
||||
|
||||
// 26 Freeplay
|
||||
{
|
||||
shape: "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw",
|
||||
required: 50000,
|
||||
reward: enumHubGoalRewards.reward_freeplay,
|
||||
},
|
||||
]),
|
||||
];
|
||||
|
||||
if (G_IS_DEV) {
|
||||
levelDefinitions.forEach(({ shape }) => {
|
||||
try {
|
||||
ShapeDefinition.fromShortKey(shape);
|
||||
} catch (ex) {
|
||||
throw new Error("Invalid tutorial goal: '" + ex + "' for shape" + shape);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return levelDefinitions;
|
||||
}
|
||||
|
||||
const fullVersionUpgrades = generateUpgrades(false);
|
||||
const demoVersionUpgrades = generateUpgrades(true);
|
||||
|
||||
const fullVersionLevels = generateLevelDefinitions(false);
|
||||
const demoVersionLevels = generateLevelDefinitions(true);
|
||||
|
||||
export class RegularGameMode extends GameMode {
|
||||
constructor(root) {
|
||||
super(root);
|
||||
}
|
||||
|
||||
getUpgrades() {
|
||||
return this.root.app.restrictionMgr.getHasExtendedUpgrades()
|
||||
? fullVersionUpgrades
|
||||
: demoVersionUpgrades;
|
||||
}
|
||||
|
||||
getIsFreeplayAvailable() {
|
||||
return this.root.app.restrictionMgr.getHasExtendedLevelsAndFreeplay();
|
||||
}
|
||||
|
||||
getBlueprintShapeKey() {
|
||||
return blueprintShape;
|
||||
}
|
||||
|
||||
getLevelDefinitions() {
|
||||
return this.root.app.restrictionMgr.getHasExtendedLevelsAndFreeplay()
|
||||
? fullVersionLevels
|
||||
: demoVersionLevels;
|
||||
}
|
||||
}
|
||||
@ -1,221 +1,225 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import { Signal } from "../core/signal";
|
||||
import { RandomNumberGenerator } from "../core/rng";
|
||||
import { createLogger } from "../core/logging";
|
||||
|
||||
// Type hints
|
||||
/* typehints:start */
|
||||
import { GameTime } from "./time/game_time";
|
||||
import { EntityManager } from "./entity_manager";
|
||||
import { GameSystemManager } from "./game_system_manager";
|
||||
import { GameHUD } from "./hud/hud";
|
||||
import { MapView } from "./map_view";
|
||||
import { Camera } from "./camera";
|
||||
import { InGameState } from "../states/ingame";
|
||||
import { AutomaticSave } from "./automatic_save";
|
||||
import { Application } from "../application";
|
||||
import { SoundProxy } from "./sound_proxy";
|
||||
import { Savegame } from "../savegame/savegame";
|
||||
import { GameLogic } from "./logic";
|
||||
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
||||
import { HubGoals } from "./hub_goals";
|
||||
import { BufferMaintainer } from "../core/buffer_maintainer";
|
||||
import { ProductionAnalytics } from "./production_analytics";
|
||||
import { Entity } from "./entity";
|
||||
import { ShapeDefinition } from "./shape_definition";
|
||||
import { BaseItem } from "./base_item";
|
||||
import { DynamicTickrate } from "./dynamic_tickrate";
|
||||
import { KeyActionMapper } from "./key_action_mapper";
|
||||
import { Vector } from "../core/vector";
|
||||
/* typehints:end */
|
||||
|
||||
const logger = createLogger("game/root");
|
||||
|
||||
/** @type {Array<Layer>} */
|
||||
export const layers = ["regular", "wires"];
|
||||
|
||||
/**
|
||||
* The game root is basically the whole game state at a given point,
|
||||
* combining all important classes. We don't have globals, but this
|
||||
* class is passed to almost all game classes.
|
||||
*/
|
||||
export class GameRoot {
|
||||
/**
|
||||
* Constructs a new game root
|
||||
* @param {Application} app
|
||||
*/
|
||||
constructor(app) {
|
||||
this.app = app;
|
||||
|
||||
/** @type {Savegame} */
|
||||
this.savegame = null;
|
||||
|
||||
/** @type {InGameState} */
|
||||
this.gameState = null;
|
||||
|
||||
/** @type {KeyActionMapper} */
|
||||
this.keyMapper = null;
|
||||
|
||||
// Store game dimensions
|
||||
this.gameWidth = 500;
|
||||
this.gameHeight = 500;
|
||||
|
||||
// Stores whether the current session is a fresh game (true), or was continued (false)
|
||||
/** @type {boolean} */
|
||||
this.gameIsFresh = true;
|
||||
|
||||
// Stores whether the logic is already initialized
|
||||
/** @type {boolean} */
|
||||
this.logicInitialized = false;
|
||||
|
||||
// Stores whether the game is already initialized, that is, all systems etc have been created
|
||||
/** @type {boolean} */
|
||||
this.gameInitialized = false;
|
||||
|
||||
/**
|
||||
* Whether a bulk operation is running
|
||||
*/
|
||||
this.bulkOperationRunning = false;
|
||||
|
||||
//////// Other properties ///////
|
||||
|
||||
/** @type {Camera} */
|
||||
this.camera = null;
|
||||
|
||||
/** @type {HTMLCanvasElement} */
|
||||
this.canvas = null;
|
||||
|
||||
/** @type {CanvasRenderingContext2D} */
|
||||
this.context = null;
|
||||
|
||||
/** @type {MapView} */
|
||||
this.map = null;
|
||||
|
||||
/** @type {GameLogic} */
|
||||
this.logic = null;
|
||||
|
||||
/** @type {EntityManager} */
|
||||
this.entityMgr = null;
|
||||
|
||||
/** @type {GameHUD} */
|
||||
this.hud = null;
|
||||
|
||||
/** @type {GameSystemManager} */
|
||||
this.systemMgr = null;
|
||||
|
||||
/** @type {GameTime} */
|
||||
this.time = null;
|
||||
|
||||
/** @type {HubGoals} */
|
||||
this.hubGoals = null;
|
||||
|
||||
/** @type {BufferMaintainer} */
|
||||
this.buffers = null;
|
||||
|
||||
/** @type {AutomaticSave} */
|
||||
this.automaticSave = null;
|
||||
|
||||
/** @type {SoundProxy} */
|
||||
this.soundProxy = null;
|
||||
|
||||
/** @type {ShapeDefinitionManager} */
|
||||
this.shapeDefinitionMgr = null;
|
||||
|
||||
/** @type {ProductionAnalytics} */
|
||||
this.productionAnalytics = null;
|
||||
|
||||
/** @type {DynamicTickrate} */
|
||||
this.dynamicTickrate = null;
|
||||
|
||||
/** @type {Layer} */
|
||||
this.currentLayer = "regular";
|
||||
|
||||
this.signals = {
|
||||
// Entities
|
||||
entityManuallyPlaced: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityAdded: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityChanged: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityGotNewComponent: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityComponentRemoved: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityQueuedForDestroy: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityDestroyed: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
|
||||
// Global
|
||||
resized: /** @type {TypedSignal<[number, number]>} */ (new Signal()),
|
||||
readyToRender: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||
aboutToDestruct: /** @type {TypedSignal<[]>} */ new Signal(),
|
||||
|
||||
// Game Hooks
|
||||
gameSaved: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got saved
|
||||
gameRestored: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got restored
|
||||
|
||||
gameFrameStarted: /** @type {TypedSignal<[]>} */ (new Signal()), // New frame
|
||||
|
||||
storyGoalCompleted: /** @type {TypedSignal<[number, string]>} */ (new Signal()),
|
||||
upgradePurchased: /** @type {TypedSignal<[string]>} */ (new Signal()),
|
||||
|
||||
// Called right after game is initialized
|
||||
postLoadHook: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||
|
||||
shapeDelivered: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()),
|
||||
itemProduced: /** @type {TypedSignal<[BaseItem]>} */ (new Signal()),
|
||||
|
||||
bulkOperationFinished: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||
|
||||
editModeChanged: /** @type {TypedSignal<[Layer]>} */ (new Signal()),
|
||||
|
||||
// Called to check if an entity can be placed, second parameter is an additional offset.
|
||||
// Use to introduce additional placement checks
|
||||
prePlacementCheck: /** @type {TypedSignal<[Entity, Vector]>} */ (new Signal()),
|
||||
|
||||
// Called before actually placing an entity, use to perform additional logic
|
||||
// for freeing space before actually placing.
|
||||
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
};
|
||||
|
||||
// RNG's
|
||||
/** @type {Object.<string, Object.<string, RandomNumberGenerator>>} */
|
||||
this.rngs = {};
|
||||
|
||||
// Work queue
|
||||
this.queue = {
|
||||
requireRedraw: false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructs the game root
|
||||
*/
|
||||
destruct() {
|
||||
logger.log("destructing root");
|
||||
this.signals.aboutToDestruct.dispatch();
|
||||
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the whole root and removes all properties
|
||||
*/
|
||||
reset() {
|
||||
if (this.signals) {
|
||||
// Destruct all signals
|
||||
for (let i = 0; i < this.signals.length; ++i) {
|
||||
this.signals[i].removeAll();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hud) {
|
||||
this.hud.cleanup();
|
||||
}
|
||||
if (this.camera) {
|
||||
this.camera.cleanup();
|
||||
}
|
||||
|
||||
// Finally free all properties
|
||||
for (let prop in this) {
|
||||
if (this.hasOwnProperty(prop)) {
|
||||
delete this[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* eslint-disable no-unused-vars */
|
||||
import { Signal } from "../core/signal";
|
||||
import { RandomNumberGenerator } from "../core/rng";
|
||||
import { createLogger } from "../core/logging";
|
||||
|
||||
// Type hints
|
||||
/* typehints:start */
|
||||
import { GameTime } from "./time/game_time";
|
||||
import { EntityManager } from "./entity_manager";
|
||||
import { GameSystemManager } from "./game_system_manager";
|
||||
import { GameHUD } from "./hud/hud";
|
||||
import { MapView } from "./map_view";
|
||||
import { Camera } from "./camera";
|
||||
import { InGameState } from "../states/ingame";
|
||||
import { AutomaticSave } from "./automatic_save";
|
||||
import { Application } from "../application";
|
||||
import { SoundProxy } from "./sound_proxy";
|
||||
import { Savegame } from "../savegame/savegame";
|
||||
import { GameLogic } from "./logic";
|
||||
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
||||
import { HubGoals } from "./hub_goals";
|
||||
import { BufferMaintainer } from "../core/buffer_maintainer";
|
||||
import { ProductionAnalytics } from "./production_analytics";
|
||||
import { Entity } from "./entity";
|
||||
import { ShapeDefinition } from "./shape_definition";
|
||||
import { BaseItem } from "./base_item";
|
||||
import { DynamicTickrate } from "./dynamic_tickrate";
|
||||
import { KeyActionMapper } from "./key_action_mapper";
|
||||
import { Vector } from "../core/vector";
|
||||
import { GameMode } from "./game_mode";
|
||||
/* typehints:end */
|
||||
|
||||
const logger = createLogger("game/root");
|
||||
|
||||
/** @type {Array<Layer>} */
|
||||
export const layers = ["regular", "wires"];
|
||||
|
||||
/**
|
||||
* The game root is basically the whole game state at a given point,
|
||||
* combining all important classes. We don't have globals, but this
|
||||
* class is passed to almost all game classes.
|
||||
*/
|
||||
export class GameRoot {
|
||||
/**
|
||||
* Constructs a new game root
|
||||
* @param {Application} app
|
||||
*/
|
||||
constructor(app) {
|
||||
this.app = app;
|
||||
|
||||
/** @type {Savegame} */
|
||||
this.savegame = null;
|
||||
|
||||
/** @type {InGameState} */
|
||||
this.gameState = null;
|
||||
|
||||
/** @type {KeyActionMapper} */
|
||||
this.keyMapper = null;
|
||||
|
||||
// Store game dimensions
|
||||
this.gameWidth = 500;
|
||||
this.gameHeight = 500;
|
||||
|
||||
// Stores whether the current session is a fresh game (true), or was continued (false)
|
||||
/** @type {boolean} */
|
||||
this.gameIsFresh = true;
|
||||
|
||||
// Stores whether the logic is already initialized
|
||||
/** @type {boolean} */
|
||||
this.logicInitialized = false;
|
||||
|
||||
// Stores whether the game is already initialized, that is, all systems etc have been created
|
||||
/** @type {boolean} */
|
||||
this.gameInitialized = false;
|
||||
|
||||
/**
|
||||
* Whether a bulk operation is running
|
||||
*/
|
||||
this.bulkOperationRunning = false;
|
||||
|
||||
//////// Other properties ///////
|
||||
|
||||
/** @type {Camera} */
|
||||
this.camera = null;
|
||||
|
||||
/** @type {HTMLCanvasElement} */
|
||||
this.canvas = null;
|
||||
|
||||
/** @type {CanvasRenderingContext2D} */
|
||||
this.context = null;
|
||||
|
||||
/** @type {MapView} */
|
||||
this.map = null;
|
||||
|
||||
/** @type {GameLogic} */
|
||||
this.logic = null;
|
||||
|
||||
/** @type {EntityManager} */
|
||||
this.entityMgr = null;
|
||||
|
||||
/** @type {GameHUD} */
|
||||
this.hud = null;
|
||||
|
||||
/** @type {GameSystemManager} */
|
||||
this.systemMgr = null;
|
||||
|
||||
/** @type {GameTime} */
|
||||
this.time = null;
|
||||
|
||||
/** @type {HubGoals} */
|
||||
this.hubGoals = null;
|
||||
|
||||
/** @type {BufferMaintainer} */
|
||||
this.buffers = null;
|
||||
|
||||
/** @type {AutomaticSave} */
|
||||
this.automaticSave = null;
|
||||
|
||||
/** @type {SoundProxy} */
|
||||
this.soundProxy = null;
|
||||
|
||||
/** @type {ShapeDefinitionManager} */
|
||||
this.shapeDefinitionMgr = null;
|
||||
|
||||
/** @type {ProductionAnalytics} */
|
||||
this.productionAnalytics = null;
|
||||
|
||||
/** @type {DynamicTickrate} */
|
||||
this.dynamicTickrate = null;
|
||||
|
||||
/** @type {Layer} */
|
||||
this.currentLayer = "regular";
|
||||
|
||||
/** @type {GameMode} */
|
||||
this.gameMode = null;
|
||||
|
||||
this.signals = {
|
||||
// Entities
|
||||
entityManuallyPlaced: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityAdded: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityChanged: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityGotNewComponent: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityComponentRemoved: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityQueuedForDestroy: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
entityDestroyed: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
|
||||
// Global
|
||||
resized: /** @type {TypedSignal<[number, number]>} */ (new Signal()),
|
||||
readyToRender: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||
aboutToDestruct: /** @type {TypedSignal<[]>} */ new Signal(),
|
||||
|
||||
// Game Hooks
|
||||
gameSaved: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got saved
|
||||
gameRestored: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got restored
|
||||
|
||||
gameFrameStarted: /** @type {TypedSignal<[]>} */ (new Signal()), // New frame
|
||||
|
||||
storyGoalCompleted: /** @type {TypedSignal<[number, string]>} */ (new Signal()),
|
||||
upgradePurchased: /** @type {TypedSignal<[string]>} */ (new Signal()),
|
||||
|
||||
// Called right after game is initialized
|
||||
postLoadHook: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||
|
||||
shapeDelivered: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()),
|
||||
itemProduced: /** @type {TypedSignal<[BaseItem]>} */ (new Signal()),
|
||||
|
||||
bulkOperationFinished: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||
|
||||
editModeChanged: /** @type {TypedSignal<[Layer]>} */ (new Signal()),
|
||||
|
||||
// Called to check if an entity can be placed, second parameter is an additional offset.
|
||||
// Use to introduce additional placement checks
|
||||
prePlacementCheck: /** @type {TypedSignal<[Entity, Vector]>} */ (new Signal()),
|
||||
|
||||
// Called before actually placing an entity, use to perform additional logic
|
||||
// for freeing space before actually placing.
|
||||
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
};
|
||||
|
||||
// RNG's
|
||||
/** @type {Object.<string, Object.<string, RandomNumberGenerator>>} */
|
||||
this.rngs = {};
|
||||
|
||||
// Work queue
|
||||
this.queue = {
|
||||
requireRedraw: false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructs the game root
|
||||
*/
|
||||
destruct() {
|
||||
logger.log("destructing root");
|
||||
this.signals.aboutToDestruct.dispatch();
|
||||
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the whole root and removes all properties
|
||||
*/
|
||||
reset() {
|
||||
if (this.signals) {
|
||||
// Destruct all signals
|
||||
for (let i = 0; i < this.signals.length; ++i) {
|
||||
this.signals[i].removeAll();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hud) {
|
||||
this.hud.cleanup();
|
||||
}
|
||||
if (this.camera) {
|
||||
this.camera.cleanup();
|
||||
}
|
||||
|
||||
// Finally free all properties
|
||||
for (let prop in this) {
|
||||
if (this.hasOwnProperty(prop)) {
|
||||
delete this[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
import { BOOL_FALSE_SINGLETON, BOOL_TRUE_SINGLETON } from "../items/boolean_item";
|
||||
import { COLOR_ITEM_SINGLETONS } from "../items/color_item";
|
||||
import { ShapeDefinition } from "../shape_definition";
|
||||
import { blueprintShape } from "../upgrades";
|
||||
|
||||
export class ConstantSignalSystem extends GameSystemWithFilter {
|
||||
constructor(root) {
|
||||
@ -64,7 +63,9 @@ export class ConstantSignalSystem extends GameSystemWithFilter {
|
||||
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(
|
||||
this.root.hubGoals.currentGoal.definition
|
||||
),
|
||||
this.root.shapeDefinitionMgr.getShapeItemFromShortKey(blueprintShape),
|
||||
this.root.shapeDefinitionMgr.getShapeItemFromShortKey(
|
||||
this.root.gameMode.getBlueprintShapeKey()
|
||||
),
|
||||
...this.root.hud.parts.pinnedShapes.pinnedShapes.map(key =>
|
||||
this.root.shapeDefinitionMgr.getShapeItemFromShortKey(key)
|
||||
),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { globalConfig, IS_DEMO } from "../../core/config";
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { smoothenDpi } from "../../core/dpi_manager";
|
||||
import { DrawParameters } from "../../core/draw_parameters";
|
||||
import { drawSpriteClipped } from "../../core/draw_utils";
|
||||
|
||||
@ -154,22 +154,18 @@ export class LogicGateSystem extends GameSystemWithFilter {
|
||||
|
||||
/**
|
||||
* @param {Array<BaseItem|null>} parameters
|
||||
* @returns {[BaseItem, BaseItem]}
|
||||
* @returns {BaseItem}
|
||||
*/
|
||||
compute_ROTATE(parameters) {
|
||||
const item = parameters[0];
|
||||
if (!item || item.getItemType() !== "shape") {
|
||||
// Not a shape
|
||||
return [null, null];
|
||||
return null;
|
||||
}
|
||||
|
||||
const definition = /** @type {ShapeItem} */ (item).definition;
|
||||
const rotatedDefinitionCCW = this.root.shapeDefinitionMgr.shapeActionRotateCCW(definition);
|
||||
const rotatedDefinitionCW = this.root.shapeDefinitionMgr.shapeActionRotateCW(definition);
|
||||
return [
|
||||
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinitionCCW),
|
||||
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinitionCW),
|
||||
];
|
||||
return this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinitionCW);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
import { IS_DEMO } from "../core/config";
|
||||
import { ShapeDefinition } from "./shape_definition";
|
||||
import { finalGameShape } from "./upgrades";
|
||||
|
||||
/**
|
||||
* Don't forget to also update tutorial_goals_mappings.js as well as the translations!
|
||||
* @enum {string}
|
||||
@ -40,229 +36,3 @@ export const enumHubGoalRewards = {
|
||||
no_reward: "no_reward",
|
||||
no_reward_freeplay: "no_reward_freeplay",
|
||||
};
|
||||
|
||||
export const tutorialGoals = [
|
||||
// 1
|
||||
// Circle
|
||||
{
|
||||
shape: "CuCuCuCu", // belts t1
|
||||
required: 30,
|
||||
reward: enumHubGoalRewards.reward_cutter_and_trash,
|
||||
},
|
||||
|
||||
// 2
|
||||
// Cutter
|
||||
{
|
||||
shape: "----CuCu", //
|
||||
required: 40,
|
||||
reward: enumHubGoalRewards.no_reward,
|
||||
},
|
||||
|
||||
// 3
|
||||
// Rectangle
|
||||
{
|
||||
shape: "RuRuRuRu", // miners t1
|
||||
required: 70,
|
||||
reward: enumHubGoalRewards.reward_balancer,
|
||||
},
|
||||
|
||||
// 4
|
||||
{
|
||||
shape: "RuRu----", // processors t2
|
||||
required: 70,
|
||||
reward: enumHubGoalRewards.reward_rotater,
|
||||
},
|
||||
|
||||
// 5
|
||||
// Rotater
|
||||
{
|
||||
shape: "Cu----Cu", // belts t2
|
||||
required: 170,
|
||||
reward: enumHubGoalRewards.reward_tunnel,
|
||||
},
|
||||
|
||||
// 6
|
||||
{
|
||||
shape: "Cu------", // miners t2
|
||||
required: 270,
|
||||
reward: enumHubGoalRewards.reward_painter,
|
||||
},
|
||||
|
||||
// 7
|
||||
// Painter
|
||||
{
|
||||
shape: "CrCrCrCr", // unused
|
||||
required: 300,
|
||||
reward: enumHubGoalRewards.reward_rotater_ccw,
|
||||
},
|
||||
|
||||
// 8
|
||||
{
|
||||
shape: "RbRb----", // painter t2
|
||||
required: 480,
|
||||
reward: enumHubGoalRewards.reward_mixer,
|
||||
},
|
||||
|
||||
// 9
|
||||
// Mixing (purple)
|
||||
{
|
||||
shape: "CpCpCpCp", // belts t3
|
||||
required: 600,
|
||||
reward: enumHubGoalRewards.reward_merger,
|
||||
},
|
||||
|
||||
// 10
|
||||
// STACKER: Star shape + cyan
|
||||
{
|
||||
shape: "ScScScSc", // miners t3
|
||||
required: 800,
|
||||
reward: enumHubGoalRewards.reward_stacker,
|
||||
},
|
||||
|
||||
// 11
|
||||
// Chainable miner
|
||||
{
|
||||
shape: "CgScScCg", // processors t3
|
||||
required: 1000,
|
||||
reward: enumHubGoalRewards.reward_miner_chainable,
|
||||
},
|
||||
|
||||
// 12
|
||||
// Blueprints
|
||||
{
|
||||
shape: "CbCbCbRb:CwCwCwCw",
|
||||
required: 1000,
|
||||
reward: enumHubGoalRewards.reward_blueprints,
|
||||
},
|
||||
|
||||
// 13
|
||||
// Tunnel Tier 2
|
||||
{
|
||||
shape: "RpRpRpRp:CwCwCwCw", // painting t3
|
||||
required: 3800,
|
||||
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
|
||||
},
|
||||
|
||||
// DEMO STOPS HERE
|
||||
...(IS_DEMO
|
||||
? [
|
||||
{
|
||||
shape: "RpRpRpRp:CwCwCwCw",
|
||||
required: 0,
|
||||
reward: enumHubGoalRewards.reward_demo_end,
|
||||
},
|
||||
]
|
||||
: [
|
||||
// 14
|
||||
// Belt reader
|
||||
{
|
||||
shape: "--Cg----:--Cr----", // unused
|
||||
required: 16, // Per second!
|
||||
reward: enumHubGoalRewards.reward_belt_reader,
|
||||
throughputOnly: true,
|
||||
},
|
||||
|
||||
// 15
|
||||
// Storage
|
||||
{
|
||||
shape: "SrSrSrSr:CyCyCyCy", // unused
|
||||
required: 10000,
|
||||
reward: enumHubGoalRewards.reward_storage,
|
||||
},
|
||||
|
||||
// 16
|
||||
// Quad Cutter
|
||||
{
|
||||
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
|
||||
required: 6000,
|
||||
reward: enumHubGoalRewards.reward_cutter_quad,
|
||||
},
|
||||
|
||||
// 17
|
||||
// Double painter
|
||||
{
|
||||
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
|
||||
required: 20000,
|
||||
reward: enumHubGoalRewards.reward_painter_double,
|
||||
},
|
||||
|
||||
// 18
|
||||
// Rotater (180deg)
|
||||
{
|
||||
shape: "Sg----Sg:CgCgCgCg:--CyCy--", // unused
|
||||
required: 20000,
|
||||
reward: enumHubGoalRewards.reward_rotater_180,
|
||||
},
|
||||
|
||||
// 19
|
||||
// Compact splitter
|
||||
{
|
||||
shape: "CpRpCp--:SwSwSwSw",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_splitter,
|
||||
},
|
||||
|
||||
// 20
|
||||
// WIRES
|
||||
{
|
||||
shape: finalGameShape,
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_wires_painter_and_levers,
|
||||
},
|
||||
|
||||
// 21
|
||||
// Filter
|
||||
{
|
||||
shape: "CrCwCrCw:CwCrCwCr:CrCwCrCw:CwCrCwCr",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_filter,
|
||||
},
|
||||
|
||||
// 22
|
||||
// Constant signal
|
||||
{
|
||||
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_constant_signal,
|
||||
},
|
||||
|
||||
// 23
|
||||
// Display
|
||||
{
|
||||
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_display,
|
||||
},
|
||||
|
||||
// 24 Logic gates
|
||||
{
|
||||
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_logic_gates,
|
||||
},
|
||||
|
||||
// 25 Virtual Processing
|
||||
{
|
||||
shape: "Rg--Rg--:CwRwCwRw:--Rg--Rg",
|
||||
required: 25000,
|
||||
reward: enumHubGoalRewards.reward_virtual_processing,
|
||||
},
|
||||
|
||||
// 26 Freeplay
|
||||
{
|
||||
shape: "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw",
|
||||
required: 50000,
|
||||
reward: enumHubGoalRewards.reward_freeplay,
|
||||
},
|
||||
]),
|
||||
];
|
||||
|
||||
if (G_IS_DEV) {
|
||||
tutorialGoals.forEach(({ shape }) => {
|
||||
try {
|
||||
ShapeDefinition.fromShortKey(shape);
|
||||
} catch (ex) {
|
||||
throw new Error("Invalid tutorial goal: '" + ex + "' for shape" + shape);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,212 +0,0 @@
|
||||
import { IS_DEMO } from "../core/config";
|
||||
import { findNiceIntegerValue } from "../core/utils";
|
||||
import { ShapeDefinition } from "./shape_definition";
|
||||
|
||||
export const preparementShape = "CpRpCp--:SwSwSwSw";
|
||||
export const finalGameShape = "RuCw--Cw:----Ru--";
|
||||
export const rocketShape = "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw";
|
||||
export const blueprintShape = "CbCbCbRb:CwCwCwCw";
|
||||
|
||||
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 1, 1];
|
||||
|
||||
const numEndgameUpgrades = !IS_DEMO ? 20 - fixedImprovements.length - 1 : 0;
|
||||
|
||||
function generateEndgameUpgrades() {
|
||||
return new Array(numEndgameUpgrades).fill(null).map((_, i) => ({
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 30000 + i * 10000 },
|
||||
{ shape: finalGameShape, amount: 20000 + i * 5000 },
|
||||
{ shape: rocketShape, amount: 20000 + i * 5000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
}));
|
||||
}
|
||||
|
||||
for (let i = 0; i < numEndgameUpgrades; ++i) {
|
||||
fixedImprovements.push(0.1);
|
||||
}
|
||||
|
||||
/** @typedef {{
|
||||
* shape: string,
|
||||
* amount: number
|
||||
* }} UpgradeRequirement */
|
||||
|
||||
/** @typedef {{
|
||||
* required: Array<UpgradeRequirement>
|
||||
* improvement?: number,
|
||||
* excludePrevious?: boolean
|
||||
* }} TierRequirement */
|
||||
|
||||
/** @typedef {Array<TierRequirement>} UpgradeTiers */
|
||||
|
||||
/** @type {Object<string, UpgradeTiers>} */
|
||||
export const UPGRADES = {
|
||||
belt: [
|
||||
{
|
||||
required: [{ shape: "CuCuCuCu", amount: 60 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "--CuCu--", amount: 500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CpCpCpCp", amount: 1000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "SrSrSrSr:CyCyCyCy", amount: 6000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", amount: 25000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: preparementShape, amount: 25000 }],
|
||||
excludePrevious: true,
|
||||
},
|
||||
{
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 25000 },
|
||||
{ shape: finalGameShape, amount: 50000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
},
|
||||
...generateEndgameUpgrades(),
|
||||
],
|
||||
|
||||
miner: [
|
||||
{
|
||||
required: [{ shape: "RuRuRuRu", amount: 300 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "Cu------", amount: 800 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "ScScScSc", amount: 3500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CwCwCwCw:WbWbWbWb", amount: 23000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", amount: 50000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: preparementShape, amount: 25000 }],
|
||||
excludePrevious: true,
|
||||
},
|
||||
{
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 25000 },
|
||||
{ shape: finalGameShape, amount: 50000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
},
|
||||
...generateEndgameUpgrades(),
|
||||
],
|
||||
|
||||
processors: [
|
||||
{
|
||||
required: [{ shape: "SuSuSuSu", amount: 500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "RuRu----", amount: 600 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CgScScCg", amount: 3500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "CwCrCwCr:SgSgSgSg", amount: 25000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", amount: 50000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: preparementShape, amount: 25000 }],
|
||||
excludePrevious: true,
|
||||
},
|
||||
{
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 25000 },
|
||||
{ shape: finalGameShape, amount: 50000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
},
|
||||
...generateEndgameUpgrades(),
|
||||
],
|
||||
|
||||
painting: [
|
||||
{
|
||||
required: [{ shape: "RbRb----", amount: 600 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "WrWrWrWr", amount: 3800 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "RpRpRpRp:CwCwCwCw", amount: 6500 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp", amount: 25000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp:CwCwCwCw", amount: 50000 }],
|
||||
},
|
||||
{
|
||||
required: [{ shape: preparementShape, amount: 25000 }],
|
||||
excludePrevious: true,
|
||||
},
|
||||
{
|
||||
required: [
|
||||
{ shape: preparementShape, amount: 25000 },
|
||||
{ shape: finalGameShape, amount: 50000 },
|
||||
],
|
||||
excludePrevious: true,
|
||||
},
|
||||
...generateEndgameUpgrades(),
|
||||
],
|
||||
};
|
||||
|
||||
// Tiers need % of the previous tier as requirement too
|
||||
const tierGrowth = 2.5;
|
||||
|
||||
// Automatically generate tier levels
|
||||
for (const upgradeId in UPGRADES) {
|
||||
const upgradeTiers = UPGRADES[upgradeId];
|
||||
|
||||
let currentTierRequirements = [];
|
||||
for (let i = 0; i < upgradeTiers.length; ++i) {
|
||||
const tierHandle = upgradeTiers[i];
|
||||
tierHandle.improvement = fixedImprovements[i];
|
||||
const originalRequired = tierHandle.required.slice();
|
||||
|
||||
for (let k = currentTierRequirements.length - 1; k >= 0; --k) {
|
||||
const oldTierRequirement = currentTierRequirements[k];
|
||||
if (!tierHandle.excludePrevious) {
|
||||
tierHandle.required.unshift({
|
||||
shape: oldTierRequirement.shape,
|
||||
amount: oldTierRequirement.amount,
|
||||
});
|
||||
}
|
||||
}
|
||||
currentTierRequirements.push(
|
||||
...originalRequired.map(req => ({
|
||||
amount: req.amount,
|
||||
shape: req.shape,
|
||||
}))
|
||||
);
|
||||
currentTierRequirements.forEach(tier => {
|
||||
tier.amount = findNiceIntegerValue(tier.amount * tierGrowth);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// VALIDATE
|
||||
if (G_IS_DEV) {
|
||||
for (const upgradeId in UPGRADES) {
|
||||
UPGRADES[upgradeId].forEach(tier => {
|
||||
tier.required.forEach(({ shape }) => {
|
||||
try {
|
||||
ShapeDefinition.fromShortKey(shape);
|
||||
} catch (ex) {
|
||||
throw new Error("Invalid upgrade goal: '" + ex + "' for shape" + shape);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,12 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { createLogger } from "../../core/logging";
|
||||
import { queryParamOptions } from "../../core/query_parameters";
|
||||
import { BeltComponent } from "../../game/components/belt";
|
||||
import { StaticMapEntityComponent } from "../../game/components/static_map_entity";
|
||||
import { GameRoot } from "../../game/root";
|
||||
import { InGameState } from "../../states/ingame";
|
||||
import { GameAnalyticsInterface } from "../game_analytics";
|
||||
import { FILE_NOT_FOUND } from "../storage";
|
||||
import { blueprintShape, UPGRADES } from "../../game/upgrades";
|
||||
import { tutorialGoals } from "../../game/tutorial_goals";
|
||||
import { BeltComponent } from "../../game/components/belt";
|
||||
import { StaticMapEntityComponent } from "../../game/components/static_map_entity";
|
||||
import { queryParamOptions } from "../../core/query_parameters";
|
||||
|
||||
const logger = createLogger("game_analytics");
|
||||
|
||||
@ -190,23 +188,26 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
|
||||
|
||||
/**
|
||||
* Returns true if the shape is interesting
|
||||
* @param {GameRoot} root
|
||||
* @param {string} key
|
||||
*/
|
||||
isInterestingShape(key) {
|
||||
if (key === blueprintShape) {
|
||||
isInterestingShape(root, key) {
|
||||
if (key === root.gameMode.getBlueprintShapeKey()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if its a story goal
|
||||
for (let i = 0; i < tutorialGoals.length; ++i) {
|
||||
if (key === tutorialGoals[i].shape) {
|
||||
const levels = root.gameMode.getLevelDefinitions();
|
||||
for (let i = 0; i < levels.length; ++i) {
|
||||
if (key === levels[i].shape) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if its required to unlock an upgrade
|
||||
for (const upgradeKey in UPGRADES) {
|
||||
const upgradeTiers = UPGRADES[upgradeKey];
|
||||
const upgrades = root.gameMode.getUpgrades();
|
||||
for (const upgradeKey in upgrades) {
|
||||
const upgradeTiers = upgrades[upgradeKey];
|
||||
for (let i = 0; i < upgradeTiers.length; ++i) {
|
||||
const tier = upgradeTiers[i];
|
||||
const required = tier.required;
|
||||
@ -226,7 +227,9 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
|
||||
* @param {GameRoot} root
|
||||
*/
|
||||
generateGameDump(root) {
|
||||
const shapeIds = Object.keys(root.hubGoals.storedShapes).filter(this.isInterestingShape.bind(this));
|
||||
const shapeIds = Object.keys(root.hubGoals.storedShapes).filter(key =>
|
||||
this.isInterestingShape(root, key)
|
||||
);
|
||||
let shapes = {};
|
||||
for (let i = 0; i < shapeIds.length; ++i) {
|
||||
shapes[shapeIds[i]] = root.hubGoals.storedShapes[shapeIds[i]];
|
||||
|
||||
@ -1,214 +1,202 @@
|
||||
import { globalConfig, IS_DEMO, IS_MOBILE } from "../../core/config";
|
||||
import { createLogger } from "../../core/logging";
|
||||
import { queryParamOptions } from "../../core/query_parameters";
|
||||
import { clamp } from "../../core/utils";
|
||||
import { GamedistributionAdProvider } from "../ad_providers/gamedistribution";
|
||||
import { NoAdProvider } from "../ad_providers/no_ad_provider";
|
||||
import { PlatformWrapperInterface } from "../wrapper";
|
||||
import { StorageImplBrowser } from "./storage";
|
||||
import { StorageImplBrowserIndexedDB } from "./storage_indexed_db";
|
||||
|
||||
const logger = createLogger("platform/browser");
|
||||
|
||||
export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
||||
initialize() {
|
||||
this.recaptchaTokenCallback = null;
|
||||
|
||||
this.embedProvider = {
|
||||
id: "shapezio-website",
|
||||
adProvider: NoAdProvider,
|
||||
iframed: false,
|
||||
externalLinks: true,
|
||||
iogLink: true,
|
||||
unlimitedSavegames: IS_DEMO ? false : true,
|
||||
showDemoBadge: IS_DEMO,
|
||||
};
|
||||
|
||||
if (!G_IS_STANDALONE && queryParamOptions.embedProvider) {
|
||||
const providerId = queryParamOptions.embedProvider;
|
||||
this.embedProvider.iframed = true;
|
||||
this.embedProvider.iogLink = false;
|
||||
|
||||
switch (providerId) {
|
||||
case "armorgames": {
|
||||
this.embedProvider.id = "armorgames";
|
||||
break;
|
||||
}
|
||||
|
||||
case "iogames.space": {
|
||||
this.embedProvider.id = "iogames.space";
|
||||
this.embedProvider.iogLink = true;
|
||||
this.embedProvider.unlimitedSavegames = true;
|
||||
this.embedProvider.showDemoBadge = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case "miniclip": {
|
||||
this.embedProvider.id = "miniclip";
|
||||
break;
|
||||
}
|
||||
|
||||
case "gamedistribution": {
|
||||
this.embedProvider.id = "gamedistribution";
|
||||
this.embedProvider.externalLinks = false;
|
||||
this.embedProvider.adProvider = GamedistributionAdProvider;
|
||||
break;
|
||||
}
|
||||
|
||||
case "kongregate": {
|
||||
this.embedProvider.id = "kongregate";
|
||||
break;
|
||||
}
|
||||
|
||||
case "crazygames": {
|
||||
this.embedProvider.id = "crazygames";
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.error("Got unsupported embed provider:", providerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.log("Embed provider:", this.embedProvider.id);
|
||||
|
||||
return this.detectStorageImplementation()
|
||||
.then(() => this.initializeAdProvider())
|
||||
.then(() => super.initialize());
|
||||
}
|
||||
|
||||
detectStorageImplementation() {
|
||||
return new Promise(resolve => {
|
||||
logger.log("Detecting storage");
|
||||
|
||||
if (!window.indexedDB) {
|
||||
logger.log("Indexed DB not supported");
|
||||
this.app.storage = new StorageImplBrowser(this.app);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// Try accessing the indexedb
|
||||
let request;
|
||||
try {
|
||||
request = window.indexedDB.open("indexeddb_feature_detection", 1);
|
||||
} catch (ex) {
|
||||
logger.warn("Error while opening indexed db:", ex);
|
||||
this.app.storage = new StorageImplBrowser(this.app);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
request.onerror = err => {
|
||||
logger.log("Indexed DB can *not* be accessed: ", err);
|
||||
logger.log("Using fallback to local storage");
|
||||
this.app.storage = new StorageImplBrowser(this.app);
|
||||
resolve();
|
||||
};
|
||||
request.onsuccess = () => {
|
||||
logger.log("Indexed DB *can* be accessed");
|
||||
this.app.storage = new StorageImplBrowserIndexedDB(this.app);
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getHasUnlimitedSavegames() {
|
||||
return this.embedProvider.unlimitedSavegames;
|
||||
}
|
||||
|
||||
getShowDemoBadges() {
|
||||
return this.embedProvider.showDemoBadge;
|
||||
}
|
||||
|
||||
getId() {
|
||||
return "browser@" + this.embedProvider.id;
|
||||
}
|
||||
|
||||
getUiScale() {
|
||||
if (IS_MOBILE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const avgDims = Math.min(this.app.screenWidth, this.app.screenHeight);
|
||||
return clamp((avgDims / 1000.0) * 1.9, 0.1, 10);
|
||||
}
|
||||
|
||||
getSupportsRestart() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getTouchPanStrength() {
|
||||
return IS_MOBILE ? 1 : 0.5;
|
||||
}
|
||||
|
||||
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() {
|
||||
logger.log("Performing restart");
|
||||
window.location.reload(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects if there is an adblocker installed
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
detectAdblock() {
|
||||
return Promise.race([
|
||||
new Promise(resolve => {
|
||||
// If the request wasn't blocked within a very short period of time, this means
|
||||
// the adblocker is not active and the request was actually made -> ignore it then
|
||||
setTimeout(() => resolve(false), 30);
|
||||
}),
|
||||
new Promise(resolve => {
|
||||
fetch("https://googleads.g.doubleclick.net/pagead/id", {
|
||||
method: "HEAD",
|
||||
mode: "no-cors",
|
||||
})
|
||||
.then(res => {
|
||||
resolve(false);
|
||||
})
|
||||
.catch(err => {
|
||||
resolve(true);
|
||||
});
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
initializeAdProvider() {
|
||||
if (G_IS_DEV && !globalConfig.debug.testAds) {
|
||||
logger.log("Ads disabled in local environment");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// First, detect adblocker
|
||||
return this.detectAdblock().then(hasAdblocker => {
|
||||
if (hasAdblocker) {
|
||||
logger.log("Adblock detected");
|
||||
return;
|
||||
}
|
||||
|
||||
const adProvider = this.embedProvider.adProvider;
|
||||
this.app.adProvider = new adProvider(this.app);
|
||||
return this.app.adProvider.initialize().catch(err => {
|
||||
logger.error("Failed to initialize ad provider, disabling ads:", err);
|
||||
this.app.adProvider = new NoAdProvider(this.app);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exitApp() {
|
||||
// Can not exit app
|
||||
}
|
||||
}
|
||||
import { globalConfig, IS_MOBILE } from "../../core/config";
|
||||
import { createLogger } from "../../core/logging";
|
||||
import { queryParamOptions } from "../../core/query_parameters";
|
||||
import { clamp } from "../../core/utils";
|
||||
import { GamedistributionAdProvider } from "../ad_providers/gamedistribution";
|
||||
import { NoAdProvider } from "../ad_providers/no_ad_provider";
|
||||
import { PlatformWrapperInterface } from "../wrapper";
|
||||
import { StorageImplBrowser } from "./storage";
|
||||
import { StorageImplBrowserIndexedDB } from "./storage_indexed_db";
|
||||
|
||||
const logger = createLogger("platform/browser");
|
||||
|
||||
export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
||||
initialize() {
|
||||
this.recaptchaTokenCallback = null;
|
||||
|
||||
this.embedProvider = {
|
||||
id: "shapezio-website",
|
||||
adProvider: NoAdProvider,
|
||||
iframed: false,
|
||||
externalLinks: true,
|
||||
iogLink: true,
|
||||
};
|
||||
|
||||
if (!G_IS_STANDALONE && queryParamOptions.embedProvider) {
|
||||
const providerId = queryParamOptions.embedProvider;
|
||||
this.embedProvider.iframed = true;
|
||||
this.embedProvider.iogLink = false;
|
||||
|
||||
switch (providerId) {
|
||||
case "armorgames": {
|
||||
this.embedProvider.id = "armorgames";
|
||||
break;
|
||||
}
|
||||
|
||||
case "iogames.space": {
|
||||
this.embedProvider.id = "iogames.space";
|
||||
this.embedProvider.iogLink = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case "miniclip": {
|
||||
this.embedProvider.id = "miniclip";
|
||||
break;
|
||||
}
|
||||
|
||||
case "gamedistribution": {
|
||||
this.embedProvider.id = "gamedistribution";
|
||||
this.embedProvider.externalLinks = false;
|
||||
this.embedProvider.adProvider = GamedistributionAdProvider;
|
||||
break;
|
||||
}
|
||||
|
||||
case "kongregate": {
|
||||
this.embedProvider.id = "kongregate";
|
||||
break;
|
||||
}
|
||||
|
||||
case "crazygames": {
|
||||
this.embedProvider.id = "crazygames";
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.error("Got unsupported embed provider:", providerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.log("Embed provider:", this.embedProvider.id);
|
||||
|
||||
return this.detectStorageImplementation()
|
||||
.then(() => this.initializeAdProvider())
|
||||
.then(() => super.initialize());
|
||||
}
|
||||
|
||||
detectStorageImplementation() {
|
||||
return new Promise(resolve => {
|
||||
logger.log("Detecting storage");
|
||||
|
||||
if (!window.indexedDB) {
|
||||
logger.log("Indexed DB not supported");
|
||||
this.app.storage = new StorageImplBrowser(this.app);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// Try accessing the indexedb
|
||||
let request;
|
||||
try {
|
||||
request = window.indexedDB.open("indexeddb_feature_detection", 1);
|
||||
} catch (ex) {
|
||||
logger.warn("Error while opening indexed db:", ex);
|
||||
this.app.storage = new StorageImplBrowser(this.app);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
request.onerror = err => {
|
||||
logger.log("Indexed DB can *not* be accessed: ", err);
|
||||
logger.log("Using fallback to local storage");
|
||||
this.app.storage = new StorageImplBrowser(this.app);
|
||||
resolve();
|
||||
};
|
||||
request.onsuccess = () => {
|
||||
logger.log("Indexed DB *can* be accessed");
|
||||
this.app.storage = new StorageImplBrowserIndexedDB(this.app);
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getId() {
|
||||
return "browser@" + this.embedProvider.id;
|
||||
}
|
||||
|
||||
getUiScale() {
|
||||
if (IS_MOBILE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const avgDims = Math.min(this.app.screenWidth, this.app.screenHeight);
|
||||
return clamp((avgDims / 1000.0) * 1.9, 0.1, 10);
|
||||
}
|
||||
|
||||
getSupportsRestart() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getTouchPanStrength() {
|
||||
return IS_MOBILE ? 1 : 0.5;
|
||||
}
|
||||
|
||||
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() {
|
||||
logger.log("Performing restart");
|
||||
window.location.reload(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects if there is an adblocker installed
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
detectAdblock() {
|
||||
return Promise.race([
|
||||
new Promise(resolve => {
|
||||
// If the request wasn't blocked within a very short period of time, this means
|
||||
// the adblocker is not active and the request was actually made -> ignore it then
|
||||
setTimeout(() => resolve(false), 30);
|
||||
}),
|
||||
new Promise(resolve => {
|
||||
fetch("https://googleads.g.doubleclick.net/pagead/id", {
|
||||
method: "HEAD",
|
||||
mode: "no-cors",
|
||||
})
|
||||
.then(res => {
|
||||
resolve(false);
|
||||
})
|
||||
.catch(err => {
|
||||
resolve(true);
|
||||
});
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
initializeAdProvider() {
|
||||
if (G_IS_DEV && !globalConfig.debug.testAds) {
|
||||
logger.log("Ads disabled in local environment");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// First, detect adblocker
|
||||
return this.detectAdblock().then(hasAdblocker => {
|
||||
if (hasAdblocker) {
|
||||
logger.log("Adblock detected");
|
||||
return;
|
||||
}
|
||||
|
||||
const adProvider = this.embedProvider.adProvider;
|
||||
this.app.adProvider = new adProvider(this.app);
|
||||
return this.app.adProvider.initialize().catch(err => {
|
||||
logger.error("Failed to initialize ad provider, disabling ads:", err);
|
||||
this.app.adProvider = new NoAdProvider(this.app);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exitApp() {
|
||||
// Can not exit app
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,65 +1,57 @@
|
||||
import { PlatformWrapperImplBrowser } from "../browser/wrapper";
|
||||
import { getIPCRenderer } from "../../core/utils";
|
||||
import { createLogger } from "../../core/logging";
|
||||
import { StorageImplElectron } from "./storage";
|
||||
import { PlatformWrapperInterface } from "../wrapper";
|
||||
|
||||
const logger = createLogger("electron-wrapper");
|
||||
|
||||
export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
|
||||
initialize() {
|
||||
this.app.storage = new StorageImplElectron(this);
|
||||
return PlatformWrapperInterface.prototype.initialize.call(this);
|
||||
}
|
||||
|
||||
getId() {
|
||||
return "electron";
|
||||
}
|
||||
|
||||
getSupportsRestart() {
|
||||
return true;
|
||||
}
|
||||
|
||||
openExternalLink(url) {
|
||||
logger.log(this, "Opening external:", url);
|
||||
window.open(url, "about:blank");
|
||||
}
|
||||
|
||||
getSupportsAds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
getHasUnlimitedSavegames() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getShowDemoBadges() {
|
||||
return false;
|
||||
}
|
||||
|
||||
performRestart() {
|
||||
logger.log(this, "Performing restart");
|
||||
window.location.reload(true);
|
||||
}
|
||||
|
||||
initializeAdProvider() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
getSupportsFullscreen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
setFullscreen(flag) {
|
||||
getIPCRenderer().send("set-fullscreen", flag);
|
||||
}
|
||||
|
||||
getSupportsAppExit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
exitApp() {
|
||||
logger.log(this, "Sending app exit signal");
|
||||
getIPCRenderer().send("exit-app");
|
||||
}
|
||||
}
|
||||
import { PlatformWrapperImplBrowser } from "../browser/wrapper";
|
||||
import { getIPCRenderer } from "../../core/utils";
|
||||
import { createLogger } from "../../core/logging";
|
||||
import { StorageImplElectron } from "./storage";
|
||||
import { PlatformWrapperInterface } from "../wrapper";
|
||||
|
||||
const logger = createLogger("electron-wrapper");
|
||||
|
||||
export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
|
||||
initialize() {
|
||||
this.app.storage = new StorageImplElectron(this);
|
||||
return PlatformWrapperInterface.prototype.initialize.call(this);
|
||||
}
|
||||
|
||||
getId() {
|
||||
return "electron";
|
||||
}
|
||||
|
||||
getSupportsRestart() {
|
||||
return true;
|
||||
}
|
||||
|
||||
openExternalLink(url) {
|
||||
logger.log(this, "Opening external:", url);
|
||||
window.open(url, "about:blank");
|
||||
}
|
||||
|
||||
getSupportsAds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
performRestart() {
|
||||
logger.log(this, "Performing restart");
|
||||
window.location.reload(true);
|
||||
}
|
||||
|
||||
initializeAdProvider() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
getSupportsFullscreen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
setFullscreen(flag) {
|
||||
getIPCRenderer().send("set-fullscreen", flag);
|
||||
}
|
||||
|
||||
getSupportsAppExit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
exitApp() {
|
||||
logger.log(this, "Sending app exit signal");
|
||||
getIPCRenderer().send("exit-app");
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import { GameRoot } from "../game/root";
|
||||
|
||||
import { newEmptyMap, clamp } from "../core/utils";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { globalConfig, IS_DEMO } from "../core/config";
|
||||
import { globalConfig } from "../core/config";
|
||||
|
||||
const logger = createLogger("sound");
|
||||
|
||||
@ -29,7 +29,9 @@ export const SOUNDS = {
|
||||
};
|
||||
|
||||
export const MUSIC = {
|
||||
theme: IS_DEMO ? "theme-short" : "theme-full",
|
||||
// The theme always depends on the standalone only, even if running the full
|
||||
// version in the browser
|
||||
theme: G_IS_STANDALONE ? "theme-full" : "theme-short",
|
||||
menu: "menu",
|
||||
};
|
||||
|
||||
|
||||
@ -1,142 +1,131 @@
|
||||
/* typehints:start */
|
||||
import { Application } from "../application";
|
||||
/* typehints:end */
|
||||
|
||||
import { IS_MOBILE } from "../core/config";
|
||||
|
||||
export class PlatformWrapperInterface {
|
||||
constructor(app) {
|
||||
/** @type {Application} */
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/** @returns {string} */
|
||||
getId() {
|
||||
abstract;
|
||||
return "unknown-platform";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UI scale, called on every resize
|
||||
* @returns {number} */
|
||||
getUiScale() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
getSupportsRestart() {
|
||||
abstract;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user has unlimited savegames
|
||||
*/
|
||||
getHasUnlimitedSavegames() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getShowDemoBadges() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the strength of touch pans with the mouse
|
||||
*/
|
||||
getTouchPanStrength() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** @returns {Promise<void>} */
|
||||
initialize() {
|
||||
document.documentElement.classList.add("p-" + this.getId());
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should initialize the apps ad provider in case supported
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
initializeAdProvider() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return the minimum supported zoom level
|
||||
* @returns {number}
|
||||
*/
|
||||
getMinimumZoom() {
|
||||
return 0.1 * this.getScreenScale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return the maximum supported zoom level
|
||||
* @returns {number}
|
||||
*/
|
||||
getMaximumZoom() {
|
||||
return 3.5 * this.getScreenScale();
|
||||
}
|
||||
|
||||
getScreenScale() {
|
||||
return Math.min(window.innerWidth, window.innerHeight) / 1024.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return if this platform supports ads at all
|
||||
*/
|
||||
getSupportsAds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to open an external url
|
||||
* @param {string} url
|
||||
* @param {boolean=} force Whether to always open the url even if not allowed
|
||||
*/
|
||||
openExternalLink(url, force = false) {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to restart the app
|
||||
*/
|
||||
performRestart() {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this platform supports a toggleable fullscreen
|
||||
*/
|
||||
getSupportsFullscreen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should set the apps fullscreen state to the desired state
|
||||
* @param {boolean} flag
|
||||
*/
|
||||
setFullscreen(flag) {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this platform supports quitting the app
|
||||
*/
|
||||
getSupportsAppExit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to quit the app
|
||||
*/
|
||||
exitApp() {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this platform supports a keyboard
|
||||
*/
|
||||
getSupportsKeyboard() {
|
||||
return !IS_MOBILE;
|
||||
}
|
||||
}
|
||||
/* typehints:start */
|
||||
import { Application } from "../application";
|
||||
/* typehints:end */
|
||||
|
||||
import { IS_MOBILE } from "../core/config";
|
||||
|
||||
export class PlatformWrapperInterface {
|
||||
constructor(app) {
|
||||
/** @type {Application} */
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/** @returns {string} */
|
||||
getId() {
|
||||
abstract;
|
||||
return "unknown-platform";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UI scale, called on every resize
|
||||
* @returns {number} */
|
||||
getUiScale() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
getSupportsRestart() {
|
||||
abstract;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the strength of touch pans with the mouse
|
||||
*/
|
||||
getTouchPanStrength() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** @returns {Promise<void>} */
|
||||
initialize() {
|
||||
document.documentElement.classList.add("p-" + this.getId());
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should initialize the apps ad provider in case supported
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
initializeAdProvider() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return the minimum supported zoom level
|
||||
* @returns {number}
|
||||
*/
|
||||
getMinimumZoom() {
|
||||
return 0.1 * this.getScreenScale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return the maximum supported zoom level
|
||||
* @returns {number}
|
||||
*/
|
||||
getMaximumZoom() {
|
||||
return 3.5 * this.getScreenScale();
|
||||
}
|
||||
|
||||
getScreenScale() {
|
||||
return Math.min(window.innerWidth, window.innerHeight) / 1024.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return if this platform supports ads at all
|
||||
*/
|
||||
getSupportsAds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to open an external url
|
||||
* @param {string} url
|
||||
* @param {boolean=} force Whether to always open the url even if not allowed
|
||||
*/
|
||||
openExternalLink(url, force = false) {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to restart the app
|
||||
*/
|
||||
performRestart() {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this platform supports a toggleable fullscreen
|
||||
*/
|
||||
getSupportsFullscreen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should set the apps fullscreen state to the desired state
|
||||
* @param {boolean} flag
|
||||
*/
|
||||
setFullscreen(flag) {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this platform supports quitting the app
|
||||
*/
|
||||
getSupportsAppExit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to quit the app
|
||||
*/
|
||||
exitApp() {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this platform supports a keyboard
|
||||
*/
|
||||
getSupportsKeyboard() {
|
||||
return !IS_MOBILE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,8 +6,7 @@ import { ReadWriteProxy } from "../core/read_write_proxy";
|
||||
import { BoolSetting, EnumSetting, RangeSetting, BaseSetting } from "./setting_types";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { ExplainedResult } from "../core/explained_result";
|
||||
import { THEMES, THEME, applyGameTheme } from "../game/theme";
|
||||
import { IS_DEMO } from "../core/config";
|
||||
import { THEMES, applyGameTheme } from "../game/theme";
|
||||
import { T } from "../translations";
|
||||
import { LANGUAGES } from "../languages";
|
||||
|
||||
@ -187,7 +186,9 @@ export const allApplicationSettings = [
|
||||
app.platformWrapper.setFullscreen(value);
|
||||
}
|
||||
},
|
||||
!IS_DEMO
|
||||
/**
|
||||
* @param {Application} app
|
||||
*/ app => app.restrictionMgr.getHasExtendedSettings()
|
||||
),
|
||||
|
||||
new BoolSetting(
|
||||
@ -215,7 +216,9 @@ export const allApplicationSettings = [
|
||||
applyGameTheme(id);
|
||||
document.documentElement.setAttribute("data-theme", id);
|
||||
},
|
||||
enabled: !IS_DEMO,
|
||||
enabledCb: /**
|
||||
* @param {Application} app
|
||||
*/ app => app.restrictionMgr.getHasExtendedSettings(),
|
||||
}),
|
||||
|
||||
new EnumSetting("autosaveInterval", {
|
||||
@ -255,6 +258,7 @@ export const allApplicationSettings = [
|
||||
|
||||
new BoolSetting("enableMousePan", 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) => {}),
|
||||
new BoolSetting("enableTunnelSmartplace", enumCategories.advanced, (app, value) => {}),
|
||||
new BoolSetting("vignette", enumCategories.userInterface, (app, value) => {}),
|
||||
@ -271,7 +275,9 @@ export const allApplicationSettings = [
|
||||
category: enumCategories.performance,
|
||||
restartRequired: false,
|
||||
changeCb: (app, id) => {},
|
||||
enabled: !IS_DEMO,
|
||||
enabledCb: /**
|
||||
* @param {Application} app
|
||||
*/ app => app.restrictionMgr.getHasExtendedSettings(),
|
||||
}),
|
||||
|
||||
new BoolSetting("lowQualityMapResources", enumCategories.performance, (app, value) => {}),
|
||||
@ -317,6 +323,7 @@ class SettingsStorage {
|
||||
this.disableTileGrid = false;
|
||||
this.lowQualityTextures = false;
|
||||
this.simplifiedBelts = false;
|
||||
this.zoomToCursor = true;
|
||||
|
||||
/**
|
||||
* @type {Object.<string, number>}
|
||||
@ -355,7 +362,7 @@ export class ApplicationSettings extends ReadWriteProxy {
|
||||
* @returns {SettingsStorage}
|
||||
*/
|
||||
getAllSettings() {
|
||||
return this.getCurrentData().settings;
|
||||
return this.currentData.settings;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -527,7 +534,7 @@ export class ApplicationSettings extends ReadWriteProxy {
|
||||
}
|
||||
|
||||
getCurrentVersion() {
|
||||
return 28;
|
||||
return 29;
|
||||
}
|
||||
|
||||
/** @param {{settings: SettingsStorage, version: number}} data */
|
||||
@ -660,6 +667,11 @@ export class ApplicationSettings extends ReadWriteProxy {
|
||||
data.version = 28;
|
||||
}
|
||||
|
||||
if (data.version < 29) {
|
||||
data.settings.zoomToCursor = true;
|
||||
data.version = 29;
|
||||
}
|
||||
|
||||
return ExplainedResult.good();
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,13 +13,13 @@ export class BaseSetting {
|
||||
* @param {string} id
|
||||
* @param {string} categoryId
|
||||
* @param {function(Application, any):void} changeCb
|
||||
* @param {boolean} enabled
|
||||
* @param {function(Application) : boolean=} enabledCb
|
||||
*/
|
||||
constructor(id, categoryId, changeCb, enabled) {
|
||||
constructor(id, categoryId, changeCb, enabledCb = null) {
|
||||
this.id = id;
|
||||
this.categoryId = categoryId;
|
||||
this.changeCb = changeCb;
|
||||
this.enabled = enabled;
|
||||
this.enabledCb = enabledCb;
|
||||
|
||||
/** @type {Application} */
|
||||
this.app = null;
|
||||
@ -39,6 +39,7 @@ export class BaseSetting {
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds all parameters
|
||||
* @param {Application} app
|
||||
* @param {HTMLElement} element
|
||||
* @param {any} dialogs
|
||||
@ -49,19 +50,37 @@ export class BaseSetting {
|
||||
this.dialogs = dialogs;
|
||||
}
|
||||
|
||||
getHtml() {
|
||||
/**
|
||||
* Returns the HTML for this setting
|
||||
* @param {Application} app
|
||||
*/
|
||||
getHtml(app) {
|
||||
abstract;
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this setting is enabled and available
|
||||
* @param {Application} app
|
||||
*/
|
||||
getIsAvailable(app) {
|
||||
return this.enabledCb ? this.enabledCb(app) : true;
|
||||
}
|
||||
|
||||
syncValueToElement() {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to modify the setting
|
||||
*/
|
||||
modify() {
|
||||
abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the dialog that a restart is required
|
||||
*/
|
||||
showRestartRequiredDialog() {
|
||||
const { restart } = this.dialogs.showInfo(
|
||||
T.dialogs.restartRequired.title,
|
||||
@ -74,6 +93,7 @@ export class BaseSetting {
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the set value
|
||||
* @param {any} value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
@ -96,10 +116,10 @@ export class EnumSetting extends BaseSetting {
|
||||
iconPrefix = null,
|
||||
changeCb = null,
|
||||
magicValue = null,
|
||||
enabled = true,
|
||||
enabledCb = null,
|
||||
}
|
||||
) {
|
||||
super(id, category, changeCb, enabled);
|
||||
super(id, category, changeCb, enabledCb);
|
||||
|
||||
this.options = options;
|
||||
this.valueGetter = valueGetter;
|
||||
@ -110,10 +130,14 @@ export class EnumSetting extends BaseSetting {
|
||||
this.magicValue = magicValue;
|
||||
}
|
||||
|
||||
getHtml() {
|
||||
/**
|
||||
* @param {Application} app
|
||||
*/
|
||||
getHtml(app) {
|
||||
const available = this.getIsAvailable(app);
|
||||
return `
|
||||
<div class="setting cardbox ${this.enabled ? "enabled" : "disabled"}">
|
||||
${this.enabled ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||
<div class="setting cardbox ${available ? "enabled" : "disabled"}">
|
||||
${available ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||
<div class="row">
|
||||
<label>${T.settings.labels[this.id].title}</label>
|
||||
<div class="value enum" data-setting="${this.id}"></div>
|
||||
@ -180,14 +204,18 @@ export class EnumSetting extends BaseSetting {
|
||||
}
|
||||
|
||||
export class BoolSetting extends BaseSetting {
|
||||
constructor(id, category, changeCb = null, enabled = true) {
|
||||
super(id, category, changeCb, enabled);
|
||||
constructor(id, category, changeCb = null, enabledCb = null) {
|
||||
super(id, category, changeCb, enabledCb);
|
||||
}
|
||||
|
||||
getHtml() {
|
||||
/**
|
||||
* @param {Application} app
|
||||
*/
|
||||
getHtml(app) {
|
||||
const available = this.getIsAvailable(app);
|
||||
return `
|
||||
<div class="setting cardbox ${this.enabled ? "enabled" : "disabled"}">
|
||||
${this.enabled ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||
<div class="setting cardbox ${available ? "enabled" : "disabled"}">
|
||||
${available ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||
|
||||
<div class="row">
|
||||
<label>${T.settings.labels[this.id].title}</label>
|
||||
@ -226,13 +254,13 @@ export class RangeSetting extends BaseSetting {
|
||||
id,
|
||||
category,
|
||||
changeCb = null,
|
||||
enabled = true,
|
||||
defaultValue = 1.0,
|
||||
minValue = 0,
|
||||
maxValue = 1.0,
|
||||
stepSize = 0.0001
|
||||
stepSize = 0.0001,
|
||||
enabledCb = null
|
||||
) {
|
||||
super(id, category, changeCb, enabled);
|
||||
super(id, category, changeCb, enabledCb);
|
||||
|
||||
this.defaultValue = defaultValue;
|
||||
this.minValue = minValue;
|
||||
@ -240,10 +268,14 @@ export class RangeSetting extends BaseSetting {
|
||||
this.stepSize = stepSize;
|
||||
}
|
||||
|
||||
getHtml() {
|
||||
/**
|
||||
* @param {Application} app
|
||||
*/
|
||||
getHtml(app) {
|
||||
const available = this.getIsAvailable(app);
|
||||
return `
|
||||
<div class="setting cardbox ${this.enabled ? "enabled" : "disabled"}">
|
||||
${this.enabled ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||
<div class="setting cardbox ${available ? "enabled" : "disabled"}">
|
||||
${available ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||
|
||||
<div class="row">
|
||||
<label>${T.settings.labels[this.id].title}</label>
|
||||
|
||||
@ -40,13 +40,6 @@ export class SavegameManager extends ReadWriteProxy {
|
||||
return 1002;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {SavegamesData}
|
||||
*/
|
||||
getCurrentData() {
|
||||
return super.getCurrentData();
|
||||
}
|
||||
|
||||
verify(data) {
|
||||
// TODO / FIXME!!!!
|
||||
return ExplainedResult.good();
|
||||
@ -96,6 +89,14 @@ export class SavegameManager extends ReadWriteProxy {
|
||||
return new Savegame(this.app, { internalId, metaDataRef: metadata });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this manager has any savegame of a 1.1.19 version, which
|
||||
* enables all levels
|
||||
*/
|
||||
getHasAnyLegacySavegames() {
|
||||
return this.currentData.savegames.some(savegame => savegame.version === 1005 || savegame.level > 14);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a savegame
|
||||
* @param {SavegameMetadata} game
|
||||
@ -149,7 +150,9 @@ export class SavegameManager extends ReadWriteProxy {
|
||||
});
|
||||
|
||||
this.currentData.savegames.push(metaData);
|
||||
this.sortSavegames();
|
||||
|
||||
// Notice: This is async and happening in the background
|
||||
this.updateAfterSavegamesChanged();
|
||||
|
||||
return new Savegame(this.app, {
|
||||
internalId: id,
|
||||
@ -157,8 +160,16 @@ export class SavegameManager extends ReadWriteProxy {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to import a savegame
|
||||
* @param {object} data
|
||||
*/
|
||||
importSavegame(data) {
|
||||
const savegame = this.createNewSavegame();
|
||||
|
||||
// Track legacy savegames
|
||||
const isOldSavegame = data.version < 1006;
|
||||
|
||||
const migrationResult = savegame.migrate(data);
|
||||
if (migrationResult.isBad()) {
|
||||
return Promise.reject("Failed to migrate: " + migrationResult.reason);
|
||||
@ -170,7 +181,19 @@ export class SavegameManager extends ReadWriteProxy {
|
||||
return Promise.reject("Verification failed: " + verification.result);
|
||||
}
|
||||
|
||||
return savegame.writeSavegameAndMetadata().then(() => this.sortSavegames());
|
||||
return savegame
|
||||
.writeSavegameAndMetadata()
|
||||
.then(() => this.updateAfterSavegamesChanged())
|
||||
.then(() => this.app.restrictionMgr.onHasLegacySavegamesChanged(isOldSavegame));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook after the savegames got changed
|
||||
*/
|
||||
updateAfterSavegamesChanged() {
|
||||
return this.sortSavegames()
|
||||
.then(() => this.writeAsync())
|
||||
.then(() => this.app.restrictionMgr.onHasLegacySavegamesChanged(this.getHasAnyLegacySavegames()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,7 +242,7 @@ export class SavegameManager extends ReadWriteProxy {
|
||||
if (G_IS_DEV && globalConfig.debug.disableSavegameWrite) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this.sortSavegames().then(() => this.writeAsync());
|
||||
return this.updateAfterSavegamesChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,7 +130,7 @@ export class SavegameSerializer {
|
||||
errorReason = errorReason || root.time.deserialize(savegame.time);
|
||||
errorReason = errorReason || root.camera.deserialize(savegame.camera);
|
||||
errorReason = errorReason || root.map.deserialize(savegame.map);
|
||||
errorReason = errorReason || root.hubGoals.deserialize(savegame.hubGoals);
|
||||
errorReason = errorReason || root.hubGoals.deserialize(savegame.hubGoals, root);
|
||||
errorReason = errorReason || root.hud.parts.pinnedShapes.deserialize(savegame.pinnedShapes);
|
||||
errorReason = errorReason || root.hud.parts.waypoints.deserialize(savegame.waypoints);
|
||||
errorReason = errorReason || this.internal.deserializeEntityArray(root, savegame.entities);
|
||||
|
||||
@ -19,7 +19,6 @@ import { getCodeFromBuildingData } from "../../game/building_codes.js";
|
||||
import { StaticMapEntityComponent } from "../../game/components/static_map_entity.js";
|
||||
import { Entity } from "../../game/entity.js";
|
||||
import { defaultBuildingVariant, MetaBuilding } from "../../game/meta_building.js";
|
||||
import { finalGameShape } from "../../game/upgrades.js";
|
||||
import { SavegameInterface_V1005 } from "./1005.js";
|
||||
|
||||
const schema = require("./1006.json");
|
||||
@ -152,7 +151,8 @@ export class SavegameInterface_V1006 extends SavegameInterface_V1005 {
|
||||
stored[shapeKey] = rebalance(stored[shapeKey]);
|
||||
}
|
||||
|
||||
stored[finalGameShape] = 0;
|
||||
// Reset final game shape
|
||||
stored["RuCw--Cw:----Ru--"] = 0;
|
||||
|
||||
// Reduce goals
|
||||
if (dump.hubGoals.currentGoal) {
|
||||
|
||||
@ -1,179 +1,173 @@
|
||||
import { TextualGameState } from "../core/textual_game_state";
|
||||
import { SOUNDS } from "../platform/sound";
|
||||
import { T } from "../translations";
|
||||
import { KEYMAPPINGS, getStringForKeyCode } from "../game/key_action_mapper";
|
||||
import { Dialog } from "../core/modal_dialog_elements";
|
||||
import { IS_DEMO } from "../core/config";
|
||||
|
||||
export class KeybindingsState extends TextualGameState {
|
||||
constructor() {
|
||||
super("KeybindingsState");
|
||||
}
|
||||
|
||||
getStateHeaderTitle() {
|
||||
return T.keybindings.title;
|
||||
}
|
||||
|
||||
getMainContentHTML() {
|
||||
return `
|
||||
|
||||
<div class="topEntries">
|
||||
<span class="hint">${T.keybindings.hint}</span>
|
||||
<button class="styledButton resetBindings">${T.keybindings.resetKeybindings}</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="keybindings">
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
onEnter() {
|
||||
const keybindingsElem = this.htmlElement.querySelector(".keybindings");
|
||||
|
||||
this.trackClicks(this.htmlElement.querySelector(".resetBindings"), this.resetBindings);
|
||||
|
||||
for (const category in KEYMAPPINGS) {
|
||||
const categoryDiv = document.createElement("div");
|
||||
categoryDiv.classList.add("category");
|
||||
keybindingsElem.appendChild(categoryDiv);
|
||||
|
||||
const labelDiv = document.createElement("strong");
|
||||
labelDiv.innerText = T.keybindings.categoryLabels[category];
|
||||
labelDiv.classList.add("categoryLabel");
|
||||
categoryDiv.appendChild(labelDiv);
|
||||
|
||||
for (const keybindingId in KEYMAPPINGS[category]) {
|
||||
const mapped = KEYMAPPINGS[category][keybindingId];
|
||||
|
||||
const elem = document.createElement("div");
|
||||
elem.classList.add("entry");
|
||||
elem.setAttribute("data-keybinding", keybindingId);
|
||||
categoryDiv.appendChild(elem);
|
||||
|
||||
const title = document.createElement("span");
|
||||
title.classList.add("title");
|
||||
title.innerText = T.keybindings.mappings[keybindingId];
|
||||
elem.appendChild(title);
|
||||
|
||||
const mappingDiv = document.createElement("span");
|
||||
mappingDiv.classList.add("mapping");
|
||||
elem.appendChild(mappingDiv);
|
||||
|
||||
const editBtn = document.createElement("button");
|
||||
editBtn.classList.add("styledButton", "editKeybinding");
|
||||
|
||||
const resetBtn = document.createElement("button");
|
||||
resetBtn.classList.add("styledButton", "resetKeybinding");
|
||||
|
||||
if (mapped.builtin) {
|
||||
editBtn.classList.add("disabled");
|
||||
resetBtn.classList.add("disabled");
|
||||
} else {
|
||||
this.trackClicks(editBtn, () => this.editKeybinding(keybindingId));
|
||||
this.trackClicks(resetBtn, () => this.resetKeybinding(keybindingId));
|
||||
}
|
||||
elem.appendChild(editBtn);
|
||||
elem.appendChild(resetBtn);
|
||||
}
|
||||
}
|
||||
this.updateKeybindings();
|
||||
}
|
||||
|
||||
editKeybinding(id) {
|
||||
// if (IS_DEMO) {
|
||||
// this.dialogs.showFeatureRestrictionInfo(T.demo.features.customizeKeybindings);
|
||||
// return;
|
||||
// }
|
||||
|
||||
const dialog = new Dialog({
|
||||
app: this.app,
|
||||
title: T.dialogs.editKeybinding.title,
|
||||
contentHTML: T.dialogs.editKeybinding.desc,
|
||||
buttons: ["cancel:good"],
|
||||
type: "info",
|
||||
});
|
||||
|
||||
dialog.inputReciever.keydown.add(({ keyCode, shift, alt, event }) => {
|
||||
if (keyCode === 27) {
|
||||
this.dialogs.closeDialog(dialog);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (event.target && event.target.tagName === "BUTTON" && keyCode === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
// Enter
|
||||
keyCode === 13
|
||||
) {
|
||||
// Ignore builtins
|
||||
return;
|
||||
}
|
||||
|
||||
this.app.settings.updateKeybindingOverride(id, keyCode);
|
||||
|
||||
this.dialogs.closeDialog(dialog);
|
||||
this.updateKeybindings();
|
||||
});
|
||||
|
||||
dialog.inputReciever.backButton.add(() => {});
|
||||
this.dialogs.internalShowDialog(dialog);
|
||||
|
||||
this.app.sound.playUiSound(SOUNDS.dialogOk);
|
||||
}
|
||||
|
||||
updateKeybindings() {
|
||||
const overrides = this.app.settings.getKeybindingOverrides();
|
||||
for (const category in KEYMAPPINGS) {
|
||||
for (const keybindingId in KEYMAPPINGS[category]) {
|
||||
const mapped = KEYMAPPINGS[category][keybindingId];
|
||||
|
||||
const container = this.htmlElement.querySelector("[data-keybinding='" + keybindingId + "']");
|
||||
assert(container, "Container for keybinding not found: " + keybindingId);
|
||||
|
||||
let keyCode = mapped.keyCode;
|
||||
if (overrides[keybindingId]) {
|
||||
keyCode = overrides[keybindingId];
|
||||
}
|
||||
|
||||
const mappingDiv = container.querySelector(".mapping");
|
||||
mappingDiv.innerHTML = getStringForKeyCode(keyCode);
|
||||
mappingDiv.classList.toggle("changed", !!overrides[keybindingId]);
|
||||
|
||||
const resetBtn = container.querySelector("button.resetKeybinding");
|
||||
resetBtn.classList.toggle("disabled", mapped.builtin || !overrides[keybindingId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetKeybinding(id) {
|
||||
this.app.settings.resetKeybindingOverride(id);
|
||||
this.updateKeybindings();
|
||||
}
|
||||
|
||||
resetBindings() {
|
||||
const { reset } = this.dialogs.showWarning(
|
||||
T.dialogs.resetKeybindingsConfirmation.title,
|
||||
T.dialogs.resetKeybindingsConfirmation.desc,
|
||||
["cancel:good", "reset:bad"]
|
||||
);
|
||||
|
||||
reset.add(() => {
|
||||
this.app.settings.resetKeybindingOverrides();
|
||||
this.updateKeybindings();
|
||||
|
||||
this.dialogs.showInfo(T.dialogs.keybindingsResetOk.title, T.dialogs.keybindingsResetOk.desc);
|
||||
});
|
||||
}
|
||||
|
||||
getDefaultPreviousState() {
|
||||
return "SettingsState";
|
||||
}
|
||||
}
|
||||
import { Dialog } from "../core/modal_dialog_elements";
|
||||
import { TextualGameState } from "../core/textual_game_state";
|
||||
import { getStringForKeyCode, KEYMAPPINGS } from "../game/key_action_mapper";
|
||||
import { SOUNDS } from "../platform/sound";
|
||||
import { T } from "../translations";
|
||||
|
||||
export class KeybindingsState extends TextualGameState {
|
||||
constructor() {
|
||||
super("KeybindingsState");
|
||||
}
|
||||
|
||||
getStateHeaderTitle() {
|
||||
return T.keybindings.title;
|
||||
}
|
||||
|
||||
getMainContentHTML() {
|
||||
return `
|
||||
|
||||
<div class="topEntries">
|
||||
<span class="hint">${T.keybindings.hint}</span>
|
||||
<button class="styledButton resetBindings">${T.keybindings.resetKeybindings}</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="keybindings">
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
onEnter() {
|
||||
const keybindingsElem = this.htmlElement.querySelector(".keybindings");
|
||||
|
||||
this.trackClicks(this.htmlElement.querySelector(".resetBindings"), this.resetBindings);
|
||||
|
||||
for (const category in KEYMAPPINGS) {
|
||||
const categoryDiv = document.createElement("div");
|
||||
categoryDiv.classList.add("category");
|
||||
keybindingsElem.appendChild(categoryDiv);
|
||||
|
||||
const labelDiv = document.createElement("strong");
|
||||
labelDiv.innerText = T.keybindings.categoryLabels[category];
|
||||
labelDiv.classList.add("categoryLabel");
|
||||
categoryDiv.appendChild(labelDiv);
|
||||
|
||||
for (const keybindingId in KEYMAPPINGS[category]) {
|
||||
const mapped = KEYMAPPINGS[category][keybindingId];
|
||||
|
||||
const elem = document.createElement("div");
|
||||
elem.classList.add("entry");
|
||||
elem.setAttribute("data-keybinding", keybindingId);
|
||||
categoryDiv.appendChild(elem);
|
||||
|
||||
const title = document.createElement("span");
|
||||
title.classList.add("title");
|
||||
title.innerText = T.keybindings.mappings[keybindingId];
|
||||
elem.appendChild(title);
|
||||
|
||||
const mappingDiv = document.createElement("span");
|
||||
mappingDiv.classList.add("mapping");
|
||||
elem.appendChild(mappingDiv);
|
||||
|
||||
const editBtn = document.createElement("button");
|
||||
editBtn.classList.add("styledButton", "editKeybinding");
|
||||
|
||||
const resetBtn = document.createElement("button");
|
||||
resetBtn.classList.add("styledButton", "resetKeybinding");
|
||||
|
||||
if (mapped.builtin) {
|
||||
editBtn.classList.add("disabled");
|
||||
resetBtn.classList.add("disabled");
|
||||
} else {
|
||||
this.trackClicks(editBtn, () => this.editKeybinding(keybindingId));
|
||||
this.trackClicks(resetBtn, () => this.resetKeybinding(keybindingId));
|
||||
}
|
||||
elem.appendChild(editBtn);
|
||||
elem.appendChild(resetBtn);
|
||||
}
|
||||
}
|
||||
this.updateKeybindings();
|
||||
}
|
||||
|
||||
editKeybinding(id) {
|
||||
const dialog = new Dialog({
|
||||
app: this.app,
|
||||
title: T.dialogs.editKeybinding.title,
|
||||
contentHTML: T.dialogs.editKeybinding.desc,
|
||||
buttons: ["cancel:good"],
|
||||
type: "info",
|
||||
});
|
||||
|
||||
dialog.inputReciever.keydown.add(({ keyCode, shift, alt, event }) => {
|
||||
if (keyCode === 27) {
|
||||
this.dialogs.closeDialog(dialog);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (event.target && event.target.tagName === "BUTTON" && keyCode === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
// Enter
|
||||
keyCode === 13
|
||||
) {
|
||||
// Ignore builtins
|
||||
return;
|
||||
}
|
||||
|
||||
this.app.settings.updateKeybindingOverride(id, keyCode);
|
||||
|
||||
this.dialogs.closeDialog(dialog);
|
||||
this.updateKeybindings();
|
||||
});
|
||||
|
||||
dialog.inputReciever.backButton.add(() => {});
|
||||
this.dialogs.internalShowDialog(dialog);
|
||||
|
||||
this.app.sound.playUiSound(SOUNDS.dialogOk);
|
||||
}
|
||||
|
||||
updateKeybindings() {
|
||||
const overrides = this.app.settings.getKeybindingOverrides();
|
||||
for (const category in KEYMAPPINGS) {
|
||||
for (const keybindingId in KEYMAPPINGS[category]) {
|
||||
const mapped = KEYMAPPINGS[category][keybindingId];
|
||||
|
||||
const container = this.htmlElement.querySelector("[data-keybinding='" + keybindingId + "']");
|
||||
assert(container, "Container for keybinding not found: " + keybindingId);
|
||||
|
||||
let keyCode = mapped.keyCode;
|
||||
if (overrides[keybindingId]) {
|
||||
keyCode = overrides[keybindingId];
|
||||
}
|
||||
|
||||
const mappingDiv = container.querySelector(".mapping");
|
||||
mappingDiv.innerHTML = getStringForKeyCode(keyCode);
|
||||
mappingDiv.classList.toggle("changed", !!overrides[keybindingId]);
|
||||
|
||||
const resetBtn = container.querySelector("button.resetKeybinding");
|
||||
resetBtn.classList.toggle("disabled", mapped.builtin || !overrides[keybindingId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetKeybinding(id) {
|
||||
this.app.settings.resetKeybindingOverride(id);
|
||||
this.updateKeybindings();
|
||||
}
|
||||
|
||||
resetBindings() {
|
||||
const { reset } = this.dialogs.showWarning(
|
||||
T.dialogs.resetKeybindingsConfirmation.title,
|
||||
T.dialogs.resetKeybindingsConfirmation.desc,
|
||||
["cancel:good", "reset:bad"]
|
||||
);
|
||||
|
||||
reset.add(() => {
|
||||
this.app.settings.resetKeybindingOverrides();
|
||||
this.updateKeybindings();
|
||||
|
||||
this.dialogs.showInfo(T.dialogs.keybindingsResetOk.title, T.dialogs.keybindingsResetOk.desc);
|
||||
});
|
||||
}
|
||||
|
||||
getDefaultPreviousState() {
|
||||
return "SettingsState";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,21 +1,23 @@
|
||||
import { GameState } from "../core/game_state";
|
||||
import { cachebust } from "../core/cachebust";
|
||||
import { A_B_TESTING_LINK_TYPE, globalConfig, IS_DEMO, THIRDPARTY_URLS } from "../core/config";
|
||||
import { A_B_TESTING_LINK_TYPE, globalConfig, THIRDPARTY_URLS } from "../core/config";
|
||||
import { GameState } from "../core/game_state";
|
||||
import { DialogWithForm } from "../core/modal_dialog_elements";
|
||||
import { FormElementInput } from "../core/modal_dialog_forms";
|
||||
import { ReadWriteProxy } from "../core/read_write_proxy";
|
||||
import {
|
||||
makeDiv,
|
||||
makeButtonElement,
|
||||
formatSecondsToTimeAgo,
|
||||
waitNextFrame,
|
||||
generateFileDownload,
|
||||
isSupportedBrowser,
|
||||
makeButton,
|
||||
makeButtonElement,
|
||||
makeDiv,
|
||||
removeAllChildren,
|
||||
startFileChoose,
|
||||
waitNextFrame,
|
||||
} from "../core/utils";
|
||||
import { ReadWriteProxy } from "../core/read_write_proxy";
|
||||
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
||||
import { T } from "../translations";
|
||||
import { getApplicationSettingById } from "../profile/application_settings";
|
||||
import { FormElementInput } from "../core/modal_dialog_forms";
|
||||
import { DialogWithForm } from "../core/modal_dialog_elements";
|
||||
import { T } from "../translations";
|
||||
|
||||
const trim = require("trim");
|
||||
|
||||
@ -24,23 +26,6 @@ const trim = require("trim");
|
||||
* @typedef {import("../profile/setting_types").EnumSetting} EnumSetting
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates a file download
|
||||
* @param {string} filename
|
||||
* @param {string} text
|
||||
*/
|
||||
function generateFileDownload(filename, text) {
|
||||
var element = document.createElement("a");
|
||||
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text));
|
||||
element.setAttribute("download", filename);
|
||||
|
||||
element.style.display = "none";
|
||||
document.body.appendChild(element);
|
||||
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
|
||||
export class MainMenuState extends GameState {
|
||||
constructor() {
|
||||
super("MainMenuState");
|
||||
@ -49,18 +34,16 @@ export class MainMenuState extends GameState {
|
||||
getInnerHTML() {
|
||||
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>
|
||||
`;
|
||||
|
||||
return `
|
||||
const showDemoBadges = this.app.restrictionMgr.getIsStandaloneMarketingActive();
|
||||
|
||||
return `
|
||||
<div class="topButtons">
|
||||
<button class="languageChoose" data-languageicon="${this.app.settings.getLanguage()}"></button>
|
||||
<button class="settingsButton"></button>
|
||||
|
||||
${
|
||||
G_IS_STANDALONE || G_IS_DEV
|
||||
? `
|
||||
@ -74,17 +57,14 @@ export class MainMenuState extends GameState {
|
||||
<source src="${cachebust("res/bg_render.webm")}" type="video/webm">
|
||||
</video>
|
||||
|
||||
|
||||
<div class="logo">
|
||||
<img src="${cachebust("res/logo.png")}" alt="shapez.io Logo">
|
||||
<span class="updateLabel">Wires update!</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mainWrapper ${IS_DEMO ? "demo" : "noDemo"}">
|
||||
|
||||
<div class="mainWrapper ${showDemoBadges ? "demo" : "noDemo"}">
|
||||
<div class="sideContainer">
|
||||
${IS_DEMO ? `<div class="standaloneBanner">${bannerHtml}</div>` : ""}
|
||||
${showDemoBadges ? `<div class="standaloneBanner">${bannerHtml}</div>` : ""}
|
||||
</div>
|
||||
|
||||
<div class="mainContainer">
|
||||
@ -95,12 +75,9 @@ export class MainMenuState extends GameState {
|
||||
}
|
||||
<div class="buttons"></div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
|
||||
<a class="githubLink boxLink" target="_blank">
|
||||
${T.mainMenu.openSourceHint}
|
||||
<span class="thirdpartyLogo githubLogo"></span>
|
||||
@ -123,32 +100,29 @@ export class MainMenuState extends GameState {
|
||||
"<author-link>",
|
||||
'<a class="producerLink" target="_blank">Tobias Springer</a>'
|
||||
)}</div>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the user to import a savegame
|
||||
*/
|
||||
requestImportSavegame() {
|
||||
if (
|
||||
IS_DEMO &&
|
||||
this.app.savegameMgr.getSavegamesMetaData().length > 0 &&
|
||||
!this.app.platformWrapper.getHasUnlimitedSavegames()
|
||||
!this.app.restrictionMgr.getHasUnlimitedSavegames()
|
||||
) {
|
||||
this.app.analytics.trackUiClick("importgame_slot_limit_show");
|
||||
this.showSavegameSlotLimit();
|
||||
return;
|
||||
}
|
||||
|
||||
var input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = ".bin";
|
||||
|
||||
input.onchange = e => {
|
||||
const file = input.files[0];
|
||||
// Create a 'fake' file-input to accept savegames
|
||||
startFileChoose(".bin").then(file => {
|
||||
if (file) {
|
||||
const closeLoader = this.dialogs.showLoadingDialog();
|
||||
waitNextFrame().then(() => {
|
||||
this.app.analytics.trackUiClick("import_savegame");
|
||||
const closeLoader = this.dialogs.showLoadingDialog();
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", event => {
|
||||
const contents = event.target.result;
|
||||
@ -194,8 +168,7 @@ export class MainMenuState extends GameState {
|
||||
reader.readAsText(file, "utf-8");
|
||||
});
|
||||
}
|
||||
};
|
||||
input.click();
|
||||
});
|
||||
}
|
||||
|
||||
onBackButton() {
|
||||
@ -557,9 +530,8 @@ export class MainMenuState extends GameState {
|
||||
|
||||
onPlayButtonClicked() {
|
||||
if (
|
||||
IS_DEMO &&
|
||||
this.app.savegameMgr.getSavegamesMetaData().length > 0 &&
|
||||
!this.app.platformWrapper.getHasUnlimitedSavegames()
|
||||
!this.app.restrictionMgr.getHasUnlimitedSavegames()
|
||||
) {
|
||||
this.app.analytics.trackUiClick("startgame_slot_limit_show");
|
||||
this.showSavegameSlotLimit();
|
||||
|
||||
@ -145,6 +145,11 @@ export class PreloadState extends GameState {
|
||||
this.app.backgroundResourceLoader.startLoading();
|
||||
})
|
||||
|
||||
.then(() => this.setStatus("Initializing restrictions"))
|
||||
.then(() => {
|
||||
return this.app.restrictionMgr.initialize();
|
||||
})
|
||||
|
||||
.then(() => this.setStatus("Initializing savegame"))
|
||||
.then(() => {
|
||||
return this.app.savegameMgr.initialize().catch(err => {
|
||||
|
||||
@ -1,169 +1,169 @@
|
||||
import { TextualGameState } from "../core/textual_game_state";
|
||||
import { formatSecondsToTimeAgo } from "../core/utils";
|
||||
import { allApplicationSettings, enumCategories } from "../profile/application_settings";
|
||||
import { T } from "../translations";
|
||||
|
||||
export class SettingsState extends TextualGameState {
|
||||
constructor() {
|
||||
super("SettingsState");
|
||||
}
|
||||
|
||||
getStateHeaderTitle() {
|
||||
return T.settings.title;
|
||||
}
|
||||
|
||||
getMainContentHTML() {
|
||||
return `
|
||||
|
||||
<div class="sidebar">
|
||||
${this.getCategoryButtonsHtml()}
|
||||
|
||||
${
|
||||
this.app.platformWrapper.getSupportsKeyboard()
|
||||
? `
|
||||
<button class="styledButton categoryButton editKeybindings">
|
||||
${T.keybindings.title}
|
||||
</button>`
|
||||
: ""
|
||||
}
|
||||
|
||||
<div class="other">
|
||||
<button class="styledButton about">${T.about.title}</button>
|
||||
|
||||
<div class="versionbar">
|
||||
<div class="buildVersion">${T.global.loading} ...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="categoryContainer">
|
||||
${this.getSettingsHtml()}
|
||||
</div>
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
getCategoryButtonsHtml() {
|
||||
return Object.keys(enumCategories)
|
||||
.map(key => enumCategories[key])
|
||||
.map(
|
||||
category =>
|
||||
`
|
||||
<button class="styledButton categoryButton" data-category-btn="${category}">
|
||||
${T.settings.categories[category]}
|
||||
</button>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
getSettingsHtml() {
|
||||
const categoriesHTML = {};
|
||||
|
||||
Object.keys(enumCategories).forEach(key => {
|
||||
const catName = enumCategories[key];
|
||||
categoriesHTML[catName] = `<div class="category" data-category="${catName}">`;
|
||||
});
|
||||
|
||||
for (let i = 0; i < allApplicationSettings.length; ++i) {
|
||||
const setting = allApplicationSettings[i];
|
||||
|
||||
categoriesHTML[setting.categoryId] += setting.getHtml();
|
||||
}
|
||||
|
||||
return Object.keys(categoriesHTML)
|
||||
.map(k => categoriesHTML[k] + "</div>")
|
||||
.join("");
|
||||
}
|
||||
|
||||
renderBuildText() {
|
||||
const labelVersion = this.htmlElement.querySelector(".buildVersion");
|
||||
const lastBuildMs = new Date().getTime() - G_BUILD_TIME;
|
||||
const lastBuildText = formatSecondsToTimeAgo(lastBuildMs / 1000.0);
|
||||
|
||||
const version = T.settings.versionBadges[G_APP_ENVIRONMENT];
|
||||
|
||||
labelVersion.innerHTML = `
|
||||
<span class='version'>
|
||||
${G_BUILD_VERSION} @ ${version} @ ${G_BUILD_COMMIT_HASH}
|
||||
</span>
|
||||
<span class='buildTime'>
|
||||
${T.settings.buildDate.replace("<at-date>", lastBuildText)}<br />
|
||||
</span>`;
|
||||
}
|
||||
|
||||
onEnter(payload) {
|
||||
this.renderBuildText();
|
||||
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
|
||||
preventDefault: false,
|
||||
});
|
||||
|
||||
const keybindingsButton = this.htmlElement.querySelector(".editKeybindings");
|
||||
|
||||
if (keybindingsButton) {
|
||||
this.trackClicks(keybindingsButton, this.onKeybindingsClicked, { preventDefault: false });
|
||||
}
|
||||
|
||||
this.initSettings();
|
||||
this.initCategoryButtons();
|
||||
|
||||
this.htmlElement.querySelector(".category").classList.add("active");
|
||||
this.htmlElement.querySelector(".categoryButton").classList.add("active");
|
||||
}
|
||||
|
||||
setActiveCategory(category) {
|
||||
const previousCategory = this.htmlElement.querySelector(".category.active");
|
||||
const previousCategoryButton = this.htmlElement.querySelector(".categoryButton.active");
|
||||
|
||||
if (previousCategory.getAttribute("data-category") == category) {
|
||||
return;
|
||||
}
|
||||
|
||||
previousCategory.classList.remove("active");
|
||||
previousCategoryButton.classList.remove("active");
|
||||
|
||||
const newCategory = this.htmlElement.querySelector("[data-category='" + category + "']");
|
||||
const newCategoryButton = this.htmlElement.querySelector("[data-category-btn='" + category + "']");
|
||||
|
||||
newCategory.classList.add("active");
|
||||
newCategoryButton.classList.add("active");
|
||||
}
|
||||
|
||||
initSettings() {
|
||||
allApplicationSettings.forEach(setting => {
|
||||
/** @type {HTMLElement} */
|
||||
const element = this.htmlElement.querySelector("[data-setting='" + setting.id + "']");
|
||||
setting.bind(this.app, element, this.dialogs);
|
||||
setting.syncValueToElement();
|
||||
this.trackClicks(
|
||||
element,
|
||||
() => {
|
||||
setting.modify();
|
||||
},
|
||||
{ preventDefault: false }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
initCategoryButtons() {
|
||||
Object.keys(enumCategories).forEach(key => {
|
||||
const category = enumCategories[key];
|
||||
const button = this.htmlElement.querySelector("[data-category-btn='" + category + "']");
|
||||
this.trackClicks(
|
||||
button,
|
||||
() => {
|
||||
this.setActiveCategory(category);
|
||||
},
|
||||
{ preventDefault: false }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
onAboutClicked() {
|
||||
this.moveToStateAddGoBack("AboutState");
|
||||
}
|
||||
|
||||
onKeybindingsClicked() {
|
||||
this.moveToStateAddGoBack("KeybindingsState");
|
||||
}
|
||||
}
|
||||
import { TextualGameState } from "../core/textual_game_state";
|
||||
import { formatSecondsToTimeAgo } from "../core/utils";
|
||||
import { allApplicationSettings, enumCategories } from "../profile/application_settings";
|
||||
import { T } from "../translations";
|
||||
|
||||
export class SettingsState extends TextualGameState {
|
||||
constructor() {
|
||||
super("SettingsState");
|
||||
}
|
||||
|
||||
getStateHeaderTitle() {
|
||||
return T.settings.title;
|
||||
}
|
||||
|
||||
getMainContentHTML() {
|
||||
return `
|
||||
|
||||
<div class="sidebar">
|
||||
${this.getCategoryButtonsHtml()}
|
||||
|
||||
${
|
||||
this.app.platformWrapper.getSupportsKeyboard()
|
||||
? `
|
||||
<button class="styledButton categoryButton editKeybindings">
|
||||
${T.keybindings.title}
|
||||
</button>`
|
||||
: ""
|
||||
}
|
||||
|
||||
<div class="other">
|
||||
<button class="styledButton about">${T.about.title}</button>
|
||||
|
||||
<div class="versionbar">
|
||||
<div class="buildVersion">${T.global.loading} ...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="categoryContainer">
|
||||
${this.getSettingsHtml()}
|
||||
</div>
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
getCategoryButtonsHtml() {
|
||||
return Object.keys(enumCategories)
|
||||
.map(key => enumCategories[key])
|
||||
.map(
|
||||
category =>
|
||||
`
|
||||
<button class="styledButton categoryButton" data-category-btn="${category}">
|
||||
${T.settings.categories[category]}
|
||||
</button>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
getSettingsHtml() {
|
||||
const categoriesHTML = {};
|
||||
|
||||
Object.keys(enumCategories).forEach(key => {
|
||||
const catName = enumCategories[key];
|
||||
categoriesHTML[catName] = `<div class="category" data-category="${catName}">`;
|
||||
});
|
||||
|
||||
for (let i = 0; i < allApplicationSettings.length; ++i) {
|
||||
const setting = allApplicationSettings[i];
|
||||
|
||||
categoriesHTML[setting.categoryId] += setting.getHtml(this.app);
|
||||
}
|
||||
|
||||
return Object.keys(categoriesHTML)
|
||||
.map(k => categoriesHTML[k] + "</div>")
|
||||
.join("");
|
||||
}
|
||||
|
||||
renderBuildText() {
|
||||
const labelVersion = this.htmlElement.querySelector(".buildVersion");
|
||||
const lastBuildMs = new Date().getTime() - G_BUILD_TIME;
|
||||
const lastBuildText = formatSecondsToTimeAgo(lastBuildMs / 1000.0);
|
||||
|
||||
const version = T.settings.versionBadges[G_APP_ENVIRONMENT];
|
||||
|
||||
labelVersion.innerHTML = `
|
||||
<span class='version'>
|
||||
${G_BUILD_VERSION} @ ${version} @ ${G_BUILD_COMMIT_HASH}
|
||||
</span>
|
||||
<span class='buildTime'>
|
||||
${T.settings.buildDate.replace("<at-date>", lastBuildText)}<br />
|
||||
</span>`;
|
||||
}
|
||||
|
||||
onEnter(payload) {
|
||||
this.renderBuildText();
|
||||
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
|
||||
preventDefault: false,
|
||||
});
|
||||
|
||||
const keybindingsButton = this.htmlElement.querySelector(".editKeybindings");
|
||||
|
||||
if (keybindingsButton) {
|
||||
this.trackClicks(keybindingsButton, this.onKeybindingsClicked, { preventDefault: false });
|
||||
}
|
||||
|
||||
this.initSettings();
|
||||
this.initCategoryButtons();
|
||||
|
||||
this.htmlElement.querySelector(".category").classList.add("active");
|
||||
this.htmlElement.querySelector(".categoryButton").classList.add("active");
|
||||
}
|
||||
|
||||
setActiveCategory(category) {
|
||||
const previousCategory = this.htmlElement.querySelector(".category.active");
|
||||
const previousCategoryButton = this.htmlElement.querySelector(".categoryButton.active");
|
||||
|
||||
if (previousCategory.getAttribute("data-category") == category) {
|
||||
return;
|
||||
}
|
||||
|
||||
previousCategory.classList.remove("active");
|
||||
previousCategoryButton.classList.remove("active");
|
||||
|
||||
const newCategory = this.htmlElement.querySelector("[data-category='" + category + "']");
|
||||
const newCategoryButton = this.htmlElement.querySelector("[data-category-btn='" + category + "']");
|
||||
|
||||
newCategory.classList.add("active");
|
||||
newCategoryButton.classList.add("active");
|
||||
}
|
||||
|
||||
initSettings() {
|
||||
allApplicationSettings.forEach(setting => {
|
||||
/** @type {HTMLElement} */
|
||||
const element = this.htmlElement.querySelector("[data-setting='" + setting.id + "']");
|
||||
setting.bind(this.app, element, this.dialogs);
|
||||
setting.syncValueToElement();
|
||||
this.trackClicks(
|
||||
element,
|
||||
() => {
|
||||
setting.modify();
|
||||
},
|
||||
{ preventDefault: false }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
initCategoryButtons() {
|
||||
Object.keys(enumCategories).forEach(key => {
|
||||
const category = enumCategories[key];
|
||||
const button = this.htmlElement.querySelector("[data-category-btn='" + category + "']");
|
||||
this.trackClicks(
|
||||
button,
|
||||
() => {
|
||||
this.setActiveCategory(category);
|
||||
},
|
||||
{ preventDefault: false }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
onAboutClicked() {
|
||||
this.moveToStateAddGoBack("AboutState");
|
||||
}
|
||||
|
||||
onKeybindingsClicked() {
|
||||
this.moveToStateAddGoBack("KeybindingsState");
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ The base language is English and can be found [here](base-en.yaml).
|
||||
- [Ukrainian](base-uk.yaml)
|
||||
- [Indonesian](base-ind.yaml)
|
||||
- [Serbian](base-sr.yaml)
|
||||
- [Czech](base-cz.yaml)
|
||||
|
||||
(If you want to translate into a new language, see below!)
|
||||
|
||||
|
||||
@ -1,20 +1,17 @@
|
||||
steamPage:
|
||||
shortText: shapez.io is a game about building factories to automate the creation
|
||||
and processing of increasingly complex shapes across an infinitely
|
||||
expanding map.
|
||||
shortText: لعبة شيبز (أشكال) هي لعبة تدور حول بناء مصانع وتوصيلها حتى تقوم بشكل
|
||||
.آلي بصناعة أشكال مختلفة تزداد تعقيدا في خريطة لانهائية.
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
لعبة شيبز (أشكال) هي لعبة مريحة تقوم فيها ببناء مصانع ووتشغيلها آليا لصناعة أشكال هندسية.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
مع التقدم في المستوى، تزداد الأشكال تعقيداً، فيتوجب عليك التوسع في الخريطة اللانهائية، وذلك ليس كافياً للتقدم في مستوى اللعبة
|
||||
حيث عليك صناعة المزيد بأضعاف مضاعفة لتلبية الطلب، الشيء الوحيد الذي يمكنه مساعدتك هو التوسع.
|
||||
|
||||
And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling!
|
||||
بينما في البداية تقوم بصناعة أشكال مختلفة، تتطلب منك المراحل المتقدمة تلوين هذه الأشكال، حيث يتوجب عليك استخراج وخلط الألوان.
|
||||
|
||||
While you only process shapes at the beginning, you have to color them later - for this you have to extract and mix colors!
|
||||
|
||||
Buying the game on Steam gives you access to the full version, but you can also play a demo on shapez.io first and decide later!
|
||||
title_advantages: Standalone Advantages
|
||||
عند شراءك اللعبة على ستيم (Steam) تحصل على الإصدار الكامل للعبة، ولكن يمكن أيضاً لعبة نسخة تجريبية على موقع shapez.io ثم يمكنك القرار لاحقا
|
||||
title_advantages: ميزات نسخة الحاسوب
|
||||
advantages:
|
||||
- <b>12 New Level</b> for a total of 26 levels
|
||||
- <b>18 New Buildings</b> for a fully automated factory!
|
||||
|
||||
@ -5,7 +5,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io es un joc relaxant en el qual has de construir fàbriques per a
|
||||
la producció automàtica de formes geomètriques.
|
||||
la producció automàtica de formes geomètriques.
|
||||
|
||||
A mesura que el nivell augmenta, les formes esdevenen més complexes, i has d'explorar el mapa infinit.
|
||||
|
||||
@ -94,7 +94,7 @@ mainMenu:
|
||||
helpTranslate: Ajuda a traduir-lo!
|
||||
madeBy: Creat per <author-link>
|
||||
browserWarning: >-
|
||||
|
||||
|
||||
Disculpa, però el joc funcionarà lent al teu navegador! Aconsegueix el joc complet o descarrega't chrome per una millor experiència.
|
||||
savegameLevel: Nivell <x>
|
||||
savegameLevelUnknown: Nivell desconegut
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
steamPage:
|
||||
shortText: shapez.io je hra o stavbě továren pro automatizaci výroby a
|
||||
kombinování čím dál složitějších tvarů na nekonečné mapě.
|
||||
discordLinkShort: Official Discord
|
||||
discordLinkShort: Oficiální Discord
|
||||
intro: >-
|
||||
Shapez.io je relaxační hra, ve které musíte stavět továrny pro
|
||||
automatizaci výroby geometrických tvarů.
|
||||
automatizaci výroby geometrických tvarů.
|
||||
|
||||
Jak se zvyšuje úroveň, tvary se stávají stále složitějšími a vy se musíte rozšířit po nekonečné mapě.
|
||||
|
||||
@ -13,38 +13,38 @@ steamPage:
|
||||
Zatímco tvary zpracováváte pouze na začátku, musíte je později obarvit - k tomu musíte těžit a míchat barvy!
|
||||
|
||||
Koupením hry na platformě Steam vám dá přístup k plné verzi hry, ale také můžete hrát demo verzi na shapez.io a potom se můžete rozhodnou jestli hru koupíte!
|
||||
title_advantages: Samostatné výhody
|
||||
title_advantages: Výhody samostatné verze hry
|
||||
advantages:
|
||||
- <b>12 Nových úrovní</b> celkem 26 úrovní
|
||||
- <b>18 Nových budov</b> pro plně automatizovanou továrnu!
|
||||
- <b>20 vylepšení</b> pro mnoho hodin zábavy!
|
||||
- <b>Wires Update</b> pro zcela nové rozměry!
|
||||
- <b>Dark Mode</b>!
|
||||
- Neomezené Savegames
|
||||
- Neomezený počet uložených her
|
||||
- Neomezené značky
|
||||
- Podpořte mě! ❤️
|
||||
title_future: Plánovaný kontent
|
||||
planned:
|
||||
- Blueprintová knihovna (Samostatně exkluzivní)
|
||||
- Blueprintová knihovna
|
||||
- Steam Achievements
|
||||
- Puzzle Mode
|
||||
- Minnimapa
|
||||
- Mody
|
||||
- Sandbox mode
|
||||
- Puzzle Mód
|
||||
- Minimapa
|
||||
- Módy
|
||||
- Sandbox Mód
|
||||
- ... a o hodně víc!
|
||||
title_open_source: Tato hra je open source!
|
||||
title_links: Odkazy
|
||||
links:
|
||||
discord: Officiální Discord
|
||||
discord: Oficiální Discord
|
||||
roadmap: Roadmap
|
||||
subreddit: Subreddit
|
||||
source_code: Source code (GitHub)
|
||||
translate: Pomozte přeložit hru!
|
||||
text_open_source: |-
|
||||
Kdokoli může přispět, aktivně se zapojit do komunity,
|
||||
pokusit se zkontrolovat všechny návrhy a vzít v úvahu zpětnou vazbu
|
||||
Kdokoli může přispět, jsem aktivně zapojený do komunity,
|
||||
pokouším se zkontrolovat všechny návrhy a vzít v úvahu zpětnou vazbu všude,
|
||||
kde je to možné.
|
||||
|
||||
|
||||
Nezapomeňte se podívat na můj trello board, kde najdete kompletní plán!
|
||||
global:
|
||||
loading: Načítám
|
||||
@ -105,8 +105,8 @@ dialogs:
|
||||
later: Později
|
||||
restart: Restart
|
||||
reset: Reset
|
||||
getStandalone: Získejte Plnou verzi
|
||||
deleteGame: Vím co dělám
|
||||
getStandalone: Získejte plnou verzi
|
||||
deleteGame: Vím, co dělám
|
||||
viewUpdate: Zobrazit aktualizaci
|
||||
showUpgrades: Zobrazit vylepšení
|
||||
showKeybindings: Zobrazit klávesové zkratky
|
||||
@ -345,7 +345,7 @@ ingame:
|
||||
desc: Kliknutím sem zobrazíte výhody Steam verze!
|
||||
get_on_steam: Získejte na steamu
|
||||
standaloneAdvantages:
|
||||
title: Získejte plnou verzy!
|
||||
title: Získejte plnou verzi!
|
||||
no_thanks: Ne, děkuji!
|
||||
points:
|
||||
levels:
|
||||
@ -399,10 +399,10 @@ buildings:
|
||||
miner:
|
||||
default:
|
||||
name: Extraktor
|
||||
description: Umístěte na náleziště tvaru nebo barvy pro zahájení těžby.
|
||||
description: Umístěte na naleziště tvaru nebo barvy pro zahájení těžby.
|
||||
chainable:
|
||||
name: Extraktor (Navazující)
|
||||
description: Umístěte na náleziště tvaru nebo barvy pro zahájení těžby. Lze
|
||||
description: Umístěte na naleziště tvaru nebo barvy pro zahájení těžby. Lze
|
||||
zapojit po skupinách.
|
||||
underground_belt:
|
||||
default:
|
||||
@ -470,7 +470,7 @@ buildings:
|
||||
balancer:
|
||||
default:
|
||||
name: Vyvažovač
|
||||
description: Multifunkční - Rozděluje vstupy do výstupy.
|
||||
description: Multifunkční - Rovnoměrně rozděluje vstupy na výstupech.
|
||||
merger:
|
||||
name: Spojovač (kompaktní)
|
||||
description: Spojí dva pásy do jednoho.
|
||||
@ -535,7 +535,7 @@ buildings:
|
||||
reader:
|
||||
default:
|
||||
name: Čtečka pásů
|
||||
description: Umožňuje měřit průměrnou propustnost pásu. Výstup čte poslední
|
||||
description: Umožňuje změřit průměrnou propustnost pásu. Výstup čte poslední
|
||||
položku ve vrstvě kabelů.
|
||||
analyzer:
|
||||
default:
|
||||
@ -633,7 +633,7 @@ storyRewards:
|
||||
barvy!
|
||||
reward_storage:
|
||||
title: Sklad
|
||||
desc: Právě jste odemkli <strong>sklad</strong> - Umožnuje skladovat přebytečné věci
|
||||
desc: Právě jste odemkli <strong>sklad</strong> - Umožnuje skladovat přebytečné věci
|
||||
až do naplnění kapacity!<br><br> Dává prioritu levému
|
||||
výstupu, takže ho také můžete použít jako <strong>průtokovou bránu</strong>!
|
||||
reward_freeplay:
|
||||
@ -732,7 +732,7 @@ settings:
|
||||
general: Obecné
|
||||
userInterface: Uživatelské rozhraní
|
||||
advanced: Rozšířené
|
||||
performance: Performance
|
||||
performance: Výkon
|
||||
versionBadges:
|
||||
dev: Vývojová verze
|
||||
staging: Testovací verze
|
||||
@ -742,7 +742,7 @@ settings:
|
||||
uiScale:
|
||||
title: Škálování UI
|
||||
description: Změní velikost uživatelského rozhraní. Rozhraní se bude stále
|
||||
přizpůsobovoat rozlišení vaší obrazovky, toto nastavení pouze
|
||||
přizpůsobovat rozlišení vaší obrazovky, toto nastavení pouze
|
||||
mění jeho škálu.
|
||||
scales:
|
||||
super_small: Velmi malé
|
||||
@ -751,7 +751,7 @@ settings:
|
||||
large: Velké
|
||||
huge: Obrovské
|
||||
scrollWheelSensitivity:
|
||||
title: Citlivost přibížení
|
||||
title: Citlivost přiblížení
|
||||
description: Změní citlivost přiblížení (kolečkem myši nebo trackpadem).
|
||||
sensitivity:
|
||||
super_slow: Hodně pomalé
|
||||
@ -801,8 +801,8 @@ settings:
|
||||
slow: Pomalá
|
||||
regular: Normální
|
||||
fast: Rychlá
|
||||
super_fast: Hodně Rychlá
|
||||
extremely_fast: Extrémně Rychlá
|
||||
super_fast: Hodně rychlá
|
||||
extremely_fast: Extrémně rychlá
|
||||
enableTunnelSmartplace:
|
||||
title: Chytré tunely
|
||||
description: Pokládání tunelů po zapnutí bude samo odstraňovat nepotřebné pásy.
|
||||
@ -829,7 +829,7 @@ settings:
|
||||
koeficient. V opačném případě zobrazí popis a obrázek.
|
||||
disableCutDeleteWarnings:
|
||||
title: Zakázat upozornění o vyjmutí nebo odstranění
|
||||
description: Deaktivujte varovná dialogová okna vyvolaná při vymutí/mazání více
|
||||
description: Deaktivujte varovná dialogová okna vyvolaná při vyjmutí/mazání více
|
||||
než 100 entit.
|
||||
enableColorBlindHelper:
|
||||
title: Režim pro barvoslepé
|
||||
@ -965,7 +965,7 @@ about:
|
||||
|
||||
Pokud se chceš na hře podílet, podívej se na <a href="<githublink>" target="_blank">shapez.io na githubu</a>.<br><br>
|
||||
|
||||
Tato hra by nebyla ani možná bez skvělé Discord komunity okolo Tobiasových her - Vážně by ses měl přijít mrknout na <a href="<discordlink>" target="_blank">Discord server</a>!<br><br>
|
||||
Tato hra by nebyla možná ani bez skvělé Discord komunity okolo Tobiasových her - Vážně by ses měl přijít mrknout na <a href="<discordlink>" target="_blank">Discord server</a>!<br><br>
|
||||
|
||||
Soundtrack udělal <a href="https://soundcloud.com/pettersumelius" target="_blank">Peppsen</a> - Je úžasnej.<br><br>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io er et afslapet spil hvor du skal bygge fabrikker for at
|
||||
automatisere productionen af geometriske figurer.
|
||||
automatisere productionen af geometriske figurer.
|
||||
|
||||
Jo længer du når, jo mere kompliseret bliver figurene, og du bliver nød til at spræde dig ud på den grænseløse spilleflade.
|
||||
|
||||
|
||||
@ -1,40 +1,39 @@
|
||||
---
|
||||
steamPage:
|
||||
shortText: In shapez.io nutzt du die vorhandenen Ressourcen, um mit deinen
|
||||
Maschinen durch Kombination immer komplexere Formen zu erschaffen.
|
||||
discordLinkShort: Offizieller Discord
|
||||
intro: >-
|
||||
Du magst Automatisierungsspiele? Dann bist du hier genau richtig!
|
||||
|
||||
shapez.io ist ein ruhiges Spiel, in dem du Fabriken zur automatisierten Produktion von geometrischen Formen bauen musst. Mit steigendem Level werden die Formen immer komplexer, und du musst dich auf der unendlich großen Karte ausbreiten.
|
||||
|
||||
Und als ob das noch nicht genug wäre, musst du auch exponentiell mehr produzieren, um die Anforderungen zu erfüllen - Da hilft nur skalieren! Während du am Anfang nur Formen verarbeitest, musst du diese später einfärben - Dafür musst du Farben extrahieren und mischen!
|
||||
|
||||
Der Kauf des Spiels auf Steam gibt dir Zugriff auf die Vollversion, du kannst aber auch zuerst eine Demo auf shapez.io spielen und dich später entscheiden!
|
||||
shapez.io ist ein ruhiges Spiel, in dem du Fabriken zur automatisierten Produktion von geometrischen Formen bauen musst.
|
||||
Mit steigendem Level werden die Formen immer komplexer, und du musst dich auf der unendlich großen Karte ausbreiten.
|
||||
Das ist noch nicht alles, denn du musst exponentiell mehr produzieren, um die Anforderungen zu erfüllen - Da hilft nur skalieren!
|
||||
Während du am Anfang nur Formen verarbeitest, musst du diese später auch einfärben - Dafür musst du Farben extrahieren und mischen!
|
||||
Der Kauf des Spiels auf Steam gibt dir Zugriff auf die Vollversion, aber du kannst auch zuerst die Demo auf shapez.io spielen und dich später entscheiden!
|
||||
title_advantages: Vorteile der Vollversion
|
||||
advantages:
|
||||
- <b>12 Neue Level</b> für insgesamt 26 Level
|
||||
- <b>18 Neue Gebäude</b> für eine komplett automatisierte Fabrik!
|
||||
- <b>20 Upgrade Stufen</b> für viele Stunden Spielspaß
|
||||
- <b>Wires Update</b> für eine komplett neue Dimension!
|
||||
- <b>Dark Mode</b>!
|
||||
- <b>20 Upgrade-Stufen</b> für viele Stunden Spielspaß
|
||||
- <b>Wires-Update</b> für eine komplett neue Dimension!
|
||||
- <b>Dark-Mode</b>!
|
||||
- Unbegrenzte Speicherstände
|
||||
- Unbegrenzte Wegpunkte
|
||||
- Unterstütze mich! ❤️
|
||||
discordLinkShort: Offizieller Discord
|
||||
title_future: Geplante Inhalte
|
||||
planned:
|
||||
- Blaupausen-Bibliothek
|
||||
- Steam Errungenschaften
|
||||
- Errungenschaften auf Steam
|
||||
- Puzzel-Modus
|
||||
- Minimap
|
||||
- Mod Unterstützung
|
||||
- Sandkasten - Modus
|
||||
- Modunterstützung
|
||||
- Sandkastenmodus
|
||||
- ... und noch viel mehr!
|
||||
title_open_source: Dieses Spiel ist Quelloffen!
|
||||
title_open_source: Dieses Spiel ist quelloffen!
|
||||
text_open_source: >-
|
||||
Jeder kann etwas zum Spiel beitragen! Ich engagiere mich aktiv in der
|
||||
Community und versuche alle Vorschläge zu berücksichtigen.
|
||||
|
||||
Die vollständige Roadmap findet ihr in meinem Trello-Board!
|
||||
Die vollständige Roadmap findet ihr auf meinem Trello-Board!
|
||||
title_links: Links
|
||||
links:
|
||||
discord: Offizieller Discord
|
||||
@ -45,7 +44,7 @@ steamPage:
|
||||
global:
|
||||
loading: Laden
|
||||
error: Fehler
|
||||
thousandsDivider: .
|
||||
thousandsDivider: "."
|
||||
decimalSeparator: ","
|
||||
suffix:
|
||||
thousands: k
|
||||
@ -74,16 +73,16 @@ global:
|
||||
shift: UMSCH
|
||||
space: LEER
|
||||
demoBanners:
|
||||
title: Demo Version
|
||||
title: Demo-Version
|
||||
intro: Kauf die Vollversion für alle Features!
|
||||
mainMenu:
|
||||
play: Spielen
|
||||
changelog: Änderungsprotokoll
|
||||
continue: Fortsetzen
|
||||
newGame: Neues Spiel
|
||||
changelog: Änderungsprotokoll
|
||||
subreddit: Reddit
|
||||
importSavegame: Importieren
|
||||
openSourceHint: Dieses Spiel ist Open Source!
|
||||
openSourceHint: Dieses Spiel ist quelloffen!
|
||||
discordLink: Offizieller Discord Server
|
||||
helpTranslate: Hilf beim Übersetzen!
|
||||
madeBy: Ein Spiel von <author-link>
|
||||
@ -110,7 +109,7 @@ dialogs:
|
||||
title: Importfehler
|
||||
text: "Fehler beim Importieren deines Speicherstands:"
|
||||
importSavegameSuccess:
|
||||
title: Speicherstand Importieren
|
||||
title: Speicherstand importiert
|
||||
text: Dein Speicherstand wurde erfolgreich importiert.
|
||||
gameLoadFailure:
|
||||
title: Der Speicherstand ist kaputt
|
||||
@ -121,13 +120,13 @@ dialogs:
|
||||
'<savegameName>' auf Level <savegameLevel><br><br>Das kann nicht rückgängig gemacht werden!
|
||||
savegameDeletionError:
|
||||
title: Löschen fehlgeschlagen
|
||||
text: "Das Löschen des Spiels ist fehlgeschlagen:"
|
||||
text: "Das Löschen des Speicherstands ist fehlgeschlagen:"
|
||||
restartRequired:
|
||||
title: Neustart nötig
|
||||
text: Du musst das Spiel neu starten, um die Einstellungen anzuwenden.
|
||||
editKeybinding:
|
||||
title: Tastenbelegung ändern
|
||||
desc: Drücke die (Maus-)Taste, die du belegen möchtest, oder ESC um abzubrechen.
|
||||
desc: Drücke die (Maus-)Taste, die du belegen möchtest, oder ESC zum Abbrechen.
|
||||
resetKeybindingsConfirmation:
|
||||
title: Tastenbelegung zurücksetzen
|
||||
desc: Dies wird alle deine Tastenbelegungen auf den Standard zurücksetzen. Bist
|
||||
@ -138,16 +137,16 @@ dialogs:
|
||||
featureRestriction:
|
||||
title: Demo-Version
|
||||
desc: Du hast ein Feature benutzt (<feature>), welches nicht in der Demo
|
||||
enthalten ist. Erwerbe die Vollversion auf Steam für das volle Erlebnis!
|
||||
enthalten ist. Erwerbe die Vollversion für das volle Erlebnis!
|
||||
oneSavegameLimit:
|
||||
title: Begrenzte Spielstände
|
||||
desc: Du kannst in der Demo nur einen Spielstand haben. Bitte lösche den
|
||||
existierenden Spielstand oder hole dir die Vollversion!
|
||||
title: Begrenzte Speicherstände
|
||||
desc: Du kannst in der Demo nur einen Speicherstand haben. Bitte lösche den
|
||||
existierenden oder hole dir die Vollversion!
|
||||
updateSummary:
|
||||
title: Neues Update!
|
||||
desc: "Hier sind die Änderungen, seitdem du das letzte Mal gespielt hast:"
|
||||
upgradesIntroduction:
|
||||
title: Upgrades Freischalten
|
||||
title: Upgrades freischalten
|
||||
desc: >-
|
||||
Viele deiner Formen können noch benutzt werden, um Upgrades freizuschalten
|
||||
- <strong>Zerstöre deine alten Fabriken nicht!</strong> Den
|
||||
@ -179,26 +178,26 @@ dialogs:
|
||||
<code class='keybinding'>ALT</code>: Invertiere die Platzierungsrichtung der Förderbänder.<br>
|
||||
createMarker:
|
||||
title: Neuer Marker
|
||||
desc: Vergib einen vernünftigen namen, du kannst auch den <strong>Kurz-Code</strong> einer Form eingeben (Welchen du <link>hier</link>) generieren kannst.
|
||||
titleEdit: Marker bearbeiten
|
||||
desc: Gib ihm einen griffigen Namen. Du kannst auch den <strong>Kurz-Code</strong> einer Form eingeben (Welchen du <link>hier</link> generieren kannst).
|
||||
editSignal:
|
||||
title: Signal setzen
|
||||
descItems: "Wähle ein vordefiniertes Item:"
|
||||
descShortKey: ... oder gib den <strong>Kurz-Code</strong> einer Form an (Welchen du <link>hier</link> generieren kannst).
|
||||
markerDemoLimit:
|
||||
desc: Du kannst nur 2 Marker in der Demo benutzen. Hol dir die Vollversion, um
|
||||
desc: Du kannst nur 2 Marker in der Demo benutzen. Hole dir die Vollversion, um
|
||||
unendlich viele Marker zu erstellen!
|
||||
exportScreenshotWarning:
|
||||
title: Bildschirmfoto exportieren
|
||||
desc: Hier kannst du ein Bildschirmfoto von deiner ganzen Fabrik erstellen. Für
|
||||
extrem große Fabriken kann das jedoch sehr lange dauern und ggf. zum
|
||||
Spielabsturz führen!
|
||||
editSignal:
|
||||
title: Signal Setzen
|
||||
descItems: "Wähle ein vordefiniertes item:"
|
||||
descShortKey: ... oder gib den <strong>Kurz-Code</strong> einer Form an (Welchen du <link>hier</link> generieren kannst)
|
||||
renameSavegame:
|
||||
title: Speicherstand umbenennen
|
||||
desc: Hier kannst du deinen Speicherstand umbenennen.
|
||||
entityWarning:
|
||||
title: Leistungswarnung
|
||||
desc: Du hast eine Menge Gebäude platziert, das hier ist nur ein freundlicher Hinweis dass das Spiel nicht mit unendlich vielen Gebäuden umgehen kann!
|
||||
desc: Du hast eine Menge Gebäude platziert. Das hier ist nur ein freundlicher Hinweis, dass das Spiel nicht mit unendlich vielen Gebäuden umgehen kann. Halte deine Fabriken kompakt!
|
||||
ingame:
|
||||
keybindingsOverlay:
|
||||
moveMap: Bewegen
|
||||
@ -229,9 +228,9 @@ ingame:
|
||||
cyan: Cyan
|
||||
white: Weiß
|
||||
black: Schwarz
|
||||
uncolored: Farblos
|
||||
uncolored: Grau
|
||||
buildingPlacement:
|
||||
cycleBuildingVariants: Presse <key> zum Wechseln
|
||||
cycleBuildingVariants: Drücke <key> zum Wechseln
|
||||
hotkeyLabel: "Taste: <key>"
|
||||
infoTexts:
|
||||
speed: Geschw.
|
||||
@ -284,11 +283,10 @@ ingame:
|
||||
description: Alle im Hub gelagerten Formen.
|
||||
produced:
|
||||
title: Produziert
|
||||
description: Alle Formen, die in deiner Fabrik hergestellt werden, einschließlich Zwischenprodukte.
|
||||
description: Alle in deiner Fabrik hergestellten Formen inkl. Zwischenprodukte.
|
||||
delivered:
|
||||
title: Geliefert
|
||||
description: Formen, die an den Hub geliefert werden.
|
||||
|
||||
description: An den Hub gelieferte Formen.
|
||||
noShapesProduced: Es werden noch keine Formen produziert oder geliefert.
|
||||
shapesDisplayUnits:
|
||||
second: <shapes> / s
|
||||
@ -298,7 +296,6 @@ ingame:
|
||||
playtime: Spielzeit
|
||||
buildingsPlaced: Gebäude
|
||||
beltsPlaced: Förderbänder
|
||||
|
||||
tutorialHints:
|
||||
title: Brauchst du Hilfe?
|
||||
showHint: Hinweis
|
||||
@ -306,7 +303,7 @@ ingame:
|
||||
blueprintPlacer:
|
||||
cost: Kosten
|
||||
waypoints:
|
||||
waypoints: Markierungen
|
||||
waypoints: Marker
|
||||
hub: Hub
|
||||
description: Linksklick auf einen Marker, um dort hinzugelangen. Rechtsklick, um
|
||||
ihn zu löschen.<br><br>Drücke <keybinding>, um einen Marker aus
|
||||
@ -318,29 +315,29 @@ ingame:
|
||||
empty: Leer
|
||||
copyKey: Schlüssel kopieren
|
||||
interactiveTutorial:
|
||||
title: Tutorial
|
||||
title: Einführung
|
||||
hints:
|
||||
1_1_extractor: Platziere einen <strong>Extrahierer</strong> auf der
|
||||
<strong>Kreisform</strong>, um sie zu extrahieren!
|
||||
1_2_conveyor: "Verbinde den Extrahierer mit einem <strong>Förderband</strong>
|
||||
1_2_conveyor: "Verbinde den Extrahierer mit einem <strong>Fließband</strong>
|
||||
und schließe ihn am Hub an!<br><br>Tipp: <strong>Drücke und
|
||||
ziehe</strong> das Förderband mit der Maus!"
|
||||
ziehe</strong> das Fließband mit der Maus!"
|
||||
1_3_expand: "Dies ist <strong>KEIN</strong> Idle-Game! Baue mehr Extrahierer und
|
||||
Förderbänder, um das Ziel schneller zu erreichen.<br><br>Tipp:
|
||||
Halte <strong>UMSCH</strong>, um mehrere Gebäude zu platzieren
|
||||
und nutze <strong>R</strong>, um sie zu rotieren."
|
||||
connectedMiners:
|
||||
one_miner: 1 Extrahierer
|
||||
one_miner: Ein Extrahierer
|
||||
n_miners: <amount> Extrahierer
|
||||
limited_items: Begrenzt auf <max_throughput>
|
||||
watermark:
|
||||
title: Demo Version
|
||||
title: Demo-Version
|
||||
desc: Klicke hier, um die Vorteile der Vollversion zu sehen!
|
||||
get_on_steam: Zur Vollversion
|
||||
|
||||
standaloneAdvantages:
|
||||
title: Vorteile der Vollversion
|
||||
no_thanks: Nein, Dank!
|
||||
no_thanks: Nein, danke!
|
||||
points:
|
||||
levels:
|
||||
title: 12 Neue Level
|
||||
@ -352,20 +349,20 @@ ingame:
|
||||
title: ∞ Speicherstände
|
||||
desc: So viele dein Herz begehrt!
|
||||
upgrades:
|
||||
title: 20 Upgrade Stufen
|
||||
title: 20 Upgrade-Stufen
|
||||
desc: Diese Demo hat nur 5!
|
||||
markers:
|
||||
title: ∞ Marker
|
||||
desc: Verliere dich nie in deiner Fabrik!
|
||||
desc: Verliere nie den Überblick!
|
||||
wires:
|
||||
title: Wires
|
||||
desc: Eine ganz neue Dimension!
|
||||
darkmode:
|
||||
title: Dark Mode
|
||||
title: Dark-Mode
|
||||
desc: Werde nicht mehr geblendet!
|
||||
support:
|
||||
title: Unterstütze Mich
|
||||
desc: Ich verwende meine Freizeit!
|
||||
desc: Ich entwickle in meiner Freizeit!
|
||||
shopUpgrades:
|
||||
belt:
|
||||
name: Förderbänder, Verteiler & Tunnel
|
||||
@ -382,12 +379,12 @@ shopUpgrades:
|
||||
buildings:
|
||||
hub:
|
||||
deliver: Liefere
|
||||
toUnlock: "Für die Belohnung:"
|
||||
toUnlock: "und schalte frei:"
|
||||
levelShortcut: LVL
|
||||
endOfDemo: Ende der Demo
|
||||
belt:
|
||||
default:
|
||||
name: Förderband
|
||||
name: Fließband
|
||||
description: Transportiert Items. Halte und ziehe, um mehrere zu platzieren.
|
||||
miner:
|
||||
default:
|
||||
@ -406,13 +403,29 @@ buildings:
|
||||
name: Tunnel Stufe II
|
||||
description: Erlaubt dir, Formen und Farbe unter Gebäuden und Förderbändern
|
||||
durchzuleiten. Höhere Reichweite.
|
||||
balancer:
|
||||
default:
|
||||
name: Verteiler
|
||||
description: Multifunktional - Verteilt alle Eingänge gleichmäßig auf die Ausgänge.
|
||||
merger:
|
||||
name: Kombinierer (kompakt)
|
||||
description: Kombiniert zwei Fließbänder zu einem.
|
||||
merger-inverse:
|
||||
name: Kombinierer (kompakt)
|
||||
description: Kombiniert zwei Fließbänder zu einem.
|
||||
splitter:
|
||||
name: Aufteiler (kompakt)
|
||||
description: Teilt ein Fließband in zwei.
|
||||
splitter-inverse:
|
||||
name: Aufteiler (kompakt)
|
||||
description: Teilt ein Fließband in zwei.
|
||||
cutter:
|
||||
default:
|
||||
name: Schneider
|
||||
description: Zerschneidet Formen von oben nach unten. <strong>Benutze oder
|
||||
zerstöre beide Hälften, sonst verstopft die Maschine!</strong>
|
||||
quad:
|
||||
name: Schneider (Vierfach)
|
||||
name: Schneider (vierfach)
|
||||
description: Zerschneidet Formen in vier Teile. <strong>Benutze oder zerstöre
|
||||
alle Viertel, sonst verstopft die Maschine!</strong>
|
||||
rotater:
|
||||
@ -444,11 +457,11 @@ buildings:
|
||||
description: Färbt die ganze Form aus dem linken Eingang mit der Farbe aus dem
|
||||
oberen Eingang.
|
||||
double:
|
||||
name: Färber (2-fach)
|
||||
name: Färber (zweifach)
|
||||
description: Färbt beide Formen aus dem linken Eingang mit der Farbe aus dem
|
||||
oberen Eingang.
|
||||
quad:
|
||||
name: Färber (4-fach)
|
||||
name: Färber (vierfach)
|
||||
description: Erlaubt dir, jeden Quadranten der Form individuell zu färben. Nur
|
||||
Quadranten mit einem <strong>wahren Signal</strong> auf der Wires-Ebene
|
||||
werden angemalt!
|
||||
@ -457,49 +470,33 @@ buildings:
|
||||
name: Mülleimer
|
||||
description: Akzeptiert Formen und Farben aus jeder Richtung und zerstört sie.
|
||||
Für immer ...
|
||||
wire:
|
||||
default:
|
||||
name: Signalkabel
|
||||
description: Erlaubt dir Signale zu transportieren.
|
||||
second:
|
||||
name: Signalkabel
|
||||
description: Überträgt Signale, die Gegenstände, Farben oder Wahrheitswerte (1 oder 0) sein können. Unterschiedlich farbige Kabel verbinden sich nicht miteinander.
|
||||
balancer:
|
||||
default:
|
||||
name: Verteiler
|
||||
description: Multifunktional - Verteilt alle Eingänge gleichmäßig auf alle Ausgänge.
|
||||
merger:
|
||||
name: Kombinierer (kompakt)
|
||||
description: Kombiniert zwei Fließbänder in eins.
|
||||
merger-inverse:
|
||||
name: Kombinierer (kompakt)
|
||||
description: Kombiniert zwei Fließbänder in eins.
|
||||
splitter:
|
||||
name: Verteiler (kompakt)
|
||||
description: Teilt ein Fließband in zwei.
|
||||
splitter-inverse:
|
||||
name: Verteiler (kompakt)
|
||||
description: Teilt ein Fließband in zwei.
|
||||
storage:
|
||||
default:
|
||||
name: Speicher
|
||||
description:
|
||||
Speichert überschüssige Gegenstände, bis zu einer bestimmten Kapazität. Priorisiert den linken
|
||||
Ausgang und kann als Überlauftor verwendet werden.
|
||||
wire:
|
||||
default:
|
||||
name: Signalkabel
|
||||
description: Erlaubt den Transport von Signalen. Das sind Items, Farben oder Wahrheitswerte (1 oder 0). Unterschiedlich gefärbte Kabel verbinden sich nicht.
|
||||
second:
|
||||
name: Signalkabel
|
||||
description: Erlaubt den Transport von Signalen. Das sind Items, Farben oder Wahrheitswerte (1 oder 0). Unterschiedlich gefärbte Kabel verbinden sich nicht.
|
||||
wire_tunnel:
|
||||
default:
|
||||
name: Signal-Kreuzung
|
||||
description: Erlaubt es, zwei Kabel zu kreuzen, ohne sie zu verbinden.
|
||||
name: Kabelkreuzung
|
||||
description: Erschafft eine isolierte Kreuzung zweier Kabel.
|
||||
constant_signal:
|
||||
default:
|
||||
name: Konstantes Signal
|
||||
description: Sendet ein konstantes Signal, das entweder eine Form, eine Farbe oder
|
||||
Wahrheitswert (1 / 0) sein kann.
|
||||
name: Signalgeber
|
||||
description: Sendet ein konstantes Signal. Du wählst zwischen Formen, Farben oder
|
||||
Wahrheitswerten (1 oder 0).
|
||||
lever:
|
||||
default:
|
||||
name: Schalter
|
||||
description:
|
||||
Kann umgeschaltet werden, um einen Wahrheitswert (1 / 0) auf der Wires-Ebene auszusenden,
|
||||
Sendet einen Wahrheitswert (1 oder 0) auf der Wires-Ebene abhängig von seiner Stellung,
|
||||
welcher dann z.B. zur Steuerung eines Filters verwendet werden kann.
|
||||
logic_gate:
|
||||
default:
|
||||
@ -516,7 +513,7 @@ buildings:
|
||||
(wahr bedeutet Form, Farbe oder "1").
|
||||
or:
|
||||
name: ODER Gatter
|
||||
description: Gibt eine "1" aus, wenn eine der Eingäge wahr ist (wahr bedeutet Form, Farbe oder "1").
|
||||
description: Gibt eine "1" aus, wenn einer der Eingänge wahr ist (wahr bedeutet Form, Farbe oder "1").
|
||||
transistor:
|
||||
default:
|
||||
name: Transistor
|
||||
@ -533,12 +530,12 @@ buildings:
|
||||
restlichen nach rechts. Kann auch mit Wahrheitswerten gesteuert werden.
|
||||
display:
|
||||
default:
|
||||
name: Display
|
||||
description: Verbinde ein Signal, um es auf dem Display anzuzeigen - Es kann eine Form sein,
|
||||
Farbe oder Wahrheitswert.
|
||||
name: Anzeige
|
||||
description: Verbinde ein Signal, um es auf der Anzeige darzustellen. Es kann eine Form,
|
||||
Farbe oder ein Wahrheitswert sein.
|
||||
reader:
|
||||
default:
|
||||
name: Fließband Leser
|
||||
name: Fließbandkontrolle
|
||||
description:
|
||||
Ermöglicht es, den durchschnittlichen Durchsatz des Fließbandes zu messen. Gibt den letzten
|
||||
Gegenstand auf der Wires-Ebene aus (sobald freigeschaltet).
|
||||
@ -550,7 +547,7 @@ buildings:
|
||||
comparator:
|
||||
default:
|
||||
name: Vergleich
|
||||
description: Gibt eine "1" zurück, wenn beide Signale genau gleich sind. Kann Formen, Gegenstände und Wahrheitswerte vergleichen.
|
||||
description: Gibt eine "1" zurück, wenn beide Signale genau gleich sind. Kann Formen, Farben und Wahrheitswerte vergleichen.
|
||||
virtual_processor:
|
||||
default:
|
||||
name: Virtueller Schneider
|
||||
@ -559,7 +556,7 @@ buildings:
|
||||
name: Virtueller Rotierer
|
||||
description: Dreht die Form virtuell, sowohl im als auch gegen den Uhrzeigersinn.
|
||||
unstacker:
|
||||
name: Virtueller Unstapler
|
||||
name: Virtueller Entstapler
|
||||
description: Extrahiert virtuell die oberste Ebene nach rechts und die
|
||||
die restlichen Ebenen nach links.
|
||||
stacker:
|
||||
@ -568,11 +565,10 @@ buildings:
|
||||
painter:
|
||||
name: Virtueller Färber
|
||||
description: Färbt virtuell die Form vom unteren Eingang mit der Farbe aus dem rechten Eingang.
|
||||
|
||||
item_producer:
|
||||
default:
|
||||
name: Item-Produzent
|
||||
description: Nur im Sandbox-Modus verfügbar, gibt das Signal aus der Wires-Ebene auf der regulären Schicht aus.
|
||||
description: Nur im Sandkastenmodus verfügbar. Gibt das Signal aus der Wires-Ebene auf der regulären Ebene aus.
|
||||
storyRewards:
|
||||
reward_cutter_and_trash:
|
||||
title: Formen zerschneiden
|
||||
@ -602,10 +598,10 @@ storyRewards:
|
||||
sie nebeneinander, werden sie <strong>verschmolzen</strong>.
|
||||
Anderenfalls wird die rechte auf die linke Form
|
||||
<strong>gestapelt</strong>.
|
||||
reward_splitter:
|
||||
title: Verteiler/Kombinierer
|
||||
desc: Du hast eine <strong>Splitter</strong> Variante des
|
||||
<strong>Verteilers</strong> freigeschaltet - Er teilt ein Fließband auf zwei auf!
|
||||
reward_balancer:
|
||||
title: Verteiler
|
||||
desc: Der multifunktionale <strong>Verteiler</strong> wurde freigeschaltet! Er kann
|
||||
benutzt werden, um größere Fabriken zu bauen, indem Items auf Fließbänder aufgeteilt oder zusammengelegt werden!
|
||||
reward_tunnel:
|
||||
title: Tunnel
|
||||
desc: Der <strong>Tunnel</strong> wurde freigeschaltet! Du kannst Items nun
|
||||
@ -627,68 +623,59 @@ storyRewards:
|
||||
desc: Du hast eine neue Variante des <strong>Tunnels</strong> freigeschaltet!
|
||||
Dieser hat eine <strong>höhere Reichweite</strong> und du kannst
|
||||
beide Tunnel miteinander mischen.
|
||||
reward_merger:
|
||||
title: Kompakter Kombinierer
|
||||
desc: Du hast eine <strong>kompakte Variante</strong> des <strong>Verteilers</strong>
|
||||
freigeschaltet! Der Kombinierer vereint zwei Eingäge zu einem Ausgang.
|
||||
reward_splitter:
|
||||
title: Kompakter Aufteiler
|
||||
desc: Du hast eine <strong>kompakte Variante</strong> des <strong>Verteilers</strong>
|
||||
freigeschaltet! Der Aufteiler spaltet einen Eingang in zwei Aufgänge auf.
|
||||
reward_belt_reader:
|
||||
title: Fließbandkontrolle
|
||||
desc: Du hast nun die <strong>Fließbandkontrolle</strong> freigeschaltet! Damit kannst du dir
|
||||
den Durchsatz eines Fließbandes anzeigen lassen.<br><br>Wenn du Stromkabel freischaltest,
|
||||
wird er um eine sehr nützliche Funktion ergänzt!
|
||||
reward_cutter_quad:
|
||||
title: Schneider (4-fach)
|
||||
desc: Du hast eine neue Variante des <strong>Schneiders</strong> freigeschaltet!
|
||||
Damit kannst du Formen in alle <strong>vier Teile</strong>
|
||||
zerschneiden.
|
||||
Damit kannst du Formen in alle <strong>vier Teile</strong> zerschneiden.
|
||||
reward_painter_double:
|
||||
title: Färber (2-fach)
|
||||
desc: Du hast eine neue Variante des <strong>Färbers</strong> freigeschaltet!
|
||||
Hiermit kannst du <strong>zwei Formen auf einmal</strong> färben und
|
||||
verbrauchst nur eine Farbe.
|
||||
reward_storage:
|
||||
title: Speicher
|
||||
desc: Du hast das <strong>Speicher</strong> Gebäude freigeschaltet - Es erlaubt dir
|
||||
title: Lager
|
||||
desc: Du hast das <strong>Lager</strong> freigeschaltet! Es erlaubt dir,
|
||||
Gegenstände bis zu einer bestimmten Kapazität zu speichern!<br><br>
|
||||
Es priorisiert den linken Ausgang, also kannst du es auch als <strong>Überlauftor</strong> benutzen!
|
||||
reward_freeplay:
|
||||
title: Freies Spiel
|
||||
desc: >-
|
||||
Du hast es geschafft! Du hast den <strong>Freispiel-Modus</strong> freigeschaltet! Das bedeutet,
|
||||
dass die Formen jetzt <strong>zufällig</strong> erzeugt werden!<br><br>
|
||||
|
||||
Da der Hub ab jetzt einen <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 ist alles was du tun musst, sie zu analysieren und
|
||||
automatisch deine Fabrik basierend darauf zu konfigurieren.
|
||||
|
||||
reward_blueprints:
|
||||
title: Blaupause
|
||||
title: Blaupausen
|
||||
desc: Jetzt kannst du Teile deiner Fabrik <strong>kopieren und
|
||||
einfügen</strong>! Wähle ein Areal aus (Halte STRG und ziehe mit
|
||||
deiner Maus) und drücke 'C', um zu kopieren.<br><br>Einfügen ist
|
||||
<strong>nicht kostenlos</strong>, du musst
|
||||
<strong>nicht kostenlos</strong>! Du musst
|
||||
<strong>Blaupausenformen</strong> produzieren, um die Kopierkosten
|
||||
zu decken (Welche du gerade produziert hast)!
|
||||
no_reward:
|
||||
title: Nächstes Level
|
||||
desc: "Dieses Level hat dir keine Belohnung gegeben, aber im Nächsten gibt es
|
||||
eine! <br><br> PS: Denke daran, deine alten Fabriken nicht zu
|
||||
zerstören - Du wirst sie später <strong>alle</strong> noch brauchen,
|
||||
um <strong>Upgrades freizuschalten</strong>!"
|
||||
no_reward_freeplay:
|
||||
title: Nächstes Level
|
||||
desc: Du hast das nächste Level freigeschalten!
|
||||
|
||||
reward_balancer:
|
||||
title: Verteiler
|
||||
desc: Der multifunktionale <strong>Verteiler</strong> wurde freigeschaltet - Er kann
|
||||
benutzt werden, um größere Fabriken zu bauen, indem Gegenstände auf mehrere Fließbänder aufgeteilt und zusammengelegt werden!
|
||||
reward_merger:
|
||||
title: Kompakter Verteiler
|
||||
desc: >-
|
||||
Du hast eine <strong>kompakte Variante</strong> des <strong>Verteilers</strong> freigeschalten - Sie verteilt zwei Fließbänder auf eins!
|
||||
reward_belt_reader:
|
||||
title: Fließband Leser
|
||||
desc: You have now unlocked the <strong>belt reader</strong>! It allows you to
|
||||
measure the throughput of a belt.<br><br>And wait until you unlock
|
||||
wires - then it gets really useful!
|
||||
reward_rotater_180:
|
||||
title: Rotater (180 degrees)
|
||||
desc: You just unlocked the 180 degrees <strong>rotater</strong>! - It allows
|
||||
you to rotate a shape by 180 degrees (Surprise! :D)
|
||||
title: Rotierer (180°)
|
||||
desc: Du hast eine weitere Variante des <strong>Rotierers</strong> freigeschaltet! Mit ihm
|
||||
kannst du Formen um 180° drehen (Überraschung! :D).
|
||||
reward_wires_painter_and_levers:
|
||||
title: Wires & Quad Painter
|
||||
desc: "You just unlocked the <strong>Wires Layer</strong>: It is a separate
|
||||
layer on top of the regular layer and introduces a lot of new
|
||||
mechanics!<br><br> For the beginning I unlocked you the <strong>Quad
|
||||
Painter</strong> - Connect the slots you would like to paint with on
|
||||
the wires layer!<br><br> To switch to the wires layer, press
|
||||
<strong>E</strong>."
|
||||
reward_filter:
|
||||
title: Item Filter
|
||||
desc: You unlocked the <strong>Item Filter</strong>! It will route items either
|
||||
to the top or the right output depending on whether they match the
|
||||
signal from the wires layer or not.<br><br> You can also pass in a
|
||||
boolean signal (1 / 0) to entirely activate or disable it.
|
||||
reward_display:
|
||||
title: Display
|
||||
desc: "You have unlocked the <strong>Display</strong> - Connect a signal on the
|
||||
@ -718,35 +705,39 @@ storyRewards:
|
||||
shape requested by the HUB (I recommend to try it!).<br><br> - Build
|
||||
something cool with wires.<br><br> - Continue to play
|
||||
regulary.<br><br> Whatever you choose, remember to have fun!
|
||||
reward_wires_painter_and_levers:
|
||||
title: Wires & Quad Painter
|
||||
desc: "You just unlocked the <strong>Wires Layer</strong>: It is a separate
|
||||
layer on top of the regular layer and introduces a lot of new
|
||||
mechanics!<br><br> For the beginning I unlocked you the <strong>Quad
|
||||
Painter</strong> - Connect the slots you would like to paint with on
|
||||
the wires layer!<br><br> To switch to the wires layer, press
|
||||
<strong>E</strong>."
|
||||
reward_filter:
|
||||
title: Item Filter
|
||||
desc: You unlocked the <strong>Item Filter</strong>! It will route items either
|
||||
to the top or the right output depending on whether they match the
|
||||
signal from the wires layer or not.<br><br> You can also pass in a
|
||||
boolean signal (1 / 0) to entirely activate or disable it.
|
||||
no_reward:
|
||||
title: Nächstes Level
|
||||
desc: "Dieses Level hat dir keine Belohnung gegeben, aber im Nächsten gibt es
|
||||
eine! <br><br> PS: Denke daran, deine alten Fabriken nicht zu
|
||||
zerstören - Du wirst sie später <strong>alle</strong> noch brauchen,
|
||||
um <strong>Upgrades freizuschalten</strong>!"
|
||||
no_reward_freeplay:
|
||||
title: Nächstes Level
|
||||
desc: Du hast das nächste Level freigeschaltet!
|
||||
reward_freeplay:
|
||||
title: Freies Spiel
|
||||
desc: Du hast es geschafft! Du hast den <strong>Freispiel-Modus</strong> freigeschaltet! Das bedeutet,
|
||||
dass die abzuliefernden Formen jetzt <strong>zufällig</strong> erzeugt werden!<br><br>
|
||||
Da der Hub ab 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
|
||||
basierend darauf automatisch deine Fabrik konfigurieren.
|
||||
reward_demo_end:
|
||||
title: End of Demo
|
||||
desc: You have reached the end of the demo version!
|
||||
title: Ende der Demo
|
||||
desc: Du bist am Ende der Demo angekommen!
|
||||
settings:
|
||||
title: Einstellungen
|
||||
categories:
|
||||
general: Allgemein
|
||||
userInterface: Benutzeroberfläche
|
||||
advanced: Erweitert
|
||||
performance: Performance
|
||||
performance: Leistung
|
||||
versionBadges:
|
||||
dev: Entwicklung
|
||||
staging: Beta
|
||||
prod: Produktion
|
||||
buildDate: Gebaut am <at-date>
|
||||
rangeSliderPercentage: <amount> %
|
||||
labels:
|
||||
uiScale:
|
||||
title: HUD Größe
|
||||
@ -862,46 +853,44 @@ settings:
|
||||
description: Deaktiviert die Warnung, welche beim Löschen und Ausschneiden von
|
||||
mehr als 100 Feldern angezeigt wird.
|
||||
lowQualityMapResources:
|
||||
title: Low Quality Map Resources
|
||||
description: Simplifies the rendering of resources on the map when zoomed in to
|
||||
improve performance. It even looks cleaner, so be sure to try it
|
||||
out!
|
||||
title: Minimalistische Ressourcen
|
||||
description: Vereinfacht die Darstellung der Ressourcen auf der hereingezoomten Karte
|
||||
zur Verbesserung der Leistung. Die Darstellung ist übersichtlicher, also probiere
|
||||
es ruhig aus!
|
||||
disableTileGrid:
|
||||
title: Disable Grid
|
||||
description: Disabling the tile grid can help with the performance. This also
|
||||
makes the game look cleaner!
|
||||
title: Gitter deaktivieren
|
||||
description: Das Deaktivieren des Gitters kann deine Leistung verbessern. Außerdem vereinfacht
|
||||
es die Darstellung!
|
||||
clearCursorOnDeleteWhilePlacing:
|
||||
title: Clear Cursor on Right Click
|
||||
description: Enabled by default, clears the cursor whenever you right click
|
||||
while you have a building selected for placement. If disabled,
|
||||
you can delete buildings by right-clicking while placing a
|
||||
building.
|
||||
title: Abwählen mit Rechtsklick
|
||||
description: Standardmäßig eingeschaltet, wählt es das aktuelle, zur Platzierung ausgewählte Gebäude
|
||||
ab, wenn du die rechte Masutaste drückst. Wenn du es abschaltest, kannst du mit der rechten
|
||||
Maustaste Gebäude löschen, während du im Platzierungsmodus bist.
|
||||
lowQualityTextures:
|
||||
title: Low quality textures (Ugly)
|
||||
description: Uses low quality textures to save performance. This will make the
|
||||
game look very ugly!
|
||||
title: Niedrige Texturqualität (Unschön)
|
||||
description: Das Spiel verwendet eine niedrigere Auflösung bei den Texturen.
|
||||
Allerdings leidet die Grafik des Spiels sehr darunter!
|
||||
displayChunkBorders:
|
||||
title: Display Chunk Borders
|
||||
description: The game is divided into chunks of 16x16 tiles, if this setting is
|
||||
enabled the borders of each chunk are displayed.
|
||||
title: Chunk-Ränder anzeigen
|
||||
description: Das Spiel ist in Blöcke (Chunks) aus je 16x16 Feldern aufgeteilt. Diese Einstellung
|
||||
lässt dich die Grenzen zwischen den Chunks anzeigen.
|
||||
|
||||
pickMinerOnPatch:
|
||||
title: Pick miner on resource patch
|
||||
description: Enabled by default, selects the miner if you use the pipette when
|
||||
hovering a resource patch.
|
||||
title: Automatisch Extrahierer auswählen
|
||||
description: Standardmäßig eingeschaltet, wählst du automatisch den Extrahierer, wenn du mit
|
||||
der Pipette auf einen Ressourcenfleck zeigst
|
||||
simplifiedBelts:
|
||||
title: Simplified Belts (Ugly)
|
||||
description: Does not render belt items except when hovering the belt to save
|
||||
performance. I do not recommend to play with this setting if you
|
||||
do not absolutely need the performance.
|
||||
title: Minimalistische Förderbänder (Unschön)
|
||||
description: Zur Verbesserung der Leistung werden die Items auf Förderbändern nur angezeigt,
|
||||
wenn du deine Maus darüber bewegst. Hier leidet sowohl die Grafik, also auch dein
|
||||
Spielerlebnis. Benutze die Funktion nur, wenn du auf die Leistung wirklich angewiesen bist!
|
||||
enableMousePan:
|
||||
title: Enable Mouse Pan
|
||||
description: Allows to move the map by moving the cursor to the edges of the
|
||||
screen. The speed depends on the Movement Speed setting.
|
||||
rangeSliderPercentage: <amount> %
|
||||
title: Scrollen am Bildschirmrand
|
||||
description: Damit kannst du dich über die Karte bewegen, indem du deinen Mauszeiger am
|
||||
Bildschirmrand platzierst. Die Geschwindigkeit stimmt dabei mit den Tasten überein.
|
||||
keybindings:
|
||||
title: Tastenbelegung
|
||||
hint: "Tipp: Benutze STRG, UMSCH and ALT! Sie aktivieren verschiedene
|
||||
Platzierungsoptionen."
|
||||
hint: "Tipp: Benutze STRG, UMSCH and ALT! Sie aktivieren verschiedene Platzierungsoptionen."
|
||||
resetKeybindings: Tastenbelegung zurücksetzen
|
||||
categoryLabels:
|
||||
general: Anwendung
|
||||
@ -922,7 +911,7 @@ keybindings:
|
||||
centerMap: Karte zentrieren
|
||||
mapZoomIn: Reinzoomen
|
||||
mapZoomOut: Rauszoomen
|
||||
createMarker: Markierung erstellen
|
||||
createMarker: Marker erstellen
|
||||
menuOpenShop: Upgrades
|
||||
menuOpenStats: Statistiken
|
||||
menuClose: Menü schließen
|
||||
@ -930,61 +919,59 @@ keybindings:
|
||||
toggleFPSInfo: FPS und Debug-Info an/aus
|
||||
switchLayers: Ebenen wechseln
|
||||
exportScreenshot: Ganze Fabrik als Foto exportieren
|
||||
belt: Förderband
|
||||
belt: Fließband
|
||||
balancer: Verteiler
|
||||
underground_belt: Tunnel
|
||||
miner: Extrahierer
|
||||
cutter: Schneider
|
||||
rotater: Rotierer (-90°)
|
||||
rotater: Rotierer (90°)
|
||||
stacker: Stapler
|
||||
mixer: Farbmischer
|
||||
painter: Färber
|
||||
trash: Mülleimer
|
||||
storage: Lager
|
||||
wire: Stromkabel
|
||||
constant_signal: Signalgeber
|
||||
logic_gate: Logikgatter
|
||||
lever: Schalter (regulär)
|
||||
filter: Filter
|
||||
wire_tunnel: Kabelkreuzung
|
||||
display: Anzeige
|
||||
reader: Fließbandkontrolle
|
||||
virtual_processor: Virtueller Schneider
|
||||
transistor: Transistor
|
||||
analyzer: Formanalyse
|
||||
comparator: Vergleich
|
||||
item_producer: Item-Produzent (Sandkastenmodus)
|
||||
pipette: Pipette
|
||||
rotateWhilePlacing: Rotieren
|
||||
rotateInverseModifier: "Modifikator: stattdessen gegen den UZS rotieren"
|
||||
cycleBuildingVariants: Nächste Variante auswählen
|
||||
confirmMassDelete: Massenlöschung bestätigen
|
||||
confirmMassDelete: Löschen bestätigen
|
||||
pasteLastBlueprint: Letzte Blaupause einfügen
|
||||
cycleBuildings: Nächstes Gebäude auswählen
|
||||
lockBeltDirection: Bandplaner aktivieren
|
||||
switchDirectionLockSide: "Bandplaner: Seite wechseln"
|
||||
copyWireValue: "Kabel: Wert unter Mauszeiger kopieren"
|
||||
massSelectStart: Halten und ziehen zum Beginnen
|
||||
massSelectSelectMultiple: Mehrere Areale markieren
|
||||
massSelectCopy: Areal kopieren
|
||||
massSelectCut: Areal ausschneiden
|
||||
placementDisableAutoOrientation: Automatische Orientierung deaktivieren
|
||||
placeMultiple: Im Platziermodus bleiben
|
||||
placeInverse: Automatische Förderbandorientierung invertieren
|
||||
wire: Stromkabel
|
||||
balancer: Balancer
|
||||
storage: Storage
|
||||
constant_signal: Constant Signal
|
||||
logic_gate: Logic Gate
|
||||
lever: Switch (regular)
|
||||
filter: Filter
|
||||
wire_tunnel: Wire Crossing
|
||||
display: Display
|
||||
reader: Belt Reader
|
||||
virtual_processor: Virtual Cutter
|
||||
transistor: Transistor
|
||||
analyzer: Shape Analyzer
|
||||
comparator: Compare
|
||||
item_producer: Item Producer (Sandbox)
|
||||
copyWireValue: "Wires: Copy value below cursor"
|
||||
placeInverse: Automatische Fließbandorientierung invertieren
|
||||
about:
|
||||
title: Über dieses Spiel
|
||||
body: >-
|
||||
Dieses Spiel hat einen offenen Quellcode (Open Source) und wurde von <a
|
||||
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 erst durch die großartige Discord-Community um meine Spiele möglich gemacht. Komm doch einfach mal auf dem <a href="<discordlink>" target="_blank">Discord-Server</a> vorbei!<br><br>
|
||||
|
||||
Das Spiel wurde erst durch die großartige Discord-Community um meine Spiele möglich gemacht.
|
||||
Komm doch einfach mal auf dem <a href="<discordlink>" target="_blank">Discord-Server</a> vorbei!<br><br>
|
||||
Der Soundtrack wurde von <a href="https://soundcloud.com/pettersumelius" target="_blank">Peppsen</a> komponiert! Klasse Typ.<br><br>
|
||||
|
||||
Abschließend 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.
|
||||
Abschließend 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: Änderungen
|
||||
demo:
|
||||
@ -996,75 +983,59 @@ demo:
|
||||
exportingBase: Ganze Fabrik als Foto exportieren
|
||||
settingNotAvailable: Nicht verfügbar in der Demo.
|
||||
tips:
|
||||
- Der Hub akzeptiert jede Art von Form, nicht nur die aktuelle!
|
||||
- Stelle sicher, dass deine Fabriken modular sind - es zahlt sich aus!
|
||||
- Baue nicht zu nah am Hub, sonst wird es ein riesiges Chaos geben!
|
||||
- Wenn das Stapeln nicht funktioniert, versuche die Eingänge zu wechseln.
|
||||
- Du kannst mittels <b>R</b> die Richtung des Bandplaners umkehren.
|
||||
- Halte <b>STRG</b> um die Förderbänder ohne automatische Orientierung zu
|
||||
platzieren.
|
||||
- Die Ratios bleiben gleich, solange die die Upgrades auf der selben Stufen
|
||||
sind.
|
||||
- Der Hub akzeptiert alle Formen, nicht nur die aktuell geforderten!
|
||||
- Stelle sicher, dass deine Fabriken modular sind. Es zahlt sich irgendwann aus!
|
||||
- Baue nicht zu nah am Hub, sonst entsteht ein riesiges Chaos!
|
||||
- Wenn der Stapler nicht die richtige Form ausspuckt, wechsle doch mal die Eingänge.
|
||||
- Du kannst mit <b>R</b> die Richtung des Bandplaners umkehren.
|
||||
- Halte <b>STRG</b>, um die Förderbänder ohne automatische Orientierung zu platzieren.
|
||||
- Die Verhältnisse der Maschinen bleiben gleich, wenn du die Upgrades gleichmäßig kaufst.
|
||||
- Serielle Ausführung ist effizienter als parallele.
|
||||
- Du wirst später im Spiel mehr Varianten von Gebäuden freischalten!
|
||||
- Du kanst <b>T</b> drücken, um auf andere Varianten des Gebäude zu wechseln.
|
||||
- Für viele Gebäude wirst du im Spielverlauf neue Varianten freischalten!
|
||||
- Du kanst <b>T</b> drücken, um auf andere Varianten des Gebäudes zu wechseln.
|
||||
- Symmetrie ist der Schlüssel!
|
||||
- Du kannst verschiedene Arten von Tunneln miteinander verweben.
|
||||
- Versuche kompakte Fabriken zu bauen - es zahlt sich aus!
|
||||
- Der Färber hat eine spiegelverkehrte Variante, die du mittels <b>T</b>
|
||||
auswählen kannst.
|
||||
- Versuche kompakte Fabriken zu bauen. Es zahlt sich aus!
|
||||
- Der Färber hat eine spiegelverkehrte Variante, die du mit <b>T</b> auswählen kannst.
|
||||
- Das richtige Verhältnis der Gebäude maximiert die Effizienz.
|
||||
- Auf dem maximalen Level genügen 5 Extrahierer für ein einzelnes Förderband.
|
||||
- Auf der gleichen Upgrade-Stufe genügen 5 Extrahierer für ein ganzes Fließband.
|
||||
- Vergiss die Tunnel nicht!
|
||||
- Du musst die Items für maximale Effizienz nicht gleichmässig aufteilen.
|
||||
- Das Halten von <b>UMSCH</b> aktiviert den Bandplaner, der dir das
|
||||
Platzieren langer Linien vereinfacht.
|
||||
- Schneider schneiden immer vertikal, egal deren Orientierung.
|
||||
- Um Weiss zu erhalten, mixe alle Farben zusammen.
|
||||
- Der Speicher priorisiert den linken Ausgang.
|
||||
- Investiere Zeit, um wiederholbare Designs zu erstellen - es lohnt sich!
|
||||
- Das Halten von <b>STRG</b> ermöglicht dir mehrere Gebäude zu platzieren.
|
||||
- Du kanst <b>ALT</b> gedrückt halten, um die Richtung der Förderbänder
|
||||
umzukehren.
|
||||
- Effizienz ist der Schlüssel!
|
||||
- Formflecken, die weiter vom Hub entfernt sind, sind komplexer.
|
||||
- Gebäude haben eine limitierte Geschwindigkeit, teile sie auf für maximale
|
||||
Effizienz.
|
||||
- Benutze Verteiler um deine Effizienz zu maximieren.
|
||||
- Organisation ist wichtig. Versuch das Kreuzen von Förderbändern zu
|
||||
minimieren.
|
||||
- Plane im Voraus, oder es gibt ein riesigen Chaos!
|
||||
- Lösche deine alten Fabriken nicht! Du benötigst sie um Upgrades
|
||||
freizuschalten.
|
||||
- Versuch Level 20 alleine zu meistern, bevor du nach Hilfe suchst!
|
||||
- Mach es dir nicht zu kompliziert, versuch es einfach zu halten und du
|
||||
wirst weit vorankommen.
|
||||
- Vielleicht musst du Fabriken später im Spiel wiederverwenden. Plane deine
|
||||
Fabriken so, dass sie wiederverwendbar sind.
|
||||
- Manchmal kannst du die gewünschte Form auf der Karte finden, ohne sie mit
|
||||
Staplern zu erstellen.
|
||||
- Für maximale Effizienz musst du die Items nicht gleichmässig aufteilen.
|
||||
- Das Halten von <b>UMSCH</b> aktiviert den Bandplaner, der lange Förderbänder ganz einfach platziert.
|
||||
- Schneider teilen die Form immer vertikal, unabhängig von der Orientierung.
|
||||
- Weiß erhälst du aus der Kombination aller 3 Grundfarben.
|
||||
- Das Lager gibt Items immer zuerst am linken Ausgang ab.
|
||||
- Es lohnt sich, Zeit in den Bau von wiederverwendbaren Designs zu stecken!
|
||||
- Das Halten von <b>STRG</b> ermöglicht dir, mehrere Gebäude zu platzieren.
|
||||
- Du kanst <b>ALT</b> gedrückt halten, um die Richtung der Förderbänder umzukehren.
|
||||
- Effizienz ist entscheidend!
|
||||
- Abbaubare Formen werden komplexer, je weiter sie vom Hub entfernt sind.
|
||||
- Gebäude haben eine limitierte Geschwindigkeit. Teile die Last zwischen mehreren auf.
|
||||
- Benutze Aufteiler, um deine Effizienz zu maximieren.
|
||||
- Organisation ist wichtig! Verheddere dich nicht in einem Gewirr aus Förderbändern.
|
||||
- Plane vorher und lasse dir Platz für Reserven, oder es gibt ein riesiges Chaos!
|
||||
- Lösche deine alten Fabriken nicht! Du benötigst sie um Upgrades freizuschalten.
|
||||
- Versuche Level 20 alleine zu meistern, bevor du nach Hilfe suchst!
|
||||
- Mache es dir nicht zu kompliziert! Auch mit einfachen Konzepten kommst du hier sehr weit.
|
||||
- Manche Fabriken musst du später wiederverwenden. Also baue sie so, damit du genau das kannst.
|
||||
- Manchmal kannst du die gewünschte Form auf der Karte finden, ohne sie herstellen zu müssen.
|
||||
- Vollständige Windmühlen werden nicht natürlich generiert.
|
||||
- Färbe deine Formen vor dem Schneiden für maximale Effizienz.
|
||||
- Mit Modulen ist der Raum nur eine Wahrnehmung; eine Sorge für die
|
||||
sterblichen Menschen.
|
||||
- Mache eine separate Blaupausenfabrik. Sie sind wichtig für Module.
|
||||
- Schau dir den Farbmischer genauer an, und deine Fragen werden beantwortet.
|
||||
- Benutze <b>STRG</b> + rechter Mausklick, um einen Bereich zu selektieren.
|
||||
- Färbe deine Formen vor dem Schneiden! Das geht viel schneller.
|
||||
- Mit Modulen wird Platz nur noch zum Begriff; eine Sorge für Sterbliche.
|
||||
- Stelle deinen Nachschub an Blaupausen sicher. Ohne sie sind Module nutzlos.
|
||||
- Schau dir den Farbmischer genauer an und du wirst deine Antwort finden.
|
||||
- Benutze <b>STRG</b> + Rechtsklick, um einen Bereich zu selektieren.
|
||||
- Zu nahe am Hub zu bauen, kann späteren Projekten im Weg stehen.
|
||||
- Das Pin-Symbol neben jeder Form in der Upgrade-Liste heftet sie an den
|
||||
Bildschirm.
|
||||
- Die Reißzwecke neben Formen in der Upgrade-Liste lässt sie dich am Bildschirm anheften.
|
||||
- Mische alle drei Grundfarben, um Weiß zu erhalten!
|
||||
- Du hast eine unendlich grosse Karte, nutze den Platz, expandiere!
|
||||
- Du hast eine unendlich grosse Karte, nutze den Platz und expandiere!
|
||||
- Probier auch mal Factorio! Es ist mein Lieblingsspiel.
|
||||
- Der Vierfachschneider 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.
|
||||
- Dieses Spiel hat viele Einstellungen, schau sie dir einmal an!
|
||||
- Die Markierung des Hubs hat einen kleinen Kompass, der die Richtung
|
||||
anzeigt!
|
||||
- Um die Förderbänder zu leeren, schneide den Bereich aus und füge ihn in
|
||||
der gleichen Position wieder ein.
|
||||
- Drücke F4 um deine FPS und Tick Rate anzuzeigen.
|
||||
- Drücke doppelt F4 um die Kachel des Zeigers und der Kamera anzuzeigen.
|
||||
- Du kannst die angehefteten Formen auf der linken Seite ablösen.
|
||||
- Diese Spiel hat viele nützliche Tastenbelegungen! Schau sie dir in den Einstellungen an.
|
||||
- Dieses Spiel hat eine Menge Einstellungen, schaue sie dir einmal an!
|
||||
- Die Richtung zu deinem Hub ist oben rechts mit einer kleinen Kompassnadel markiert!
|
||||
- Um alle Förderbänder zu leeren, schneide den Bereich aus und füge ihn auf der selben Position wieder ein.
|
||||
- Drücke F4 um deine FPS und Tickrate anzuzeigen.
|
||||
- Drücke doppelt F4 um den Standort des Mauszeigers und der Kamera zu bestimmen.
|
||||
- Du kannst die angehefteten Formen am linken Rand wieder entfernen.
|
||||
|
||||
@ -5,7 +5,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
automated production of geometric shapes.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
|
||||
|
||||
@ -272,10 +272,6 @@ dialogs:
|
||||
title: Rename Savegame
|
||||
desc: You can rename your savegame here.
|
||||
|
||||
entityWarning:
|
||||
title: Performance Warning
|
||||
desc: You have placed a lot of buildings, this is just a friendly reminder that the game can not handle an endless number of buildings - try to keep your factories compact!
|
||||
|
||||
ingame:
|
||||
# This is shown in the top left corner and displays useful keybindings in
|
||||
# every situation
|
||||
@ -355,10 +351,6 @@ ingame:
|
||||
# Gets replaced to e.g. "Tier IX"
|
||||
tier: Tier <x>
|
||||
|
||||
# The roman number for each tier
|
||||
tierLabels:
|
||||
[I, II, III, IV, V, VI, VII, VIII, IX, X, XI, XII, XIII, XIV, XV, XVI, XVII, XVIII, XIX, XX]
|
||||
|
||||
maximumLevel: MAXIMUM LEVEL (Speed x<currentMult>)
|
||||
|
||||
# The "Statistics" window
|
||||
@ -1033,6 +1025,11 @@ settings:
|
||||
description: >-
|
||||
Allows panning the map by moving the cursor to the edges of the screen. The scroll speed depends on the Movement Speed setting.
|
||||
|
||||
zoomToCursor:
|
||||
title: Zoom towards Cursor
|
||||
description: >-
|
||||
If activated the zoom will happen in the direction of your mouse position, otherwise in the middle of the screen.
|
||||
|
||||
keybindings:
|
||||
title: Keybindings
|
||||
hint: >-
|
||||
|
||||
@ -2,29 +2,29 @@ steamPage:
|
||||
shortText: shapez.io es un juego sobre construir fábricas para automatizar la
|
||||
creación y combinación de figuras cada vez más complejas en un mapa
|
||||
infinito.
|
||||
discordLinkShort: Official Discord
|
||||
discordLinkShort: Discord oficial
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
Shapez.io es un juego tranquilo en el que tienes que construir fábricas para la
|
||||
producción automatizada de formas geométricas.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
A medida que el nivel aumenta, las formas se vuelven más y más complejas, y tienes que extenderte en un mapa infinito.
|
||||
|
||||
And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling!
|
||||
Y por si fuera poco, también tienes que producir exponencialmente más para satisfacer las demandas - ¡lo único que ayuda es escalar!
|
||||
|
||||
While you only process shapes at the beginning, you have to color them later - for this you have to extract and mix colors!
|
||||
Mientras que sólo procesas formas al principio, tienes que colorearlas después - ¡para ello tienes que extraer y mezclar los colores!
|
||||
|
||||
Buying the game on Steam gives you access to the full version, but you can also play a demo on shapez.io first and decide later!
|
||||
title_advantages: Standalone Advantages
|
||||
Comprando el juego en Steam tienes acceso a la versión completa, ¡pero también puedes jugar una demo en shapez.io primero y decidir después!
|
||||
title_advantages: Ventajas del juego
|
||||
advantages:
|
||||
- <b>12 New Level</b> for a total of 26 levels
|
||||
- <b>18 New Buildings</b> for a fully automated factory!
|
||||
- <b>12 nuevos niveles</b> de un total de 26 niveles
|
||||
- <b>18 nuevos edificios</b> ¡para una fábrica totalmente automatizada!
|
||||
- <b>20 Upgrade Tiers</b> for many hours of fun!
|
||||
- <b>Wires Update</b> for an entirely new dimension!
|
||||
- <b>Dark Mode</b>!
|
||||
- Unlimited Savegames
|
||||
- Unlimited Markers
|
||||
- <b>Modo oscuro</b>!
|
||||
- Partidad guardadas ilimitadas
|
||||
- Marcadores ilimitados
|
||||
- Support me! ❤️
|
||||
title_future: Planned Content
|
||||
title_future: Contenido futuro
|
||||
planned:
|
||||
- Blueprint Library (Standalone Exclusive)
|
||||
- Steam Achievements
|
||||
|
||||
@ -5,7 +5,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
automated production of geometric shapes.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
automated production of geometric shapes.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
automated production of geometric shapes.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
|
||||
|
||||
@ -4,17 +4,17 @@ steamPage:
|
||||
yang meluas tanpa batas.
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
Shapez.io adalah game santai dimana anda harus membuat pabrik untuk
|
||||
mengotomatiskan produksi bentuk-bentuk geometris.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
Semakin meningkatnya level, bentuk-bentuknya menjadi lebih kompleks, dan anda perlu meluas di peta yang tak terbatas.
|
||||
|
||||
And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling!
|
||||
Dan jita itu tidak cukup, anda juga perlu untuk memproduksi secara ekxponensial untuk memenuhkan kebutuhan - hal yang membantu hanyalah memperbesar pabrik!
|
||||
|
||||
While you only process shapes at the beginning, you have to color them later - for this you have to extract and mix colors!
|
||||
Walaupun anda hanya memproses bentuk di awal, anda perlu mewarnainya untuk nanti - untuk ini, anda perlu untuk mengekstrak dan mencampur warna!
|
||||
|
||||
Buying the game on Steam gives you access to the full version, but you can also play a demo on shapez.io first and decide later!
|
||||
title_advantages: Standalone Advantages
|
||||
Membeli game ini di Steam memberikan anda akses ke versi lengkap, namun anda juga dapat mencoba demo dan memutuskan nanti!
|
||||
title_advantages: Keuntungan versi penuh
|
||||
advantages:
|
||||
- <b>12 New Level</b> for a total of 26 levels
|
||||
- <b>18 New Buildings</b> for a fully automated factory!
|
||||
@ -411,12 +411,12 @@ buildings:
|
||||
beberapa.
|
||||
wire:
|
||||
default:
|
||||
name: Kawat Energi
|
||||
description: Memungkinkan anda untuk mengangkut energi.
|
||||
name: Kabel
|
||||
description: Memungkinkan anda untuk mengangkut Energi.
|
||||
second:
|
||||
name: Wire
|
||||
description: Transfers signals, which can be items, colors or booleans (1 / 0).
|
||||
Different colored wires do not connect.
|
||||
name: Kabel
|
||||
description: Mentransfer sinyal, dapat berupa bentuk, warna, atau boolean (1 / 0).
|
||||
Kabel dengan warna berbeda tidak akan menyambung.
|
||||
miner:
|
||||
default:
|
||||
name: Ekstraktor
|
||||
@ -455,13 +455,13 @@ buildings:
|
||||
name: Pemutar (Berlawanan Arah Jarum Jam)
|
||||
description: Memutar bentuk berlawanan arah jarum jam sebesar 90 derajat.
|
||||
rotate180:
|
||||
name: Rotate (180)
|
||||
description: Rotates shapes by 180 degrees.
|
||||
name: Pemutar (180)
|
||||
description: Memutar bentuk searah jarum jam sebesar 180 derajat.
|
||||
stacker:
|
||||
default:
|
||||
name: Penyusun
|
||||
description: Menggabungkan kedua artikel. Apabila mereka tidak dapat
|
||||
digabungkan, artikel kanan akan diletakkan diatas artikel kiri.
|
||||
name: Penumpuk
|
||||
description: Menumpukkan kedua bentuk. Apabila mereka tidak dapat
|
||||
digabungkan, bentuk kanan akan diletakkan diatas bentuk kiri.
|
||||
mixer:
|
||||
default:
|
||||
name: Pencampur Warna
|
||||
@ -489,123 +489,120 @@ buildings:
|
||||
description: Menerima input dari semua sisi dan menghancurkannya. Selamanya.
|
||||
balancer:
|
||||
default:
|
||||
name: Balancer
|
||||
description: Multifunctional - Evenly distributes all inputs onto all outputs.
|
||||
name: Pengimbang
|
||||
description: Multifungsional - Mendistribusikan seluruh input secara merata ke seluruh output.
|
||||
merger:
|
||||
name: Merger (compact)
|
||||
description: Merges two conveyor belts into one.
|
||||
name: Penggabung (Kompak)
|
||||
description: Menggabungkan dua sabuk konveyor menjadi satu.
|
||||
merger-inverse:
|
||||
name: Merger (compact)
|
||||
description: Merges two conveyor belts into one.
|
||||
name: Penggabung (Kompak)
|
||||
description: Menggabungkan dua sabuk konveyor menjadi satu.
|
||||
splitter:
|
||||
name: Splitter (compact)
|
||||
description: Splits one conveyor belt into two.
|
||||
name: Pemisah (Kompak)
|
||||
description: Memisahkan satu sabuk konveyor menjadi dua.
|
||||
splitter-inverse:
|
||||
name: Splitter (compact)
|
||||
description: Splits one conveyor belt into two.
|
||||
name: Pemisah (Kompak)
|
||||
description: Memisahkan satu sabuk konveyor menjadi dua.
|
||||
storage:
|
||||
default:
|
||||
name: Storage
|
||||
description: Stores excess items, up to a given capacity. Prioritizes the left
|
||||
output and can be used as an overflow gate.
|
||||
name: Tempat Penyimpanan
|
||||
description: Menyumpan bentuk yang berlebuhan, hingga kapasitas yang tertentu. Memprioritaskan output dari kiri
|
||||
wire_tunnel:
|
||||
default:
|
||||
name: Wire Crossing
|
||||
description: Allows to cross two wires without connecting them.
|
||||
name: Penyebrangan Kabel
|
||||
description: Memungkinkan untuk menyebrangkan 2 kabel tanpa menyambungkannya.
|
||||
constant_signal:
|
||||
default:
|
||||
name: Constant Signal
|
||||
description: Emits a constant signal, which can be either a shape, color or
|
||||
boolean (1 / 0).
|
||||
name: Sinyal Konstan
|
||||
description: Mengeluarkan sinyal yang konstan, dapat berupa bentuk, warna atau boolean (1 / 0).
|
||||
lever:
|
||||
default:
|
||||
name: Switch
|
||||
description: Can be toggled to emit a boolean signal (1 / 0) on the wires layer,
|
||||
which can then be used to control for example an item filter.
|
||||
name: Saklar
|
||||
description: Dapat diubah untuk mengeluarkan sinyal boolean (1 / 0) pada lapisan kabel,
|
||||
yang bisa digunakan untuk mengontrol seperti penyaring.
|
||||
logic_gate:
|
||||
default:
|
||||
name: AND Gate
|
||||
description: Emits a boolean "1" if both inputs are truthy. (Truthy means shape,
|
||||
color or boolean "1")
|
||||
name: Gerbang AND
|
||||
description: Mengeluarkan boolean "1" jika kedua input adalah benar. (Benar berarti sebuah bentuk,
|
||||
warna atau boolean "1")
|
||||
not:
|
||||
name: NOT Gate
|
||||
description: Emits a boolean "1" if the input is not truthy. (Truthy means
|
||||
shape, color or boolean "1")
|
||||
name: Gerbang NOT
|
||||
description: Mengeluarkan boolean "1" jika input adalah tidak benar. (Benar berarti sebuah bentuk,
|
||||
warna atau boolean "1")
|
||||
xor:
|
||||
name: XOR Gate
|
||||
description: Emits a boolean "1" if one of the inputs is truthy, but not both.
|
||||
(Truthy means shape, color or boolean "1")
|
||||
name: Gerbang XOR
|
||||
description: Mengeluarkan boolean "1" jika kedua input adalah benar, namun bukan keduanya.
|
||||
(Benar berarti sebuah bentuk, warna atau boolean "1")
|
||||
or:
|
||||
name: OR Gate
|
||||
description: Emits a boolean "1" if one of the inputs is truthy. (Truthy means
|
||||
shape, color or boolean "1")
|
||||
name: Gerbang OR
|
||||
description: Mengeluarkan boolean "1" jika satu input adalah benar. (Benar berarti sebuah bentuk,
|
||||
warna atau boolean "1")
|
||||
transistor:
|
||||
default:
|
||||
name: Transistor
|
||||
description: Forwards the bottom input if the side input is truthy (a shape,
|
||||
color or "1").
|
||||
description: Melanjutkan sinyal dari input bawah jika input samping adalah benar (sebuah bentuk,
|
||||
warna atau boolean "1")
|
||||
mirrored:
|
||||
name: Transistor
|
||||
description: Forwards the bottom input if the side input is truthy (a shape,
|
||||
color or "1").
|
||||
description: Melanjutkan sinyal dari input bawah jika input samping adalah benar (sebuah bentuk,
|
||||
warna atau boolean "1")
|
||||
filter:
|
||||
default:
|
||||
name: Filter
|
||||
description: Connect a signal to route all matching items to the top and the
|
||||
remaining to the right. Can be controlled with boolean signals
|
||||
too.
|
||||
description: Hubungkan sebuah sinyal untuk merutekan semua benda yang cocok ke atas dan
|
||||
sisanya ke kanan. Dapat juga dikontrol dengan sinyal boolean
|
||||
display:
|
||||
default:
|
||||
name: Display
|
||||
description: Connect a signal to show it on the display - It can be a shape,
|
||||
color or boolean.
|
||||
name: Layar
|
||||
description: Hubungkan dengan sebuah sinyal untuk ditunjukkan pada layar - Dapat berupa bentuk,
|
||||
warna atau boolean.
|
||||
reader:
|
||||
default:
|
||||
name: Belt Reader
|
||||
description: Allows to measure the average belt throughput. Outputs the last
|
||||
read item on the wires layer (once unlocked).
|
||||
name: Pembaca Sabuk Konveyor
|
||||
description: Memungkinkan untuk mengukur rata-rata benda yang melewati sabuk konveyor. Mengeluarkan output benda terakhir
|
||||
yang dilewati pada lapisan kabel (Setelah terbuka).
|
||||
analyzer:
|
||||
default:
|
||||
name: Shape Analyzer
|
||||
description: Analyzes the top right quadrant of the lowest layer of the shape
|
||||
and returns its shape and color.
|
||||
name: Penganalisa bentuk
|
||||
description: Menganalisa perempat bentuk pada kanan atas dan lapisan terbawah
|
||||
lalu mengeluarkan bentuk dan warnanya.
|
||||
comparator:
|
||||
default:
|
||||
name: Compare
|
||||
description: Returns boolean "1" if both signals are exactly equal. Can compare
|
||||
shapes, items and booleans.
|
||||
name: Pembanding
|
||||
description: Mengeluarkan boolean "1" jika kedua sinya adalah sama. Dapat membandingkan
|
||||
Bentuk, warna dan boolean.
|
||||
virtual_processor:
|
||||
default:
|
||||
name: Virtual Cutter
|
||||
description: Virtually cuts the shape into two halves.
|
||||
name: Pemotong Virtual
|
||||
description: Memotong bentuk secara virtual menjadi dua bagian.
|
||||
rotater:
|
||||
name: Virtual Rotater
|
||||
description: Virtually rotates the shape, both clockwise and counter-clockwise.
|
||||
name: Pemutar Virtual
|
||||
description: Memutar bentuk secara virtual, searah jarum jam dan tidak searah jarum jam.
|
||||
unstacker:
|
||||
name: Virtual Unstacker
|
||||
description: Virtually extracts the topmost layer to the right output and the
|
||||
remaining ones to the left.
|
||||
name: Pemisah Tumpukan Virtual
|
||||
description: Memisahkan lapisan teratas secara virtual ke output kanan dan
|
||||
sisanya ke output kiri.
|
||||
stacker:
|
||||
name: Virtual Stacker
|
||||
description: Virtually stacks the right shape onto the left.
|
||||
name: Penumpuk Virtual
|
||||
description: Menumpuk bentuk kanan ke bentuk kiri secara virtual.
|
||||
painter:
|
||||
name: Virtual Painter
|
||||
description: Virtually paints the shape from the bottom input with the shape on
|
||||
the right input.
|
||||
name: Pencat Virtual
|
||||
description: Mengecat bentuk dari input bawah dengan warna
|
||||
dari input kanan.
|
||||
item_producer:
|
||||
default:
|
||||
name: Item Producer
|
||||
description: Available in sandbox mode only, outputs the given signal from the
|
||||
wires layer on the regular layer.
|
||||
name: Pembuat Artikel
|
||||
description: Hanya tersedia di dalam mode sandbox , Mengeluarkan sinyal yang diberikan dari
|
||||
lapisan kabel ke lapisan biasa.
|
||||
storyRewards:
|
||||
reward_cutter_and_trash:
|
||||
title: Memotong Bentuk
|
||||
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: <strong>Pemotong</strong> telah dibuka, yang dapat memotong bentuk menjadi dua
|
||||
secara vertikal <strong>apapun
|
||||
orientasinya</strong>!<br><br>Pastikan untuk membuang sisanya, jika
|
||||
tidak <strong>ini dapat menghambat dan memperlambat</strong> - karena ini
|
||||
anda diberikan <strong>Tong sampah</strong>, yang menghapus
|
||||
semua yang anda masukkan!
|
||||
reward_rotater:
|
||||
title: Memutar
|
||||
desc: <strong>Pemutar</strong> telah dibuka! Ia memutar bentuk-bentuk searah
|
||||
|
||||
@ -4,7 +4,7 @@ steamPage:
|
||||
discordLinkShort: 公式Discord
|
||||
intro: >-
|
||||
工場の自動化ゲームはお好きですか?それなら間違いないでしょう!
|
||||
|
||||
|
||||
Shapez.ioは、様々な幾何学的形状を生成するために工場を建設する、落ち着いたゲームです。レベルが上がる毎に生成すべき形はどんどん複雑になり、工場を無限に広がるマップに拡張する必要があります。
|
||||
|
||||
しかし、それだけでは不十分です。需要は指数関数的に上昇し、より多くの形状を生産する必要があり――"スケーリング"が、唯一の対抗策と成り得ます。最初は形状を加工するだけですが、後々着色も必要になってきます――それには色を抽出して、混ぜ合わせることが必要です!
|
||||
@ -120,18 +120,17 @@ dialogs:
|
||||
title: セーブデータのインポートに成功
|
||||
text: セーブデータをインポートしました。
|
||||
|
||||
|
||||
gameLoadFailure:
|
||||
title: ゲームが壊れています
|
||||
text: >-
|
||||
セーブデータのロードに失敗しました:
|
||||
セーブデータのロードに失敗しました:
|
||||
|
||||
confirmSavegameDelete:
|
||||
title: 削除確認
|
||||
text: >-
|
||||
本当に削除しますか?<br><br>
|
||||
レベル<savegameLevel>: '<savegameName>'<br><br>
|
||||
この操作は取り消しできません!
|
||||
この操作は取り消しできません!
|
||||
|
||||
savegameDeletionError:
|
||||
title: 削除に失敗
|
||||
@ -142,7 +141,6 @@ dialogs:
|
||||
title: 再起動が必要
|
||||
text: 設定を反映するには再起動が必要です
|
||||
|
||||
|
||||
editKeybinding:
|
||||
title: キー設定の変更
|
||||
desc: 割り当てるキーかマウスボタンを押してください。ESCでキャンセルします。
|
||||
@ -168,33 +166,26 @@ dialogs:
|
||||
desc: >-
|
||||
前回からの変更点:
|
||||
|
||||
|
||||
upgradesIntroduction:
|
||||
title: アップグレード解除
|
||||
desc: すべての納品された形はアップグレードの解除のためにカウントされています。<strong>作った生産ラインを削除しないようにしてください!</strong> アップグレードタブは画面の右上から確認できます。
|
||||
|
||||
|
||||
|
||||
massDeleteConfirm:
|
||||
title: 削除確認
|
||||
desc: 多数の建造物を削除しようとしています! (<count> 個の選択) 続行しますか?
|
||||
|
||||
|
||||
massCutConfirm:
|
||||
title: カット確認
|
||||
desc: 多数の建造物をカットしようとしています! (<count> 個の選択) 続行しますか?
|
||||
|
||||
|
||||
massCutInsufficientConfirm:
|
||||
title: カット確認
|
||||
desc: 設置コストが不足しています! 続行しますか?
|
||||
|
||||
|
||||
blueprintsNotUnlocked:
|
||||
title: 未解除
|
||||
desc: レベル12をクリアしてブループリント機能を解除してください!
|
||||
|
||||
|
||||
keybindingsIntroduction:
|
||||
title: 便利なキー設定
|
||||
desc: >-
|
||||
@ -228,10 +219,8 @@ dialogs:
|
||||
entityWarning:
|
||||
title: パフォーマンスの警告
|
||||
desc: あなたは沢山の工場を配置しましたが、このゲームは無限の建物を処理できるわけではありません。これは友好的なリマインダですが、より工場をコンパクトにすることに挑戦してみてください。
|
||||
|
||||
|
||||
ingame:
|
||||
|
||||
|
||||
keybindingsOverlay:
|
||||
moveMap: マップ移動
|
||||
selectBuildings: 範囲選択
|
||||
@ -253,7 +242,6 @@ ingame:
|
||||
pipette: ピペット
|
||||
switchLayers: レイヤーを変更
|
||||
|
||||
|
||||
colors:
|
||||
red: 赤
|
||||
green: 緑
|
||||
@ -265,17 +253,10 @@ ingame:
|
||||
black: 黒
|
||||
uncolored: 無色
|
||||
|
||||
|
||||
|
||||
buildingPlacement:
|
||||
cycleBuildingVariants: <key> キーを押して変更
|
||||
hotkeyLabel: "ホットキー: <key>"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
infoTexts:
|
||||
speed: スピード
|
||||
range: レンジ
|
||||
@ -285,36 +266,26 @@ ingame:
|
||||
itemsPerSecondDouble: (x2)
|
||||
tiles: <x> タイル
|
||||
|
||||
|
||||
|
||||
levelCompleteNotification:
|
||||
levelTitle: レベル <level>
|
||||
completed: 完了
|
||||
unlockText: <reward> を解除!
|
||||
buttonNextLevel: 次のレベル
|
||||
|
||||
|
||||
|
||||
notifications:
|
||||
newUpgrade: 新しいアップグレードが利用可能です!
|
||||
gameSaved: ゲームをセーブしました。
|
||||
freeplayLevelComplete: レベル <level> をクリアしました!
|
||||
|
||||
|
||||
shop:
|
||||
title: アップグレード
|
||||
buttonUnlock: アップグレード
|
||||
tier: 第 <x> 段階
|
||||
|
||||
|
||||
|
||||
|
||||
tierLabels:
|
||||
[I, II, III, IV, V, VI, VII, VIII, IX, X, XI, XII, XIII, XIV, XV, XVI, XVII, XVIII, XIX, XX]
|
||||
maximumLevel: 最大レベル (スピード x<currentMult>)
|
||||
|
||||
|
||||
|
||||
statistics:
|
||||
title: 統計情報
|
||||
dataSources:
|
||||
@ -329,16 +300,14 @@ ingame:
|
||||
description: 中央の建造物に納品された形の総数です。
|
||||
noShapesProduced: まだ形が生産されていません。
|
||||
|
||||
|
||||
shapesDisplayUnits:
|
||||
second: <shapes> / 秒
|
||||
minute: <shapes> / 分
|
||||
hour: <shapes> / 時間
|
||||
|
||||
|
||||
settingsMenu:
|
||||
playtime: プレイ時間
|
||||
|
||||
|
||||
buildingsPlaced: 建造物
|
||||
beltsPlaced: ベルト
|
||||
|
||||
@ -347,17 +316,14 @@ ingame:
|
||||
settings: 設定
|
||||
menu: メニューに戻る
|
||||
|
||||
|
||||
tutorialHints:
|
||||
title: ヒントが必要ですか?
|
||||
showHint: ヒントを見る
|
||||
hideHint: 閉じる
|
||||
|
||||
|
||||
blueprintPlacer:
|
||||
cost: コスト
|
||||
|
||||
|
||||
waypoints:
|
||||
waypoints: マーカー
|
||||
hub: HUB
|
||||
@ -370,7 +336,6 @@ ingame:
|
||||
empty: 空
|
||||
copyKey: キーをコピー
|
||||
|
||||
|
||||
interactiveTutorial:
|
||||
title: チュートリアル
|
||||
hints:
|
||||
@ -528,7 +493,7 @@ buildings:
|
||||
second:
|
||||
name: *wire
|
||||
description: *wire_desc
|
||||
|
||||
|
||||
wire_tunnel:
|
||||
default:
|
||||
name: &wire_tunnel 交差ワイヤ
|
||||
@ -572,13 +537,13 @@ buildings:
|
||||
display:
|
||||
default:
|
||||
name: &display ディスプレイ
|
||||
description: >-
|
||||
description: >-
|
||||
入力された信号をディスプレイに表示します。
|
||||
形状、色、真偽値のいずれでも可能です。
|
||||
reader:
|
||||
default:
|
||||
name: &reader ベルトリーダ
|
||||
description: >-
|
||||
description: >-
|
||||
平均スループットを計測できます。 アンロック後は、
|
||||
最後に通過したアイテムの情報を出力します。
|
||||
analyzer:
|
||||
@ -773,7 +738,7 @@ settings:
|
||||
title: オートセーブ間隔
|
||||
description: >-
|
||||
ゲームが自動的にセーブされる頻度を設定します。無効化することも可能です。
|
||||
|
||||
|
||||
intervals:
|
||||
one_minute: 1分
|
||||
two_minutes: 2分
|
||||
@ -818,7 +783,7 @@ settings:
|
||||
soundVolume:
|
||||
title: 音量(SE)
|
||||
description: 効果音の音量を設定してください。
|
||||
|
||||
|
||||
musicVolume:
|
||||
title: 音量(BGM)
|
||||
description: 音楽の音量を設定してください。
|
||||
@ -866,7 +831,8 @@ settings:
|
||||
これにより、ゲームの見た目もすっきりします。
|
||||
clearCursorOnDeleteWhilePlacing:
|
||||
title: 右クリックで配置をキャンセル
|
||||
description: デフォルトで有効です。建物を設置しているときに右クリックすると、選択中の建物がキャンセルされます。
|
||||
description:
|
||||
デフォルトで有効です。建物を設置しているときに右クリックすると、選択中の建物がキャンセルされます。
|
||||
無効にすると、建物の設置中に右クリックで建物を削除できます。
|
||||
lowQualityTextures:
|
||||
title: 低品質のテクスチャ(視認性低下)
|
||||
@ -911,20 +877,20 @@ keybindings:
|
||||
mapMoveLeft: 左移動
|
||||
mapMoveFaster: より速く移動
|
||||
centerMap: マップ中央移動
|
||||
|
||||
|
||||
mapZoomIn: ズームイン
|
||||
mapZoomOut: ズームアウト
|
||||
createMarker: マーカー設置
|
||||
|
||||
|
||||
menuOpenShop: アップグレード
|
||||
menuOpenStats: 統計情報
|
||||
menuClose: メニューを閉じる
|
||||
|
||||
|
||||
toggleHud: HUD切り替え
|
||||
toggleFPSInfo: FPS、デバッグ情報表示切り替え
|
||||
switchLayers: レイヤを変更
|
||||
exportScreenshot: 工場の全体像を画像出力
|
||||
|
||||
|
||||
# --- Do not translate the values in this section
|
||||
belt: *belt
|
||||
balancer: *balancer
|
||||
@ -951,7 +917,7 @@ keybindings:
|
||||
comparator: *comparator
|
||||
item_producer: なんでも抽出機(サンドボックス)
|
||||
# ---
|
||||
|
||||
|
||||
pipette: スポイト
|
||||
rotateWhilePlacing: 回転
|
||||
rotateInverseModifier: >-
|
||||
|
||||
@ -4,7 +4,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
automated production of geometric shapes.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
|
||||
|
||||
@ -222,7 +222,7 @@ ingame:
|
||||
placeBuilding: Plaats gebouw
|
||||
createMarker: Plaats markering
|
||||
delete: Vernietig
|
||||
pasteLastBlueprint: Plak laatst gekopiëerde blauwdruk
|
||||
pasteLastBlueprint: Plak laatst gekopieerde blauwdruk
|
||||
lockBeltDirection: Gebruik lopende band planner
|
||||
plannerSwitchSide: Draai de richting van de planner
|
||||
cutSelection: Knip
|
||||
@ -325,7 +325,7 @@ ingame:
|
||||
1_2_conveyor: "Verbind de ontginner met een <strong>lopende band</strong> aan je
|
||||
hub!<br><br>Tip: <strong>Klik en sleep</strong> de lopende band
|
||||
met je muis!"
|
||||
1_3_expand: "Dit is <strong>GEEN</strong> nietsdoen-spel! bouw meer ontginners
|
||||
1_3_expand: "Dit is <strong>GEEN</strong> nietsdoen-spel! Bouw meer ontginners
|
||||
en lopende banden om het doel sneller te behalen.<br><br>Tip:
|
||||
Houd <strong>SHIFT</strong> ingedrukt om meerdere ontginners te
|
||||
plaatsen en gebruik <strong>R</strong> om ze te draaien."
|
||||
@ -342,7 +342,7 @@ ingame:
|
||||
shapeViewer:
|
||||
title: Lagen
|
||||
empty: Leeg
|
||||
copyKey: Kopiëer sleutel
|
||||
copyKey: Kopieer sleutel
|
||||
connectedMiners:
|
||||
one_miner: 1 Miner
|
||||
n_miners: <amount> Miners
|
||||
@ -861,7 +861,7 @@ settings:
|
||||
kunt spelen wanneer je kleurenblind bent.
|
||||
rotationByBuilding:
|
||||
title: Rotatie per type gebouw
|
||||
description: Elk type gebouw onthoud apart de rotatie waarin je het voor het
|
||||
description: Elk type gebouw onthoudt apart de rotatie waarin je het voor het
|
||||
laatst geplaatst hebt. Dit kan handig zijn wanneer je vaak
|
||||
tussen verschillende soorten gebouwen wisselt.
|
||||
soundVolume:
|
||||
|
||||
@ -5,7 +5,7 @@ steamPage:
|
||||
discordLinkShort: Oficjalny serwer Discord
|
||||
intro: >-
|
||||
Shapez.io jest spokojną grą, której celem jest budowanie automatycznych fabryk
|
||||
produkujących różne kształty geometryczne.
|
||||
produkujących różne kształty geometryczne.
|
||||
|
||||
W miarę zwiększania się poziomów, kształty będą stawać się coraz bardziej skomplikowane, a Twoja fabryka będzie musiała się rozpszetrzenić na mapie o nieskończonej wielkości.
|
||||
|
||||
@ -705,7 +705,7 @@ storyRewards:
|
||||
title: Stały sygnał
|
||||
desc: >-
|
||||
Właśnie odblokowałeś budynek emitujący <strong>stały sygnał</strong> na warstwie przewodów!
|
||||
Jest on przydatny na przykład: do ustawiania <strong>filtrów</strong><br><br>
|
||||
Jest on przydatny na przykład: do ustawiania <strong>filtrów</strong><br><br>
|
||||
Sygnał może być <strong>kształtem</strong>, <strong>kolorem</strong> lub wartością
|
||||
<strong>Prawda/Fałsz</strong>.
|
||||
reward_logic_gates:
|
||||
|
||||
@ -4,7 +4,7 @@ steamPage:
|
||||
discordLinkShort: Discord Oficial
|
||||
intro: >-
|
||||
Shapez.io é um jogo relaxante no qual você deve construir fábricas para
|
||||
produzir formas geométricas automaticamente.
|
||||
produzir formas geométricas automaticamente.
|
||||
|
||||
Conforme os níveis aumentam, as formas se tornam mais complexas, e você terá que explorar o mapa infinito.
|
||||
|
||||
@ -25,7 +25,7 @@ steamPage:
|
||||
- Me ajuda! ❤️
|
||||
title_future: Conteúdo Planejado
|
||||
planned:
|
||||
- Biblioteca de esquemas (Exclusivo para a versão completa)
|
||||
- Biblioteca de projetos (Exclusivo para a versão completa)
|
||||
- Conquistas da Steam
|
||||
- Modo Puzzle
|
||||
- Minimapa
|
||||
@ -94,7 +94,7 @@ mainMenu:
|
||||
completa ou baixe o Chrome para obter uma experiência completa.
|
||||
savegameLevel: Nível <x>
|
||||
savegameLevelUnknown: Nível desconhecido
|
||||
savegameUnnamed: Unnamed
|
||||
savegameUnnamed: Sem nome
|
||||
dialogs:
|
||||
buttons:
|
||||
ok: OK
|
||||
@ -119,9 +119,9 @@ dialogs:
|
||||
text: "Houve uma falha ao carregar seu jogo salvo:"
|
||||
confirmSavegameDelete:
|
||||
title: Confirmar exclusão
|
||||
text: Are you sure you want to delete the following game?<br><br>
|
||||
'<savegameName>' at level <savegameLevel><br><br> This can not be
|
||||
undone!
|
||||
text: Tem certeza que deseja deletar o jogo a seguir?<br><br>
|
||||
'<savegameName>' no nível <savegameLevel><br><br> Isso não
|
||||
pode ser revertido!
|
||||
savegameDeletionError:
|
||||
title: Falha ao deletar
|
||||
text: "Houve uma falha ao deletar seu jogo salvo:"
|
||||
@ -135,14 +135,14 @@ dialogs:
|
||||
title: Resetar controles
|
||||
desc: Essa opção deixa os controles nas definições padrão.
|
||||
keybindingsResetOk:
|
||||
title: Resetar controles
|
||||
title: Controles resetados
|
||||
desc: Os controles foram resetados para as definições padrão.
|
||||
featureRestriction:
|
||||
title: Versão Demo
|
||||
desc: Você tentou acessar um recurso (<feature>) que não está disponível na
|
||||
demo. Considere obter a versão completa para a proceder!
|
||||
oneSavegameLimit:
|
||||
title: Jogo salvo limitado
|
||||
title: Limite de jogos salvos
|
||||
desc: Você pode ter apenas um jogo salvo por vez na versão demo. Remova o
|
||||
existente ou obtenha a versão completa!
|
||||
updateSummary:
|
||||
@ -164,7 +164,7 @@ dialogs:
|
||||
continuar?
|
||||
massCutInsufficientConfirm:
|
||||
title: Confirmar Corte?
|
||||
desc: You can not afford to paste this area! Are you sure you want to cut it?
|
||||
desc: Você não conseguirá colar essa área! Tem certeza que quer cortá-la??
|
||||
blueprintsNotUnlocked:
|
||||
title: Não desbloqueado ainda
|
||||
desc: Os projetos ainda não foram desbloqueados! Complete mais níveis para
|
||||
@ -181,8 +181,8 @@ dialogs:
|
||||
createMarker:
|
||||
title: Nova Marcação
|
||||
titleEdit: Editar Marcador
|
||||
desc: Give it a meaningful name, you can also include a <strong>short
|
||||
key</strong> of a shape (Which you can generate <link>here</link>)
|
||||
desc: Dê um nome significativo, você também pode incluir um <strong>código
|
||||
</strong> de uma forma (Você pode gerá-lo <link>aqui</link>)
|
||||
markerDemoLimit:
|
||||
desc: Você só pode criar dois marcadores na versão demo. Adquira a versão
|
||||
completa para marcadores ilimitados!
|
||||
@ -404,7 +404,7 @@ buildings:
|
||||
description: Permite transportar energia.
|
||||
second:
|
||||
name: Fio
|
||||
description: Transfere sinais, que podem ser de itens, cores or binários (1 /
|
||||
description: Transfere sinais, que podem ser de itens, cores ou binários (1 /
|
||||
0). Fios com cores diferentes não se conectam.
|
||||
miner:
|
||||
default:
|
||||
@ -466,9 +466,9 @@ buildings:
|
||||
description: Colore as formas na entrada esquerda com a cor da entrada superior.
|
||||
quad:
|
||||
name: Pintor (Quádruplo)
|
||||
description: Allows you to color each quadrant of the shape individually. Only
|
||||
slots with a <strong>truthy signal</strong> on the wires layer
|
||||
will be painted!
|
||||
description: Permite que você pinte cada quadrante da forma individualmente. Apenas
|
||||
entradas com um <strong>sinal verdadeiro</strong> no plano de fios
|
||||
serão pintadas!
|
||||
trash:
|
||||
default:
|
||||
name: Lixo
|
||||
@ -514,31 +514,31 @@ buildings:
|
||||
default:
|
||||
name: Portão E (AND)
|
||||
description: Emite um sinal binário "1" se ambas as entradas forem verdadeiras.
|
||||
(Ser verdadeira significa receber um sinal de forma, cor or
|
||||
(Ser verdadeira significa receber um sinal de forma, cor ou
|
||||
binário "1")
|
||||
not:
|
||||
name: Portão NEGAR (NOT)
|
||||
description: Emite um sinal binário "1" se a entrada for falsa. (Ser verdadeira
|
||||
significa receber um sinal de forma, cor or binário "1")
|
||||
significa receber um sinal de forma, cor ou binário "1")
|
||||
xor:
|
||||
name: Portão OU EXCLUSIVO (XOR)
|
||||
description: Emite um sinal binário "1" se uma das entradas for verdadeira, mas
|
||||
não duas. (Ser verdadeira significa receber um sinal de forma,
|
||||
cor or binário "1")
|
||||
cor ou binário "1")
|
||||
or:
|
||||
name: Portão OU (OR)
|
||||
description: Emite um sinal binário "1" se uma das entradas for verdadeira. (Ser
|
||||
verdadeira significa receber um sinal de forma, cor or binário
|
||||
verdadeira significa receber um sinal de forma, cor ou binário
|
||||
"1")
|
||||
transistor:
|
||||
default:
|
||||
name: Transistor
|
||||
description: Envia o sinal adiante se a entrada for verdadeira. (Ser verdadeira
|
||||
significa receber um sinal de forma, cor or binário "1")
|
||||
significa receber um sinal de forma, cor ou binário "1")
|
||||
mirrored:
|
||||
name: Transistor
|
||||
description: Envia o sinal adiante se a entrada for verdadeira. (Ser verdadeira
|
||||
significa receber um sinal de forma, cor or binário "1")
|
||||
significa receber um sinal de forma, cor ou binário "1")
|
||||
filter:
|
||||
default:
|
||||
name: Filtro
|
||||
@ -593,12 +593,12 @@ buildings:
|
||||
storyRewards:
|
||||
reward_cutter_and_trash:
|
||||
title: Cortando formas
|
||||
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: Você acabou de desbloquear o <strong>cortador</strong>, que corta formas pela metade
|
||||
de cima para baixo <strong>independente de sua
|
||||
orientação</strong>!<br><br>Lembre-se de se livrar do lixo, caso
|
||||
contrário, <strong>a máquina irá entupir</strong> - Por isso
|
||||
eu te dei o <strong>lixo</strong>, que destrói
|
||||
tudo que você coloca nele!
|
||||
reward_rotater:
|
||||
title: Rotação
|
||||
desc: O <strong>rotacionador</strong> foi desbloqueado! Gira as formas no
|
||||
@ -620,10 +620,10 @@ storyRewards:
|
||||
da outra, serão <strong>fundidas</strong>. Caso contrário, a entrada
|
||||
direita é <strong>empilhada em cima</strong> da entrada esquerda!
|
||||
reward_splitter:
|
||||
title: Distribuidor
|
||||
desc: You have unlocked a <strong>splitter</strong> variant of the
|
||||
<strong>balancer</strong> - It accepts one input and splits them
|
||||
into two!
|
||||
title: Divisor
|
||||
desc: Você desbloqueou uma variante <strong>divisora</strong> do
|
||||
<strong>balanceador</strong> - Ela aceita uma entrada e a divide
|
||||
em duas saídas!
|
||||
reward_tunnel:
|
||||
title: Túnel
|
||||
desc: O <strong>túnel</strong> foi desbloqueado - Agora você pode transportar
|
||||
@ -662,13 +662,13 @@ storyRewards:
|
||||
output, so you can also use it as an <strong>overflow gate</strong>!
|
||||
reward_freeplay:
|
||||
title: Modo Livre
|
||||
desc: You did it! You unlocked the <strong>free-play mode</strong>! This means
|
||||
that shapes are now <strong>randomly</strong> generated!<br><br>
|
||||
Since the hub will require a <strong>throughput</strong> from now
|
||||
on, I highly recommend to build a machine which automatically
|
||||
delivers the requested shape!<br><br> The HUB outputs the requested
|
||||
shape on the wires layer, so all you have to do is to analyze it and
|
||||
automatically configure your factory based on that.
|
||||
desc: Você conseguiu! Você desbloqueou o <strong>modo livre</strong>! Isso significa
|
||||
que formas agora são geradas <strong>aleatóriamente</strong>!<br><br>
|
||||
Já que o HUB vai precisar de uma entrada <strong>constante</strong> a partir de
|
||||
agora, eu altamente recomendo que você construa uma máquina que entregue
|
||||
automaticamente as formas pedidas!<br><br> O HUB emite a forma pedida
|
||||
no plano dos fios, então tudo que você precisa fazer é analizá-la e
|
||||
automaticamente configurar sua fábrica baseado nessa análise.
|
||||
reward_blueprints:
|
||||
title: Projetos
|
||||
desc: Agora você pode <strong>copiar e colar</strong> partes de sua fábrica!
|
||||
@ -706,10 +706,10 @@ storyRewards:
|
||||
Ele permite que você rotacione uma forma em 180 graus (Surpresa! :D)
|
||||
reward_display:
|
||||
title: Display
|
||||
desc: "You have unlocked the <strong>Display</strong> - Connect a signal on the
|
||||
wires layer to visualize it!<br><br> PS: Did you notice the belt
|
||||
reader and storage output their last read item? Try showing it on a
|
||||
display!"
|
||||
desc: "Você desbloqueou o <strong>Display</strong> - Conecte um sinal no
|
||||
plano de fios para poder vê-lo!<br><br> PS: Você percebeu que ambos o leitor
|
||||
de esteiras e o armazenamento emitem o último item lido? Tente mostrar
|
||||
isso em um display!"
|
||||
reward_constant_signal:
|
||||
title: Sinal Constante
|
||||
desc: Você desbloqueou a construção que emite um <strong>sinal
|
||||
@ -1082,4 +1082,3 @@ tips:
|
||||
- Pressione F4 para mostrar seu FPS e taxa de tiques.
|
||||
- Pressione F4 duas vezes para mostrar o ladrilho do seu mouse e da câmera.
|
||||
- Você pode clicar em uma forma fixada na esquerda para tirá-la de lá.
|
||||
- null
|
||||
|
||||
@ -4,47 +4,49 @@ steamPage:
|
||||
complexas num mapa infinito.
|
||||
discordLinkShort: Discord Oficial
|
||||
intro: >-
|
||||
Shapez.io é um jogo relaxante onde tens que construir fábricas para a produção automatizada de formas geométricas.
|
||||
Shapez.io é um jogo relaxante onde tens de construir fábricas para
|
||||
autumatizar a produção de formas geométricas.
|
||||
|
||||
Enquanto o nível aumenta, as formas ficam cada vez mais e mais complexas, e tens de te expandir por um mapa infinito.
|
||||
Com o aumento do nível, as formas começam a ser cada vez mais e mais complexas, e tu terás de te expandir num mapa infinito.
|
||||
|
||||
E como se isso não fosse suficiente, também tens de produzir cada vez mais para satisfazer a demanda - a única coisa que ajuda é aumentar!
|
||||
E como se isso não fosse suficiente, tu também terás de produzir de forma exponencial para satisfazeres as tuas necessidades - a única coisa que ajuda é aumentar!
|
||||
|
||||
Enquanto só podes processar formas no inicio, vais ter de as colorir mais tarde - para isto vais ter de extrair e juntar cores!
|
||||
Embora no inicio apenas tenhas de processar formas, mais tarde, vais ter de as colorir - para isto terás de extrair e misturar cores!
|
||||
|
||||
Comprar o jogo na Steam dá-te acesso à versão completa, mas também podes jogar a demo em shapez.io primeiro e decidir depois!
|
||||
title_advantages: Vantagens Standalone
|
||||
Comprar o jogo na Steam dar-te-á acesso à versão completa, mas também podes jogar a versão demo em shapez.io primeiro e decidir mais tarde!
|
||||
title_advantages: Vantagens da versão completa
|
||||
advantages:
|
||||
- <b>12 Novos Níveis</b> para um total de 26 níveis
|
||||
- <b>18 Novos Edifícios</b> para uma fábrica totalmente automatizada!
|
||||
- <b>20 Níveis de Upgrade</b> para muitas horas de diversão!
|
||||
- <b>Atualização de Fios</b> para uma completamente nova dimensão!
|
||||
- <b>Modo Escuro</b>!
|
||||
- Savegames Ilimitados
|
||||
- Marcos Ilimitados
|
||||
- Suporta-me! ❤️
|
||||
- <b>12 Novos Níveis</b> para um total de 26 Níves
|
||||
- <b>18 Novas Construções</b> para uma fábrica totalmente automatizada!
|
||||
- <b>20 Níveis de Melhoria</b> para muitas horas de diversão!
|
||||
- <b>Atualização de Fios</b> para uma dimensão totalmente nova!
|
||||
- <b>Modo escuro</b>!
|
||||
- Savegames ilimitados
|
||||
- Marcos ilimitados
|
||||
- Ajuda-me! ❤️
|
||||
title_future: Conteúdo Planeado
|
||||
planned:
|
||||
- Blueprint Library (Exclusivo Standalone)
|
||||
- Steam Achievements
|
||||
- Biblioteca Blueprint (Exclusivo na versão Completa)
|
||||
- Conquistas na Steam
|
||||
- Modo Puzzle
|
||||
- Minimap
|
||||
- Mods
|
||||
- Minimapa
|
||||
- Modos
|
||||
- Modo Sandbox
|
||||
- ... e muito mais!
|
||||
title_open_source: Este jogo é código aberto!
|
||||
- ... e Muito Mais!
|
||||
title_open_source: Este jogo é open source (código aberto)!
|
||||
title_links: Links
|
||||
links:
|
||||
discord: Discord Oficial
|
||||
roadmap: Roadmap
|
||||
roadmap: Roteiro de desenvolvimento
|
||||
subreddit: Subreddit
|
||||
source_code: Source code (GitHub)
|
||||
translate: Ajuda a traduzir
|
||||
source_code: Código Fonte (GitHub)
|
||||
translate: Ajuda a Traduzir
|
||||
text_open_source: >-
|
||||
Qualquer pessoa pode contribuir, estou ativamente envolvido na comunidade e
|
||||
tento rever todas as sugestões e levo o feedback em consideração sempre que possível.
|
||||
Qualquer um pode contribuir, estou ativamente envolvido na comunidade e
|
||||
tento ver todas as sugestões e ter em consideração o feedback recebido
|
||||
assim que possível.
|
||||
|
||||
Verifique o meu trello board para o roadmap completo!
|
||||
Segue o meu trello board para veres todo o roteiro de desenvolvimento!
|
||||
|
||||
global:
|
||||
loading: A Carregar
|
||||
@ -97,7 +99,6 @@ mainMenu:
|
||||
madeBy: Criado por <author-link>
|
||||
subreddit: Reddit
|
||||
savegameUnnamed: Sem Nome
|
||||
|
||||
dialogs:
|
||||
buttons:
|
||||
ok: OK
|
||||
@ -122,8 +123,9 @@ dialogs:
|
||||
text: "Erro ao carregar o teu savegame:"
|
||||
confirmSavegameDelete:
|
||||
title: Confirmar eliminação
|
||||
text: Tens que queres apagar o seguinte jogo?<br><br>
|
||||
'<savegameName>' no Nível <savegameLevel><br><br> Isto não pode
|
||||
text: >-
|
||||
Tens a certeza que queres apagar o seguinte jogo?<br><br>
|
||||
'<savegameName>' no nível <savegameLevel><br><br> Isto não pode ser
|
||||
desfeito!
|
||||
savegameDeletionError:
|
||||
title: Erro de eliminação
|
||||
@ -179,8 +181,8 @@ dialogs:
|
||||
class='keybinding'>ALT</code>: Inverte as posições.<br>"
|
||||
createMarker:
|
||||
title: Novo Marco
|
||||
desc: Dá-lhe um nome com significado, também poderás adicionar <strong>um
|
||||
pequeno código</strong> de uma forma (Que podes gerar aqui <link>here</link>)
|
||||
desc: Dá-lhe um nome com significado, também poderás adicionar um <strong>pequeno
|
||||
código</strong> de uma forma. (Pode ser gerado <link>aqui</link>)
|
||||
titleEdit: Editar Marco
|
||||
markerDemoLimit:
|
||||
desc: Apenas podes criar dois marcos na versão Demo. Adquire o jogo completo
|
||||
@ -199,17 +201,18 @@ dialogs:
|
||||
desc: Não consegues pagar para colar esta área! Tens a certeza que pretendes
|
||||
cortá-la?
|
||||
editSignal:
|
||||
title: Definir Sinal
|
||||
title: Define o Sinal
|
||||
descItems: "Escolhe um item pre-definido:"
|
||||
descShortKey: ... ou entra o <strong>atalho</strong> duma forma (Que podes
|
||||
gerar <link>aqui</link>)
|
||||
descShortKey: ... ou insere o <strong>pequeno código</strong> de uma forma (Pode ser
|
||||
gerado <link>aqui</link>)
|
||||
renameSavegame:
|
||||
title: Renomear Savegame
|
||||
desc: Podes renomear o teu savegame aqui.
|
||||
entityWarning:
|
||||
title: Aviso de Desempenho
|
||||
desc: Tu colocaste muitos edifícios, isto é apenas um lembrete amigável que o jogo não consegue aguentar com um número infinito de edifícios - Tenta meter as tuas fábricas compactas!
|
||||
|
||||
desc: Tu colocaste muitas contruções, isto é apenas um lembrete amigável de que
|
||||
o que o jogo não aguenta com um número infinito de contruções - Sendo assim tenta
|
||||
manter as tuas fábricas compactas!
|
||||
ingame:
|
||||
keybindingsOverlay:
|
||||
moveMap: Mover
|
||||
@ -295,7 +298,6 @@ ingame:
|
||||
second: <shapes> / s
|
||||
minute: <shapes> / m
|
||||
hour: <shapes> / h
|
||||
|
||||
settingsMenu:
|
||||
playtime: Tempo de jogo
|
||||
buildingsPlaced: Construções
|
||||
@ -345,41 +347,41 @@ ingame:
|
||||
empty: Vazio
|
||||
copyKey: Chave de cópia
|
||||
connectedMiners:
|
||||
one_miner: 1 Minerador
|
||||
n_miners: <amount> Mineradores
|
||||
limited_items: Limitado a <max_throughput>
|
||||
one_miner: 1 Extrator
|
||||
n_miners: <amount> Extratores
|
||||
limited_items: Limite de <max_throughput>
|
||||
watermark:
|
||||
title: Versão Demo
|
||||
desc: Clica aqui para ver as vantagens da versão Steam!
|
||||
get_on_steam: Compra na steam
|
||||
desc: Clica aqui para veres as vantagens da versão na Steam!
|
||||
get_on_steam: Compra na Steam
|
||||
standaloneAdvantages:
|
||||
title: Obtém a versão completa!
|
||||
no_thanks: Não, obrigado!
|
||||
points:
|
||||
levels:
|
||||
title: 12 Novos Níveis
|
||||
desc: Para um total de 26 níveis!
|
||||
desc: Para um total de 26 Níveis!
|
||||
buildings:
|
||||
title: 18 Novos Edifícios
|
||||
desc: Automatiza completamente a tua fábrica!
|
||||
title: 18 Novas contruções
|
||||
desc: Para uma fábrica totalmente automatizada!
|
||||
savegames:
|
||||
title: Savegames ∞
|
||||
desc: Quantos o teu coração quiser!
|
||||
desc: Tantos quanto o teu corção desejar!
|
||||
upgrades:
|
||||
title: 20 Níveis de Upgrades
|
||||
desc: Esta versão demo só tem 5!
|
||||
title: 20 Níveis de melhoria
|
||||
desc: Nesta versão demo apenas tens 5!
|
||||
markers:
|
||||
title: Marcos ∞
|
||||
desc: Nunca te percas na tua fábrica!
|
||||
desc: Nunca te percas na tua Fábrica!
|
||||
wires:
|
||||
title: Fios
|
||||
desc: Uma completamente nova dimensão!
|
||||
desc: Uma dimensão totalmente nova!!
|
||||
darkmode:
|
||||
title: Modo Escuro
|
||||
desc: Para de magoar os meus olhos!
|
||||
desc: Não magoes os teus olhos!
|
||||
support:
|
||||
title: Suporta-me
|
||||
desc: Eu desenvolvo o jogo no meu tempo livre!
|
||||
title: Ajuda-me
|
||||
desc: Eu desenvolvo este jogo no meu tempo livre!
|
||||
|
||||
shopUpgrades:
|
||||
belt:
|
||||
@ -398,7 +400,7 @@ buildings:
|
||||
belt:
|
||||
default:
|
||||
name: Tapete Rolante
|
||||
description: Transporta items. Mantém pressionado e arrasta para colocar vários.
|
||||
description: Transporta itens. Mantém pressionado e arrasta para colocar vários.
|
||||
miner:
|
||||
default:
|
||||
name: Extrator
|
||||
@ -431,11 +433,12 @@ buildings:
|
||||
description: Roda as formas 90º no sentido dos ponteiros do relógio.
|
||||
ccw:
|
||||
name: Rodar (CCW)
|
||||
description: Roda as formas 90º no sentido contrário ao dos ponteiros do relógio.
|
||||
description: Roda as formas 90º no sentido contrário ao dos ponteiros do
|
||||
relógio.
|
||||
|
||||
rotate180:
|
||||
name: Rodar (180)
|
||||
description: Roda as formas 180º.
|
||||
name: Rodar (180º)
|
||||
description: Roda as formas 180º.
|
||||
stacker:
|
||||
default:
|
||||
name: Empilhador
|
||||
@ -456,7 +459,9 @@ buildings:
|
||||
entrada superior.
|
||||
quad:
|
||||
name: Pintor (Quádruplo)
|
||||
description: Pinta cada quadrante da forma geométrica com uma cor diferente. Apenas slots com um <strong>sinal verdadeiro</strong> na camada de fios vão ser pintados!
|
||||
description: Permite colorir cada quadrante da forma individualmente. Apenas
|
||||
entradas com um <strong>sinal verdadeira</strong> na camada de fios
|
||||
irá ser pintada!
|
||||
mirrored:
|
||||
name: Pintor
|
||||
description: Pinta a forma geométrica da entrada esquerda com a cor da entrada
|
||||
@ -465,28 +470,30 @@ buildings:
|
||||
default:
|
||||
name: Lixo
|
||||
description: Aceita entradas de todos os lados e destrói-os. Para sempre.
|
||||
|
||||
hub:
|
||||
deliver: Entrega
|
||||
toUnlock: para desbloquear
|
||||
levelShortcut: NVL
|
||||
endOfDemo: Fim do Demo
|
||||
wire:
|
||||
default:
|
||||
name: Fio Elétrico
|
||||
description: Transfere sinais, que podem ser itens, cores ou boleanos (1 / 0). Fios com cores diferentes não conectam.
|
||||
description: Tranfere sinais, que podem ser itens, cores ou um sinal binário (1 ou 0).
|
||||
Fios de cores diferestes não se conectam.
|
||||
second:
|
||||
name: Fio Elétrico
|
||||
description: Transfere sinais, que podem ser itens, cores ou boleanos (1 / 0). Fios com cores diferentes não conectam.
|
||||
description: Tranfere sinais, que podem ser itens, cores ou um sinal binário (1 ou 0).
|
||||
Fios de cores diferestes não se conectam.
|
||||
balancer:
|
||||
default:
|
||||
name: Balanceador
|
||||
description: Multifuncional - Distribui uniformemente todas as entradas para todas as saídas.
|
||||
name: Distribuidor
|
||||
description: Multifunções - Distribui igualmente todas as entradas por todas as saídas.
|
||||
merger:
|
||||
name: Junção (compacto)
|
||||
description: Junta um tapete rolante em dois.
|
||||
name: Misturador (comp.)
|
||||
description: Junta dois tapetes rolantes num só.
|
||||
merger-inverse:
|
||||
name: Junção (compacto)
|
||||
description: Junta um tapete rolante em dois.
|
||||
name: Misturador (comp.)
|
||||
description: Junta dois tapetes rolantes num só.
|
||||
splitter:
|
||||
name: Divisor (compacto)
|
||||
description: Divide um tapete rolante em dois.
|
||||
@ -494,99 +501,115 @@ buildings:
|
||||
name: Divisor (compacto)
|
||||
description: Divide um tapete rolante em dois.
|
||||
storage:
|
||||
default:
|
||||
name: Armazém
|
||||
description: >-
|
||||
Guarda itens em excesso, até uma quantidade determinada. Prioritiza a entrada esquerda
|
||||
e pode ser usada como um portão de transbordar.
|
||||
default:
|
||||
name: Armazém
|
||||
description: Armazena itens em excesso, até uma determinada capacidade. Dá prioridade à saída da
|
||||
esquerda e pode ser usado como uma porta de transbordo.
|
||||
wire_tunnel:
|
||||
default:
|
||||
name: Túnel de Fio
|
||||
description: Permite cruzar dois fios sem os conectar.
|
||||
default:
|
||||
name: Túnel de Fios
|
||||
description: Permite que dois fios cruzem sem conectarem-se um ao outro.
|
||||
constant_signal:
|
||||
default:
|
||||
name: Sinal constante
|
||||
description: >-
|
||||
Emite um sinal constante, que pode ser uma forma, cor ou um booleano (1 / 0).
|
||||
default:
|
||||
name: Sinal Constante
|
||||
description: Emite um sinal constante , que pode ser uma forma, cor ou
|
||||
um sinal binário (1 ou 0).
|
||||
lever:
|
||||
default:
|
||||
name: Interruptor
|
||||
description: >-
|
||||
Pode ser alternado para emitir um sinal booleano (1 / 0) na camada de fios, que pode então ser usada
|
||||
para controlar por exemplo um filtro de itens.
|
||||
default:
|
||||
name: Interruptor
|
||||
description: Pode emitir alternadamente um sinal binário (1 ou 0) na camada de fios,
|
||||
que pode posteriormente ser usado, por exemplo, num filtro de itens.
|
||||
logic_gate:
|
||||
default:
|
||||
name: Portão AND
|
||||
description: Emite um booleano "1" se ambas as entradas são verdadeiras. (Verdadeiro significa forma, cor ou booleano "1")
|
||||
description: >-
|
||||
Emite um sinal binário "1" se ambas as entradas forem verdadeiras. (Verdadeiro significa:
|
||||
forma, cor ou sinal binário "1")
|
||||
not:
|
||||
name: Portão NOT
|
||||
description: Emite um booleano "1" se a entrada não é verdadeira. (Verdadeiro significa forma, cor ou booleano "1")
|
||||
description: >-
|
||||
Emite um sinal binário "1" se a entrada não for verdadeira. (Verdadeiro significa:
|
||||
forma, cor ou sinal binário "1")
|
||||
xor:
|
||||
name: Portão XOR
|
||||
description: Emite um booleano "1" se uma das entradas é verdadeira, mas não as duas. (Verdadeiro significa forma, cor ou booleano "1")
|
||||
description: >-
|
||||
Emite um sinal binário "1" se uma das entradas for verdadeira, mas não as duas. (Verdadeiro significa:
|
||||
forma, cor ou sinal binário "1")
|
||||
or:
|
||||
name: Portão OR
|
||||
description: Emite um booleano "1" se uma entrada é verdadeira. (Verdadeiro significa forma, cor ou booleano "1")
|
||||
description: >-
|
||||
Emite um sinal binário "1" se uma entrada é verdadeira. (Verdadeiro significa:
|
||||
forma, cor ou sinal binário "1")
|
||||
transistor:
|
||||
default:
|
||||
name: Transistor
|
||||
description: Encaminha a entrada inferior se a entrada lateral for verdade (uma forma, cor ou "1").
|
||||
name: Transístor
|
||||
description: Encaminha a entrada inferior se a entrada lateral for verdade
|
||||
(uma forma, cor ou "1").
|
||||
|
||||
mirrored:
|
||||
name: Transistor
|
||||
description: Encaminha a entrada inferior se a entrada lateral for verdade (uma forma, cor ou "1").
|
||||
name: Transístor
|
||||
description: Encaminha a entrada inferior se a entrada lateral for verdade
|
||||
(uma forma, cor ou "1").
|
||||
filter:
|
||||
default:
|
||||
name: Filtro
|
||||
description: Conecta um sinal para encaminhar todos os itens correspondentes para o topo e o resto
|
||||
para a direita. Pode ser controlado com sinais booleanos também.
|
||||
name: Filtro de Itens
|
||||
description: Conecta um sinal que irá encaminhar todos os itens correspondentes
|
||||
para o topo e os restantes para a direita. Também pode ser
|
||||
controlado com sinais binários.
|
||||
display:
|
||||
default:
|
||||
name: Display
|
||||
description: Conecta um sinal para mostrar no display - Pode ser uma forma, cor ou
|
||||
booleano.
|
||||
default:
|
||||
name: Visor
|
||||
description: Conecta um sinal para mostrar no Visor - Pode ser uma forma, cor
|
||||
ou um sinal binário.
|
||||
reader:
|
||||
default:
|
||||
name: Leitor de Tapete
|
||||
description: Permite medir o rendimento do tapete. Produz o último item lido na camada de
|
||||
fios (quando desbloqueada).
|
||||
default:
|
||||
name: Leitor de Tapete
|
||||
description:
|
||||
Permite medir a passagem média de itens no tapete. Fornece o último item lido na camada de
|
||||
fios (quando desbloqueada).
|
||||
analyzer:
|
||||
default:
|
||||
name: Analizador de Forma
|
||||
description: Analiza o quadrante do topo direito da camada mais baixa da forma e produz
|
||||
a forma ou cor.
|
||||
default:
|
||||
name: Analizador de Forma
|
||||
description: Analiza o quadrante superior direito da camada mais baixa da forma e retorna
|
||||
a forma ou cor.
|
||||
comparator:
|
||||
default:
|
||||
name: Comparar
|
||||
description: Produz o booleano "1" se ambos os itens são exatamente iguais. Pode comparar formas,
|
||||
itens e booleanos.
|
||||
default:
|
||||
name: Comparador
|
||||
description:
|
||||
Produz o sinal binário "1" se ambos os itens são exatamente iguais. Pode comparar formas,
|
||||
itens e sinais binários.
|
||||
virtual_processor:
|
||||
default:
|
||||
name: Cortador Virtual
|
||||
description: Computa
|
||||
description: Virtualmente, corta as formas em duas metades.
|
||||
rotater:
|
||||
name: Rodar Virtual
|
||||
description: Roda virtualmente as formas 90º no sentido dos ponteiros do relógio.
|
||||
name: Rodador Virtual
|
||||
description: Virtualmente, roda a forma tanto no sentido horário quanto no anti-horário.
|
||||
unstacker:
|
||||
name: Desempilhador Virtual
|
||||
description: Produz a camada no topo para a direita, e o resto para esquerda.
|
||||
description: Virtualmente, remove a camada do topo para a saída da direita
|
||||
e o restante para a da esquerda.
|
||||
stacker:
|
||||
name: Empilhador Virtual
|
||||
description: Empilha virtualmente o item da direita em cima do item da esquerda.
|
||||
description: Virtualmente empilhada a forma da direita em cima do item da esquerda.
|
||||
painter:
|
||||
name: Pintor Virtual
|
||||
description: Pinta virtualmente a forma de baixo com a forma da direita.
|
||||
description: Virtualmente, pinta a forma a forma da entrada de baixo
|
||||
com o item da entrada da direita.
|
||||
item_producer:
|
||||
default:
|
||||
name: Produtor de Itens
|
||||
description: Disponível apenas no modo sandbox, produz o sinal dado da camada de fios na camala normal.
|
||||
|
||||
description: Disponível apenas no modo sandbox, produz o sinal dado na
|
||||
camada de fios na camada normal.
|
||||
storyRewards:
|
||||
reward_cutter_and_trash:
|
||||
title: Corte de formas
|
||||
desc: Acabaste de desbloquear o <strong>Cortador</strong>, que corta as formas
|
||||
geométricas ao meio de cima para baixo <strong>independentemente da orientação</strong>!<br><br>Certifica-te de que te
|
||||
livras do desperdício, caso contrário <strong>encravará</strong> -
|
||||
Por isso, dou-te um lixo, que destruirá tudo o que lá colocares!
|
||||
desc: Acabaste de desbloquear o <strong>cortador</strong>, que corta as formas ao meio
|
||||
de cima para baixo <strong>independentemente da sua
|
||||
orientação</strong>!<br><br>Certefica-te de que te livras do desperdício,
|
||||
caso contrário <strong>irá encravar e parar</strong> - Para este propósito
|
||||
eu dei-te um <strong>lixo</strong>, que destrói
|
||||
tudo o que lá colocares!
|
||||
reward_rotater:
|
||||
title: Rotação
|
||||
desc: O <strong>Rodador</strong> foi desbloqueado! Ele roda as formas
|
||||
@ -610,8 +633,9 @@ storyRewards:
|
||||
esquerda!
|
||||
reward_splitter:
|
||||
title: Divisor
|
||||
desc: Desbloqueaste o <strong>divisor</strong>, variante do
|
||||
<strong>balanceador</strong> - Aceita uma entrada e divide-a em duas!
|
||||
desc: Desbloqueaste o <strong>dvisor</strong> uma variante do
|
||||
<strong>distribuidor</strong> - Aceita uma entradae divide-a
|
||||
em duas!
|
||||
reward_tunnel:
|
||||
title: Túnel
|
||||
desc: O <strong>Túnel</strong> foi desbloqueado - Com ele podes passar itens
|
||||
@ -624,94 +648,120 @@ storyRewards:
|
||||
variantes</strong>!
|
||||
reward_miner_chainable:
|
||||
title: Extração em série
|
||||
desc: >-
|
||||
Desbloqueaste o <strong>Extrator em série</strong>! Permite <strong>enviar
|
||||
o recurso extraído</strong> para outros extratores, permitindo uma
|
||||
extração mais eficiente!<br><br> PS: O velho extrator já foi trocado na tua toolbar!
|
||||
desc: "Desbloqueaste o <strong>extrator em séire</strong>! Permite
|
||||
<strong>enviar os recursos</strong> para outros extratores, sendo assim
|
||||
permite uma extração de recursos mais eficiente!<br><br> PS: O extrator
|
||||
antigo já foi trocado na tua lista de construções!"
|
||||
reward_underground_belt_tier_2:
|
||||
title: Túnel Nível II
|
||||
desc: Desbloqueaste uma nova variante do <strong>Túnel</strong> - Tem um <strong>maior alcance</strong>, e podes interlaçar as duas variantes entre si!
|
||||
desc: Desbloqueaste uma nova variante do <strong>Túnel</strong> - Tem um
|
||||
<strong>maior alcance</strong>, e podes interlaçar as duas variantes
|
||||
entre si!
|
||||
reward_cutter_quad:
|
||||
title: Corte quádruplo
|
||||
desc: Desbloqueaste a variante do <strong>Cortador</strong> - Permite cortar formas geométricas em <strong>quatro partes</strong> em vez de apenas duas!
|
||||
desc: Desbloqueaste a variante do <strong>Cortador</strong> - Permite cortar
|
||||
formas geométricas em <strong>quatro partes</strong> em vez de
|
||||
apenas duas!
|
||||
reward_painter_double:
|
||||
title: Pintura dupla
|
||||
desc: Desbloqueaste uma variante do <strong>Pintor</strong> - Funciona como um pintor normal mas processa <strong>duas formas ao mesmo tempo</strong> consumindo apenas uma cor em vez de duas!
|
||||
desc: Desbloqueaste uma variante do <strong>Pintor</strong> - Funciona como um
|
||||
pintor normal mas processa <strong>duas formas ao mesmo
|
||||
tempo</strong> consumindo apenas uma cor em vez de duas!
|
||||
reward_storage:
|
||||
title: Armazém
|
||||
desc: Desbloqueaste uma variante do <strong>Lixo</strong> - Permite armazenar items até uma determinada capacidade!<br><br> Prioritiza a saída esquerda, por isso também o podes usar como um portão de transbordar.
|
||||
desc: Desbloqueaste uma variante do <strong>lixo</strong> - Permite armazenar
|
||||
itens, até uma determinada capacidade!<br><br> Dá prioridade à saída da
|
||||
esquerda e pode ser usado como uma <strong>porta de transbordo</strong>!
|
||||
reward_freeplay:
|
||||
title: Jogo livre
|
||||
desc: Conseguiste! Desbloqueaste o <strong>modo jogo livre</strong>! Isto significa que agora as formas são geradas <strong>aleatoriamente</strong>!<br><br>
|
||||
Como o edifício central vai precisar de uma <strong>taxa de transferência</strong> a partir de
|
||||
agora, eu recomendo contruires uma máquina que automaticamente
|
||||
entrega a forma pedida!<br><br> O edifício central produz a forma pedida na camada de fios,
|
||||
então tudo o que tens de fazer é analizar-la e automaticamente configurar a tua fábrica à volta disso.
|
||||
desc: Conseguiste! Desbloqueaste o <strong>modo jogo livre</strong>! Isto
|
||||
significa que agora as formas são geradas <strong>aleatoriamente</strong>!<br><br>
|
||||
Como o edifício central vai precisar de uma <strong>taxa de rendimento</strong> a partir
|
||||
de agora, recomendo vivamente a contruires uma máquina que, automaticamente,
|
||||
entraga as formas pedidas!<br><br> O edifício central emite a forma pedida
|
||||
na camada de fios,sendo assim tudo o que tens a fazer é analiza-la e
|
||||
automaticamente configurares a tua fábrica baseada nisso.
|
||||
reward_blueprints:
|
||||
title: Projetos
|
||||
desc: Agora podes <strong>copiar e colar</strong> partes da tua fábrica! Seleciona uma área (Mantém pressionado CTRL e arrasta com o rato), e pressiona 'C' para copiar.<br><br>Colar não é <strong>gratuito</strong>, precisas de produzir <strong>formas projeto</strong> para o pagares! (Aquelas que acabaste de entregar).
|
||||
desc: Agora podes <strong>copiar e colar</strong> partes da tua fábrica!
|
||||
Seleciona uma área (Mantém pressionado CTRL e arrasta com o rato), e
|
||||
pressiona 'C' para copiar.<br><br>Colar não é
|
||||
<strong>gratuito</strong>, precisas de produzir <strong>formas
|
||||
projeto</strong> para o pagares! (Aquelas que acabaste de entregar).
|
||||
no_reward:
|
||||
title: Próximo nível
|
||||
desc: >-
|
||||
Este nível não te deu nenhuma recompensa, mas o próximo dará! <br><br> PS: É melhor não destruires a tua fábrica atual - Precisarás de <strong>todas</strong> essas formas no futuro para <strong>desbloquear upgrades</strong>!
|
||||
desc: "Este nível não te deu nenhuma recompensa, mas o próximo dará! <br><br>
|
||||
PS: É melhor não destruires a tua fábrica atual - Precisarás de
|
||||
<strong>todas</strong> essas formas no futuro para
|
||||
<strong>desbloquear upgrades</strong>!"
|
||||
no_reward_freeplay:
|
||||
title: Próximo nível
|
||||
desc: Parabéns! Já agora, está planeado mais conteúdo para o jogo completo!
|
||||
reward_balancer:
|
||||
title: Balanceador
|
||||
desc: O multifunctional <strong>balanceador</strong> foi desbloqueado - Pode ser usado
|
||||
para construir fábricas maiores <strong>dividindo e juntando itens</strong>
|
||||
por vários tapetes!<br><br>
|
||||
title: Distribuidor
|
||||
desc: O multifunctional <strong>distribuidor</strong> foi desbloqueado - Pode
|
||||
ser usado para construbir fábricas maiores <strong>dividindo e juntando
|
||||
itens</strong> por vários tapetes rolantes!<br><br>
|
||||
reward_merger:
|
||||
title: Junção (Compacto)
|
||||
desc: Destravaste a <strong>junção</strong> variante do
|
||||
<strong>balanceador</strong> - Aceita duas entradas e junta-as num só tapete!
|
||||
title: Misturador (compacto)
|
||||
desc: Desbloqueaste um <strong>misturador</strong>, uma variante do
|
||||
<strong>distribuidor</strong> - Aceita duas entradas e junta-as num só
|
||||
tapete rolante!
|
||||
reward_belt_reader:
|
||||
title: Leitor de Tapete
|
||||
desc: Tu desbloqueaste o <strong>leitor de tapete</strong>! Permite-te medir
|
||||
o rendimento dum tapete.<br><br>E espera até desbloqueares fios - aí é que é super útil!
|
||||
title: Leitor de Tapete
|
||||
desc: Desbloqueaste o <strong>leitor de tapete</strong>! Permite-te medires
|
||||
a passagem média de itens no tapete.<br><br>E espera por desbloqueares
|
||||
os fios - aí é que vão ser bastante úteis!
|
||||
reward_rotater_180:
|
||||
title: Rodar (180 degrees)
|
||||
desc: Acabaste de desbloquear a versão de 180º do <strong>Rotador</strong>! - Deixa-te rodar formas por 180º (Surpresa! :D)
|
||||
title: Rodar (180º)
|
||||
desc: Desbloqueaste o <strong>rodador</strong> de 180 graus! - Permite-te
|
||||
rodares formas 180 graus (Surpresa! :D)
|
||||
reward_display:
|
||||
title: Display
|
||||
desc: >-
|
||||
Destravaste o <strong>Display</strong> - Conecta um sinal elétrico na camada de fios para visualizar-lo!<br><br> PS:
|
||||
Reparaste que o leitor de tapetes e o armazém produz o último item lido por eles na camada de fios? Tenta mostrar isso num display!
|
||||
title: Visor
|
||||
desc: "Desbloqueaste o <strong>Visor</strong> - Conecta um sinal na
|
||||
camada de fios para o visualizares!<br><br> PS: Reparaste que o leitor
|
||||
de tapete e o armazém emitem o último item lido por eles? tenta mostrar isso
|
||||
num visor!"
|
||||
reward_constant_signal:
|
||||
title: Sinal Constante
|
||||
desc: Acabaste de destravar o edifício <strong>sinal constante</strong> na camada de fios!
|
||||
Isto é útil conectado a um <strong>filtro de itens</strong> por exemplo.<br><br>
|
||||
O sinal constante pode emitir uma <strong>forma</strong>,
|
||||
<strong>cor</strong> ou um <strong>booleano</strong> (1 / 0).
|
||||
title: Sinal Constante
|
||||
desc: Desbloqueaste o <strong>sinal constante</strong> contruido na camada
|
||||
de fios! Isto é útil conectado com um <strong>filtro de itens</strong>
|
||||
por exemplo.<br><br> O sinal constante pode emitir uma
|
||||
<strong>forma</strong>, <strong>cor</strong> ou
|
||||
<strong>sinal binário</strong> (1 ou 0).
|
||||
reward_logic_gates:
|
||||
title: Portões Lógicos
|
||||
desc: "Tu desbloqueaste os <strong>portões lógicos</strong>! Não tens de estar excitado sobre isto,
|
||||
mas é na verdade super fixe!<br><br> Com estes portões agora podes fazer operações booleanas
|
||||
AND, OR, XOR e NOT!"
|
||||
desc: Desbloqueaste os <strong>portões lógicos</strong>! N tens de te excitar
|
||||
com isto, mas é realmente super fixe!<br><br> Com estes portões
|
||||
agora podes realizar operações AND, OR, XOR and NOT.<br><br> Como um
|
||||
bónus anteriormente já de dei um <strong>transístor</strong>!
|
||||
reward_virtual_processing:
|
||||
title: Processamento Virtual
|
||||
desc: >-
|
||||
Acabei de te dar um monte de novos edifícios que permitem-te
|
||||
<strong>simular o processamento de formas</strong>!<br><br> Podes agora
|
||||
simular um cortador, rodar, empilhador e mais na camada de fios!<br><br>
|
||||
Com isto tens agora três opções para continuar o jogo:<br><br> - Construir
|
||||
uma <strong>máquina automatizada</strong> para criar qualquer forma requerida
|
||||
pelo edifício central (Isto é fixe, eu prometo!).<br><br> - Construir algo fixe com
|
||||
fios.<br><br> - Continuar a jogar regularmente. Seja lá o que escolheres, lembra-te de te divertires!
|
||||
desc: Acadei de te dar um monte de novas construções, que te vão permitir
|
||||
<strong>simular o processamento de formas</strong>!<br><br> Agora podes
|
||||
simular um cortador,um rodador, um empilhador e muito mais na camada de fios!
|
||||
Com isto, agora tens três opções para continuares o jogo:<br><br> -
|
||||
Construir uma <strong>máquina automática</strong> para criar qualquer forma
|
||||
possível pedida pelo Edifício Central (Reconmento-te a experimentares!).<br><br> - Contruir
|
||||
algo fixe com os fios.<br><br> - Continuar a jogar
|
||||
regularmente.<br><br> Independentemente da tua escolha, lembra-te de te divertires!
|
||||
reward_wires_painter_and_levers:
|
||||
title: Fios e Pintor Quádruplo
|
||||
desc: "Acabaste de desbloquear a <strong>Camada de Fios</strong>: É uma camada separada
|
||||
no topo da camada normal e introduz um monte de novas mecânicas!<br><br>
|
||||
Para o início eu dei-te o <strong>Pintor Quádruplo</strong> - Conecta os slots que queres pintar na
|
||||
camada de fios!<br><br> Para trocar para a camada de fios, pressiona <strong>E</strong>."
|
||||
title: Fios & Pintor Quádruplo
|
||||
desc: "Desbloquaste a <strong>Camada de Fios</strong>: É uma camada separada
|
||||
no topo da camada normal e introduz um monte de novas
|
||||
mecânicas!<br><br> Para o inicio eu dei-te o <strong>Pintor
|
||||
Quádruplo</strong> - Conecta as entradasque queres pintar na
|
||||
camada de fios!<br><br> Para trocares para a camada de fios, pressiona a tecla
|
||||
<strong>E</strong>."
|
||||
reward_filter:
|
||||
title: Filtro de Itens
|
||||
desc: Desbloqueaste o <strong>Filtro de Itens</strong>! Vai mandar items para a saída de topo ou para a saída da direita
|
||||
dependendo se são iguais ao sinal da camada de fios.<br><br> Também podes passar um sinal booleano (1 / 0) para ativar-lo ou desativar-lo completamente.
|
||||
desc: Desbloquaste o <strong>Filtro de Itens</strong>! Vai mandar itens ou
|
||||
para o topo ou para a saída da esquerda dependendo depending se são iguais ao
|
||||
sinal da camada de fios ou não.<br><br> Também podes passar um
|
||||
sinal binário (1 ou 0) para ativa-lo ou desativa-lo totalmente.
|
||||
reward_demo_end:
|
||||
title: Fim da Demo
|
||||
desc: Chegaste ao fim da versão demo!
|
||||
desc: Tu chegaste ao fim da versão demo!
|
||||
settings:
|
||||
title: Definições
|
||||
categories:
|
||||
@ -727,8 +777,9 @@ settings:
|
||||
labels:
|
||||
uiScale:
|
||||
title: Escala da interface
|
||||
description: >-
|
||||
Altera o tamanho da interface do utilizador. A interface será redimensionada com base na resolução do teu dispositivo, mas esta definição controla a escala.
|
||||
description: Altera o tamanho da interface do utilizador. A interface será
|
||||
redimensionada com base na resolução do teu dispositivo, mas
|
||||
esta definição controla a escala.
|
||||
scales:
|
||||
super_small: Super pequeno
|
||||
small: Pequeno
|
||||
@ -737,8 +788,7 @@ settings:
|
||||
huge: Enorme
|
||||
scrollWheelSensitivity:
|
||||
title: Sensibilidade do zoom
|
||||
description: >-
|
||||
Define o quão sensível é o zoom (Roda do rato ou trackpad).
|
||||
description: Define o quão sensível é o zoom (Roda do rato ou trackpado).
|
||||
sensitivity:
|
||||
super_slow: Muito lento
|
||||
slow: Lento
|
||||
@ -747,39 +797,41 @@ settings:
|
||||
super_fast: Muito rápido
|
||||
language:
|
||||
title: Língua
|
||||
description: >-
|
||||
Muda a língua. Todas as traduções são contribuições dos utilizadores e podem estar incompletas!
|
||||
description: Muda a língua. Todas as traduções são contribuições dos
|
||||
utilizadores e podem estar incompletas!
|
||||
fullscreen:
|
||||
title: Ecrã inteiro
|
||||
description: >-
|
||||
É recomendado jogar o jogo em ecrã inteiro para a melhor experiência. Apenas disponível no jogo completo.
|
||||
description: É recomendado jogar o jogo em ecrã inteiro para a melhor
|
||||
experiência. Apenas disponível no jogo completo.
|
||||
soundsMuted:
|
||||
title: Desativar sons
|
||||
description: >-
|
||||
Se ativado, desativa todos os sons.
|
||||
description: Se ativado, desativa todos os sons.
|
||||
musicMuted:
|
||||
title: Desativar música
|
||||
description: >-
|
||||
Se ativado, desativa todas as músicas.
|
||||
description: Se ativado, desativa todas as músicas.
|
||||
theme:
|
||||
title: Tema do jogo
|
||||
description: >-
|
||||
Escolhe o tema do jogo (claro / escuro).
|
||||
description: Escolhe o tema do jogo (claro / escuro).
|
||||
themes:
|
||||
dark: Escuro
|
||||
light: Claro
|
||||
refreshRate:
|
||||
title: Frequência
|
||||
description: >-
|
||||
Isto determina quantos game ticks ocorrem por segundo. No geral, uma frequência alta significa melhor precisão mas também pior desempenho. Em frequências baixas, o rendimento pode não ser exato.
|
||||
description: Se tens um monitor 144hz, muda a frequência para que o jogo simule
|
||||
corretamente frequências de autalização altas. Isto pode
|
||||
resultar em perda de FPS se o teu computador for demasiado
|
||||
lento.
|
||||
alwaysMultiplace:
|
||||
title: Colocação múltipla
|
||||
description: >-
|
||||
Se ativado, todas as construções permanecerão selecionadas após a colocação até cancelares. Isto é equivalente a pressionares SHIFT permanentemente.
|
||||
description: Se ativado, todas as construções permanecerão selecionadas após a
|
||||
colocação até cancelares. Isto é equivalente a pressionares
|
||||
SHIFT permanentemente.
|
||||
offerHints:
|
||||
title: Dicas e tutoriais
|
||||
description: >-
|
||||
Se ativado, dá dicas e tutoriais de apoio ao jogo. Adicionalmente, esconde certos elementos da interface do utilizador até ao nível em que são desbloqueados de forma a simplificar o início do jogo.
|
||||
description: Se ativado, dá dicas e tutoriais de apoio ao jogo. Adicionalmente,
|
||||
esconde certos elementos da interface do utilizador até ao nível
|
||||
em que são desbloqueados de forma a simplificar o início do
|
||||
jogo.
|
||||
movementSpeed:
|
||||
title: Velocidade de movimentação
|
||||
description: Define quão rápida é a movimentação usando o teclado.
|
||||
@ -792,19 +844,17 @@ settings:
|
||||
extremely_fast: Extremamente rápida
|
||||
enableTunnelSmartplace:
|
||||
title: Túneis inteligentes
|
||||
description: >-
|
||||
Quando ativado, a colocação de túneis removerá tapetes desnecessários automaticamente.
|
||||
Isto também permite arrastar túneis e túneis em excesso serão removidos.
|
||||
description: Quando ativado, a colocação de túneis removerá tapetes
|
||||
desnecessários automaticamente. Isto também permite arrastar
|
||||
túneis e túneis em excesso serão removidos.
|
||||
vignette:
|
||||
title: Vinheta
|
||||
description: >-
|
||||
Ativa a vinheta, que escurece os cantos do ecrã e torna a leitura do texto
|
||||
mais fácil.
|
||||
description: Ativa a vinheta, que escurece os cantos do ecrã e torna a leitura
|
||||
do texto mais fácil.
|
||||
autosaveInterval:
|
||||
title: Intervalo de gravação automática
|
||||
description: >-
|
||||
Define o quão frequentemente o jogo grava automaticamente. Também podes desativar
|
||||
aqui.
|
||||
description: Define o quão frequentemente o jogo grava automaticamente. Também
|
||||
podes desativar aqui.
|
||||
intervals:
|
||||
one_minute: 1 Minuto
|
||||
two_minutes: 2 Minutos
|
||||
@ -814,69 +864,68 @@ settings:
|
||||
disabled: Desligado
|
||||
compactBuildingInfo:
|
||||
title: Informações de construções compactas
|
||||
description: >-
|
||||
Encurta caixas de informação e apenas mostra os respetivos rácios. Caso contrário
|
||||
é mostrada a descrição e a imagem.
|
||||
description: Encurta caixas de informação e apenas mostra os respetivos rácios.
|
||||
Caso contrário é mostrada a descrição e a imagem.
|
||||
disableCutDeleteWarnings:
|
||||
title: Desativar Avisos de Corte/Eliminação
|
||||
description: >-
|
||||
Desativa os avisos mostrados quando é feito o corte ou a eliminação de mais de 100
|
||||
entidades.
|
||||
description: Desativa os avisos mostrados quando é feito o corte ou a eliminação
|
||||
de mais de 100 entidades.
|
||||
enableColorBlindHelper:
|
||||
title: Modo Daltónico
|
||||
description: Ativa várias ferramentas que te permitirão jogar o jogo se fores daltónico.
|
||||
description: Ativa várias ferramentas que te permitirão jogar o jogo se fores
|
||||
daltónico.
|
||||
rotationByBuilding:
|
||||
title: Rotação por tipo de construção
|
||||
description: >-
|
||||
Cada tipo de construção lembra-se da última rotação que definiste.
|
||||
Esta definição pode ser mais confortável se alterares frequentemente
|
||||
a colocação de diferentes tipos de construções.
|
||||
description: Cada tipo construção lembra-se da última rotação que definiste.
|
||||
Esta definição pode ser mais confortável se alterares
|
||||
frequentemente a colocação de diferentes tipos de construções.
|
||||
soundVolume:
|
||||
title: Volume do Som
|
||||
description: Define o volume para efeitos sonoros
|
||||
title: Volume do Som
|
||||
description: Define o volume para efeitos sonoros
|
||||
musicVolume:
|
||||
title: Volume da Música
|
||||
description: Define o volume para música
|
||||
title: Volume da Música
|
||||
description: Define o volume para música
|
||||
lowQualityMapResources:
|
||||
title: Recursos de Mapa de Baixa Qualidade
|
||||
description: >-
|
||||
Simplifica a renderização de recursos quanto o mapa está ampliado para melhorar o desempenho. Até parece mais limpo, então lembra-te de experimentar!
|
||||
title: Recursos de Mapa de Baixa Qualidade
|
||||
description: Simplifica a renderização de recursos quando o mapa está ampliado para
|
||||
melhorar o desempenho. Até parece mais limpo, então lembra-te de
|
||||
experimentares!
|
||||
disableTileGrid:
|
||||
title: Desativar Grelha
|
||||
description: >-
|
||||
Desativar a grelha pode ajudar com o desempenho. Isto também faz o jogo estar mais limpo!
|
||||
title: Desativar Grelha
|
||||
description: Desativar a grelha pode ajudar com o desempenho. Isto também
|
||||
fazz o jogo parecer mais limpo!
|
||||
clearCursorOnDeleteWhilePlacing:
|
||||
title: Limpar Cursor com Clique Direito
|
||||
description: >-
|
||||
Ativado por default, limpa o cursos sempre que clicas no botão direito do rato enquanto tens um edifício selecionado para colocamento.
|
||||
Se desativado, podes apagar edifícios fazendo um clique direito enquanto colocas um edifício.
|
||||
title: Limpar Cursor com Clique Direito
|
||||
description: Ativado por padrão, limpa o cursor sempre que pressionas o botão direito do rato
|
||||
enquanto tens um edifício para colocamento. Se desativado,
|
||||
podes apagar construções pressionando o botão direito do rato enquanto colocas um
|
||||
edifício.
|
||||
lowQualityTextures:
|
||||
title: Texturas de baixa qualidade (Feio)
|
||||
description: >-
|
||||
Usa texturas de baixa qualidade para melhorar o desempenho. Isto vai tornar o jogo muito feio!
|
||||
title: Texturas de baixa qualidade (Feio)
|
||||
description: sa texturas de baixa qualidade para melhorar o desempenho. sto vai tornar o
|
||||
jogo parecer muito feio!
|
||||
displayChunkBorders:
|
||||
title: Mostrar bordas de Chunks
|
||||
description: >-
|
||||
O jogo está dividido em pedaços de 16x16 quadrados, se esta definição estiver ativada
|
||||
as bordas de cada pedaço são mostradas.
|
||||
title: Mostrar bordas de limites (chunk borders)
|
||||
description: O jogo está dividido em partes de 16x16 quadrados, se esta dedinição estiver
|
||||
ativada as bordas de cada limitece são mostradas.
|
||||
pickMinerOnPatch:
|
||||
title: Selecionar extrator num remendo de recursos
|
||||
description: >-
|
||||
Ativado por default, seleciona o extrator se usares a pipeta enquanto estás num remendo de recursos.
|
||||
title: Selecionar extrator num quadrado de recurso
|
||||
description: Ativado por padrão, seleciona um extrator se usares a pipeta quando
|
||||
estiveres com o rato em cima de um quadrado de recurso.
|
||||
simplifiedBelts:
|
||||
title: Tapetes rolantes simplificados (Feio)
|
||||
description: >-
|
||||
Não renderiza itens em tapetes excepto quando tens o rato em cima do tapete para salvar desempenho.
|
||||
Não recomendo jogares com esta definição a menos que absolutamente precisas do desempenho.
|
||||
title: Tapetes rolantes simplificados (Feio)
|
||||
description: Não renderiza os intens nos tapetes excepto quando tens o rato em cima do tapete
|
||||
para melhorar o desempenho. Não recomendo a jogares com esta definição ativada
|
||||
a não ser que precises mesmo de melhorar o desempenho.
|
||||
enableMousePan:
|
||||
title: Ativar Mouse Pan
|
||||
description: >-
|
||||
Permite-te mover o mapa apenas movendo o rato aos cantos do ecrã. A velocidade depende da definição Velocidade de movimentação.
|
||||
title: Ativar rato panorâmico
|
||||
description: Permite-te mover o mapa movento o rato nos cantos do
|
||||
ecrâ. A velociade depende da definição de velocidade de movimentação.
|
||||
rangeSliderPercentage: <amount> %
|
||||
keybindings:
|
||||
title: Atalhos
|
||||
hint: >-
|
||||
Tip: Utiliza o CTRL, o SHIFT e o ALT! Eles permitem diferentes opções de posicionamento.
|
||||
hint: "Dica: Utiliza o CTRL, o SHIFT e o ALT! Eles permitem diferentes opções de
|
||||
posicionamento."
|
||||
resetKeybindings: Resetar Atalhos
|
||||
categoryLabels:
|
||||
general: Aplicação
|
||||
@ -931,13 +980,12 @@ keybindings:
|
||||
menuClose: Fechar Menu
|
||||
switchLayers: Troca de camadas
|
||||
wire: Fio Elétrico
|
||||
balancer: Balanceador
|
||||
balancer: Distribuidor
|
||||
storage: Armazém
|
||||
constant_signal: Sinal Constante
|
||||
logic_gate: Portões Lógicos
|
||||
lever: Interruptor (normal)
|
||||
lever_wires: Interruptor (fios)
|
||||
filter: Filtro
|
||||
filter: Filtro de itens
|
||||
wire_tunnel: Túnel de Fio
|
||||
display: Display
|
||||
reader: Leitor de Tapete
|
||||
@ -972,13 +1020,13 @@ demo:
|
||||
exportingBase: Exportar base como uma imagem
|
||||
settingNotAvailable: Não disponível no Demo.
|
||||
tips:
|
||||
- 'O edifício central aceita qualquer entrada, não apenas a forma atual!'
|
||||
- "O edifício central aceita qualquer entrada, não apenas a forma atual!"
|
||||
- Tem a certeza que as tuas fábricas são modulares - vai valer a pena!
|
||||
- 'Não construas demasiado perto do edifício, ou vai ser um grande caos!'
|
||||
- 'Se empilhar não funciona, tenta trocar as entradas.'
|
||||
- "Não construas demasiado perto do edifício, ou vai ser um grande caos!"
|
||||
- "Se empilhar não funciona, tenta trocar as entradas."
|
||||
- Podes alternar a direção do planeador de tapete rolante ao pressionar <b>R</b>.
|
||||
- Ao segurar <b>CTRL</b> podes arrastar tapetes rolantes sem auto-orientação.
|
||||
- 'Os rácios continuam os mesmos, desde que todos os upgrades estejam no mesmo Nível.'
|
||||
- "Os rácios continuam os mesmos, desde que todos os upgrades estejam no mesmo Nível."
|
||||
- Execução em série é mais eficiente que em paralelo.
|
||||
- Vais desbloquear mais variações de edifícios mais tarde no jogo!
|
||||
- Podes usar <b>T</b> para trocar entre as diferentes variantes.
|
||||
@ -987,11 +1035,11 @@ tips:
|
||||
- Tenta construir fábricas compactas - vai valer a pena!
|
||||
- O pintor tem uma variante espelhada que podes selectionar com <b>T</b>
|
||||
- Ter os rácios de edifícios corretos vai maximizar a eficiência.
|
||||
- 'No nível máximo, 5 extratores vão encher um tapete.'
|
||||
- "No nível máximo, 5 extratores vão encher um tapete."
|
||||
- Não te esqueças dos túneis!
|
||||
- Não tens de dividir os itens uniformemente para eficiência máxima.
|
||||
- Segurar <b>SHIFT</b> vai ativar o planeador de tapetes, deixando-te colocar longas linhas de tapetes facilmente.
|
||||
- 'Os cortadores cortam sempre verticalmente, independentemente da sua orientação.'
|
||||
- "Os cortadores cortam sempre verticalmente, independentemente da sua orientação."
|
||||
- Para obter branco junta as três cores.
|
||||
- O buffer do armazém prioritiza a primeira saída.
|
||||
- Investe tempo para costruir designs repetiveis - vale a pena!
|
||||
@ -999,32 +1047,32 @@ tips:
|
||||
- Podes segurar <b>ALT</b> para inverter a direção de tapetes colocados.
|
||||
- Eficiência é a solução!
|
||||
- As formas que estão mais longes do edifício central são mais complexas.
|
||||
- 'As Máquinas têm uma velocidade limitada, divide-as para eficiência máxima.'
|
||||
- "As Máquinas têm uma velocidade limitada, divide-as para eficiência máxima."
|
||||
- Usa balanceadores para maximizar a tua eficiência.
|
||||
- Organização é importante. Tenta não cruzar tapetes demasiado.
|
||||
- 'Planeja antecipadamente, ou vai ser um grande caos!'
|
||||
- "Planeja antecipadamente, ou vai ser um grande caos!"
|
||||
- Não removas as tuas fábricas antigas! Vais precisar delas para desbloquear upgrades.
|
||||
- Tenta superar o nível 18 sozinho sem procurar ajuda!
|
||||
- 'Não complicas as coisas, tenta continuar simples e irás muito longe.'
|
||||
- "Não complicas as coisas, tenta continuar simples e irás muito longe."
|
||||
- Talvez precises de reusar fábricas mais tarde no jogo. Planeia as tuas fábricas para serem reutilizáveis.
|
||||
- Às vezes, podes encontrar uma forma necessária no mapa sem criar-la com empilhadoras.
|
||||
- Moinhos de vento e cataventos completos nunca aparecem naturalmente.
|
||||
- Pinta as tuas formas antes de cortar-las para eficiência máxima.
|
||||
- 'Com módulos, o espaço é apenas uma percepção; uma preocupação para pessoas mortais.'
|
||||
- "Com módulos, o espaço é apenas uma percepção; uma preocupação para pessoas mortais."
|
||||
- Faz uma fábrica de diagramas separada. São importantes para módulos.
|
||||
- 'Dá uma olhada ao misturador de cores, e as tuas questões serão respondidas.'
|
||||
- "Dá uma olhada ao misturador de cores, e as tuas questões serão respondidas."
|
||||
- Use <b>CTRL</b> + Clique para selecionar uma área.
|
||||
- Construir demasiado perto do edifício central pode ficar no caminho de projetos futuros.
|
||||
- O ícone de alfinete perto duma forma na lista de upgrades vai afixar-la ao ecrã.
|
||||
- Junta todas as cores primárias juntas para fazer branco!
|
||||
- 'Tu tens um mapa infinito, não limites a tua fábrica, expande!'
|
||||
- "Tu tens um mapa infinito, não limites a tua fábrica, expande!"
|
||||
- Tenta também Factorio! É o meu jogo favorito.
|
||||
- O cortador quádruplo corta no sentido dos ponteiros começando no canto superior direito!
|
||||
- Podes fazer download dos teus savegames no menu principal!
|
||||
- Este jogo tem muitos atalhos de teclado úteis! Não te esqueças de verificar a página de configurações.
|
||||
- 'Este jogo tem muitas definições, não te esqueças de as verificar!'
|
||||
- "Este jogo tem muitas definições, não te esqueças de as verificar!"
|
||||
- O marco para o teu edifício central tem uma pequena bússola para indicar a sua direção!
|
||||
- 'Para limpar tapetes, corta a área e cola-a na mesma localização.'
|
||||
- "Para limpar tapetes, corta a área e cola-a na mesma localização."
|
||||
- Pressiona F4 para mostrar os teus FPS e Tick Rate.
|
||||
- Pressiona F4 duas vezes para mostrar a tile do teu rato e câmara.
|
||||
- Podes clicar numa forma afixada no lado direito para desafixar-la.
|
||||
|
||||
@ -5,7 +5,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
automated production of geometric shapes.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
|
||||
|
||||
@ -1,51 +1,50 @@
|
||||
steamPage:
|
||||
shortText: shapez.io — это игра о строительстве фабрик для автоматизации
|
||||
создания и объединения все более сложных фигур на бесконечной карте.
|
||||
discordLinkShort: Official Discord
|
||||
discordLinkShort: Официальный Discord сервер
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
Shapez.io - это спокойная игра о создании фабрик для автоматизации создания сложных геометрических фигур.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
По мере управления уровня, фигуры становятся все сложнее, так что придется расширять фабрику засчет бесконечной карты.
|
||||
|
||||
And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling!
|
||||
Если этого мало, то Вам так же придется экспоненциально производить все больше и больше фигур, чтобы удовлетворить потребности Вашей фабрики. Ключ к успеху - расширение!
|
||||
|
||||
While you only process shapes at the beginning, you have to color them later - for this you have to extract and mix colors!
|
||||
Вначале игры Вам понадобится производить только фигуры, однако позже фигуры надо будет окрашивать. Для этого добывайте и смешивайте краски!
|
||||
|
||||
Buying the game on Steam gives you access to the full version, but you can also play a demo on shapez.io first and decide later!
|
||||
title_advantages: Standalone Advantages
|
||||
Приобретение игры в Steam предоставляет доступ к полной версии игры, но вы можете опробовать демоверсию игры на shapez.io и принять решение позже!
|
||||
title_advantages: Преимущества полной версии
|
||||
advantages:
|
||||
- <b>12 New Level</b> for a total of 26 levels
|
||||
- <b>18 New Buildings</b> for a fully automated factory!
|
||||
- <b>20 Upgrade Tiers</b> for many hours of fun!
|
||||
- <b>Wires Update</b> for an entirely new dimension!
|
||||
- <b>Dark Mode</b>!
|
||||
- Unlimited Savegames
|
||||
- Unlimited Markers
|
||||
- Support me! ❤️
|
||||
title_future: Planned Content
|
||||
- <b>12 новых уровней</b> - всего 26 уровней!
|
||||
- <b>18 новых построек</b> для полностью автоматизированной фабрики!
|
||||
- <b>20 стадий улучшения</b> для долгих часов веселья!
|
||||
- <b>Провода</b> - открывает полноценное новое измерение!
|
||||
- <b>Темная тема</b>!
|
||||
- Неограниченные сохранения
|
||||
- Неограниченные маркеры
|
||||
- Поддержите меня! ❤️
|
||||
title_future: Запланированный контент
|
||||
planned:
|
||||
- Blueprint Library (Standalone Exclusive)
|
||||
- Steam Achievements
|
||||
- Puzzle Mode
|
||||
- Minimap
|
||||
- Mods
|
||||
- Sandbox mode
|
||||
- ... and a lot more!
|
||||
title_open_source: This game is open source!
|
||||
title_links: Links
|
||||
- Библиотека чертежей (только для Полной версии)
|
||||
- Достижения Steam
|
||||
- Режим головоломок
|
||||
- Мини-карта
|
||||
- Моды
|
||||
- Режим песочницы
|
||||
- ... и многое другое!
|
||||
title_open_source: Эта игра находится в открытом доступе!
|
||||
title_links: Ссылки
|
||||
links:
|
||||
discord: Official Discord
|
||||
roadmap: Roadmap
|
||||
discord: Официальный Discord сервер
|
||||
roadmap: Планы
|
||||
subreddit: Subreddit
|
||||
source_code: Source code (GitHub)
|
||||
translate: Help translate
|
||||
source_code: Исходный код (GitHub)
|
||||
translate: Помочь с переводом
|
||||
text_open_source: >-
|
||||
Anybody can contribute, I'm actively involved in the community and
|
||||
attempt to review all suggestions and take feedback into consideration
|
||||
where possible.
|
||||
Кто угодно может внести свой вклад в разработку игры - я активно вовлечен
|
||||
в сообщество и стараюсь просмотреть все предложения и по возможности
|
||||
прислушиваться к отзывам.
|
||||
|
||||
Be sure to check out my trello board for the full roadmap!
|
||||
Не забудьте заглянуть на мой Trello board, чтобы ознакомиться с планами на будущее!
|
||||
global:
|
||||
loading: Загрузка
|
||||
error: Ошибка
|
||||
@ -78,7 +77,7 @@ global:
|
||||
shift: SHIFT
|
||||
space: ПРОБЕЛ
|
||||
demoBanners:
|
||||
title: Демо-версия
|
||||
title: Демоверсия
|
||||
intro: Приобретите полную версию, чтобы разблокировать все возможности!
|
||||
mainMenu:
|
||||
play: Играть
|
||||
@ -121,9 +120,9 @@ dialogs:
|
||||
text: Не удалось загрузить сохранение игры.
|
||||
confirmSavegameDelete:
|
||||
title: Подтвердите удаление.
|
||||
text: Are you sure you want to delete the following game?<br><br>
|
||||
'<savegameName>' at level <savegameLevel><br><br> This can not be
|
||||
undone!
|
||||
text: Вы уверены, что хотите удалить это сохранение?<br><br>
|
||||
'<savegameName>' на уровне <savegameLevel><br><br> Это не может
|
||||
быть отменено!
|
||||
savegameDeletionError:
|
||||
title: Ошибка удаления
|
||||
text: Не удалось удалить сохранение игры.
|
||||
@ -142,13 +141,13 @@ dialogs:
|
||||
title: Сброс управления
|
||||
desc: Настройки управления сброшены до соответствующих значений по умолчанию!
|
||||
featureRestriction:
|
||||
title: Демо-версия
|
||||
title: Демоверсия
|
||||
desc: Вы попытались получить доступ к функции (<feature>), которая недоступна в
|
||||
демо-версии. Вы можете приобрести полную версию чтобы пользоваться
|
||||
демоверсии. Вы можете приобрести полную версию чтобы пользоваться
|
||||
всеми функциями!
|
||||
oneSavegameLimit:
|
||||
title: Лимит сохранений
|
||||
desc: Вы можете иметь только одно сохранение игры в демо-версии. Пожалуйста,
|
||||
desc: Вы можете иметь только одно сохранение игры в демоверсии. Пожалуйста,
|
||||
удалите существующее или приобретите полную версию!
|
||||
updateSummary:
|
||||
title: Новое обновление!
|
||||
@ -177,11 +176,11 @@ dialogs:
|
||||
Инвертировать направление размещаемых конвейерных лент.<br>"
|
||||
createMarker:
|
||||
title: Новый маркер
|
||||
desc: Give it a meaningful name, you can also include a <strong>short
|
||||
key</strong> of a shape (Which you can generate <link>here</link>)
|
||||
desc: Дайте ему значимое название, вы также можете добавить <strong>короткий
|
||||
ключ</strong> фигуры (Который можно сгенерировать <link>здесь</link>)
|
||||
titleEdit: Редактирование маркера
|
||||
markerDemoLimit:
|
||||
desc: Вы можете создать только 2 своих маркера в демо-версии. Приобретите полную
|
||||
desc: Вы можете создать только 2 своих маркера в демоверсии. Приобретите полную
|
||||
версию для безлимитных маркеров.
|
||||
massCutConfirm:
|
||||
title: Подтвердите вырезку
|
||||
@ -197,18 +196,17 @@ dialogs:
|
||||
desc: Вы не можете позволить себе вставить эту область! Вы уверены, что хотите
|
||||
вырезать ее?
|
||||
editSignal:
|
||||
title: Set Signal
|
||||
descItems: "Choose a pre-defined item:"
|
||||
descShortKey: ... or enter the <strong>short key</strong> of a shape (Which you
|
||||
can generate <link>here</link>)
|
||||
title: Установить Сигнал
|
||||
descItems: "Выберите объект:"
|
||||
descShortKey: ... или введите <strong>короткий
|
||||
ключ</strong> фигуры (Который можно сгенерировать <link>здесь</link>)
|
||||
renameSavegame:
|
||||
title: Rename Savegame
|
||||
desc: You can rename your savegame here.
|
||||
title: Переименовать Сохранение
|
||||
desc: Здесь вы можете изменить название своего сохранения.
|
||||
entityWarning:
|
||||
title: Performance Warning
|
||||
desc: You have placed a lot of buildings, this is just a friendly reminder that
|
||||
the game can not handle an endless count of buildings - So try to
|
||||
keep your factories compact!
|
||||
title: Вы разместили очень много построек, это просто напоминание о том, что игра
|
||||
не может справиться с бесконечным количеством построек. Так что
|
||||
постарайтесь создавать компактные фабрики!
|
||||
ingame:
|
||||
keybindingsOverlay:
|
||||
moveMap: Передвижение
|
||||
@ -217,7 +215,7 @@ ingame:
|
||||
rotateBuilding: Повернуть постройку
|
||||
placeMultiple: Поставить несколько
|
||||
reverseOrientation: Реверсировать направление
|
||||
disableAutoOrientation: Отключить авто-определение направления
|
||||
disableAutoOrientation: Отключить автоопределение направления
|
||||
toggleHud: Переключить HUD
|
||||
placeBuilding: Разместить постройку
|
||||
createMarker: Создать маркер
|
||||
@ -343,41 +341,41 @@ ingame:
|
||||
empty: Пусто
|
||||
copyKey: Копировать
|
||||
connectedMiners:
|
||||
one_miner: 1 Miner
|
||||
n_miners: <amount> Miners
|
||||
limited_items: Limited to <max_throughput>
|
||||
one_miner: 1 Экстрактор
|
||||
n_miners: <amount> Экстрактора(-ов)
|
||||
limited_items: Ограничено до <max_throughput>
|
||||
watermark:
|
||||
title: Demo version
|
||||
desc: Click here to see the Steam version advantages!
|
||||
get_on_steam: Get on steam
|
||||
title: Демоверсия
|
||||
desc: Нажмите сюда, чтобы узнать о преимуществах Steam версии!
|
||||
get_on_steam: Приобрести в Steam
|
||||
standaloneAdvantages:
|
||||
title: Get the full version!
|
||||
no_thanks: No, thanks!
|
||||
title: Приобретите полную версию!
|
||||
no_thanks: Нет, спасибо!
|
||||
points:
|
||||
levels:
|
||||
title: 12 New Levels
|
||||
desc: For a total of 26 levels!
|
||||
title: 12 Новых Уровней!
|
||||
desc: Всего 26 уровней!
|
||||
buildings:
|
||||
title: 18 New Buildings
|
||||
desc: Fully automate your factory!
|
||||
title: 18 новых Построек!
|
||||
desc: Полностью автоматизируйте свою фабрику!
|
||||
savegames:
|
||||
title: ∞ Savegames
|
||||
desc: As many as your heart desires!
|
||||
title: ∞ Сохранений
|
||||
desc: Сколько Вашей душе угодно!
|
||||
upgrades:
|
||||
title: 20 Upgrade Tiers
|
||||
desc: This demo version has only 5!
|
||||
title: 20 стадий улучшений!
|
||||
desc: В демоверсии всего 5!
|
||||
markers:
|
||||
title: ∞ Markers
|
||||
desc: Never get lost in your factory!
|
||||
title: ∞ Маркеров!
|
||||
desc: Никогда не теряйтесь в своей фабрике!
|
||||
wires:
|
||||
title: Wires
|
||||
desc: An entirely new dimension!
|
||||
title: Провода!
|
||||
desc: Полноценное дополнительное измерение!
|
||||
darkmode:
|
||||
title: Dark Mode
|
||||
desc: Stop hurting your eyes!
|
||||
title: Темная Тема!
|
||||
desc: Дайте глазам отдохнуть!
|
||||
support:
|
||||
title: Support me
|
||||
desc: I develop it in my spare time!
|
||||
title: Поддержите меня
|
||||
desc: Я занимаюсь разработкой в свободное время!
|
||||
shopUpgrades:
|
||||
belt:
|
||||
name: Конвейеры, Разделители & Туннели
|
||||
@ -417,11 +415,11 @@ buildings:
|
||||
default:
|
||||
name: Резак
|
||||
description: Разрезает фигуры сверху вниз и выводит обе половины. <strong>Если
|
||||
Вы собираетесь использовать только одну часть, уничтожьте
|
||||
вы собираетесь использовать только одну часть, уничтожьте
|
||||
другую, иначе производство остановится!</strong>
|
||||
quad:
|
||||
name: Резак (4Вых.)
|
||||
description: Разрезает фигуры на четыре части. <strong>Если Вы собираетесь
|
||||
description: Разрезает фигуры на четыре части. <strong>Если вы собираетесь
|
||||
использовать не все части - уничтожьте оставшиеся, иначе
|
||||
производство остановится!</strong>
|
||||
rotater:
|
||||
@ -432,8 +430,8 @@ buildings:
|
||||
name: Вращатель (Обр.)
|
||||
description: Поворачивает фигуры против часовой стрелки на 90 градусов.
|
||||
rotate180:
|
||||
name: Rotate (180)
|
||||
description: Rotates shapes by 180 degrees.
|
||||
name: Вращатель (180)
|
||||
description: Поворачивает фигуры на 180 градусов.
|
||||
stacker:
|
||||
default:
|
||||
name: Объединитель
|
||||
@ -452,9 +450,9 @@ buildings:
|
||||
description: Красит фигуру из левых входов красителем из перпендикулярного.
|
||||
quad:
|
||||
name: Покрасчик (4Вх.)
|
||||
description: Allows you to color each quadrant of the shape individually. Only
|
||||
slots with a <strong>truthy signal</strong> on the wires layer
|
||||
will be painted!
|
||||
description: Позволяет отдельно окрашивать каждую часть фигуры. Только ячейки с
|
||||
<strong>положительным сигналом</strong> на слое с проводами
|
||||
будут окрашены!
|
||||
mirrored:
|
||||
name: Покрасчик
|
||||
description: Красит всю фигуру из левого входа красителем из перпендикулярного.
|
||||
@ -466,134 +464,132 @@ buildings:
|
||||
deliver: Доставить
|
||||
toUnlock: чтобы открыть
|
||||
levelShortcut: Ур.
|
||||
endOfDemo: End of Demo
|
||||
endOfDemo: Конец Демо
|
||||
wire:
|
||||
default:
|
||||
name: Энерг. провод
|
||||
description: Позволяет транспортировать энергию.
|
||||
second:
|
||||
name: Wire
|
||||
description: Transfers signals, which can be items, colors or booleans (1 / 0).
|
||||
Different colored wires do not connect.
|
||||
name: Энерг. провод
|
||||
description: Передает сигналы, которые могут быть ресурсами, цветами или логическими значениями (1 / 0).
|
||||
Провода разных цветов не соединяются.
|
||||
balancer:
|
||||
default:
|
||||
name: Balancer
|
||||
description: Multifunctional - Evenly distributes all inputs onto all outputs.
|
||||
name: Балансер
|
||||
description: Многофункциональный - равномерно распределяет все входы на выходы.
|
||||
merger:
|
||||
name: Merger (compact)
|
||||
description: Merges two conveyor belts into one.
|
||||
name: Соединитель (компактный)
|
||||
description: Соединяет две линии ковейера в одну.
|
||||
merger-inverse:
|
||||
name: Merger (compact)
|
||||
description: Merges two conveyor belts into one.
|
||||
name: Соединитель (компактный)
|
||||
description: Соединяет две линии ковейера в одну.
|
||||
splitter:
|
||||
name: Splitter (compact)
|
||||
description: Splits one conveyor belt into two.
|
||||
name: Разделитель (компактный)
|
||||
description: Разделяет одну линию конвейера на две.
|
||||
splitter-inverse:
|
||||
name: Splitter (compact)
|
||||
description: Splits one conveyor belt into two.
|
||||
name: Разделитель (компактный)
|
||||
description: Разделяет одну линию конвейера на две.
|
||||
storage:
|
||||
default:
|
||||
name: Storage
|
||||
description: Stores excess items, up to a given capacity. Prioritizes the left
|
||||
output and can be used as an overflow gate.
|
||||
name: Буферное Хранилище
|
||||
description: Хранит излишние ресурсы пока есть место. Левый выход в приоритете, может быть использован как буфер.
|
||||
wire_tunnel:
|
||||
default:
|
||||
name: Wire Crossing
|
||||
description: Allows to cross two wires without connecting them.
|
||||
name: Пересечение Проводов
|
||||
description: Позволяет пересекать провода при этом их не соединяя.
|
||||
constant_signal:
|
||||
default:
|
||||
name: Constant Signal
|
||||
description: Emits a constant signal, which can be either a shape, color or
|
||||
boolean (1 / 0).
|
||||
name: Постоянный Сигнал
|
||||
description: Издает постоянный сигнал, который может быть ресурсом, цветом или логическим значением (1 / 0).
|
||||
lever:
|
||||
default:
|
||||
name: Switch
|
||||
description: Can be toggled to emit a boolean signal (1 / 0) on the wires layer,
|
||||
which can then be used to control for example an item filter.
|
||||
name: Переключатель
|
||||
description: Может быть переключен, чтобы издавать логический сигнал (1 / 0) на слое с проводами,
|
||||
который может быть использован для управления Фильтром, например.
|
||||
logic_gate:
|
||||
default:
|
||||
name: AND Gate
|
||||
description: Emits a boolean "1" if both inputs are truthy. (Truthy means shape,
|
||||
color or boolean "1")
|
||||
description: Издает значение "1" если оба входа положительны. (Положительный - значит ресурс,
|
||||
цвет или логическое значение "1")
|
||||
not:
|
||||
name: NOT Gate
|
||||
description: Emits a boolean "1" if the input is not truthy. (Truthy means
|
||||
shape, color or boolean "1")
|
||||
description: Издает значение "1" если вход не положительный. (Положительный - значит ресурс,
|
||||
цвет или логическое значение "1")
|
||||
xor:
|
||||
name: XOR Gate
|
||||
description: Emits a boolean "1" if one of the inputs is truthy, but not both.
|
||||
(Truthy means shape, color or boolean "1")
|
||||
description: Издает значение "1" только один из входов положительный.
|
||||
(Положительный - значит ресурс,
|
||||
цвет или логическое значение "1")
|
||||
or:
|
||||
name: OR Gate
|
||||
description: Emits a boolean "1" if one of the inputs is truthy. (Truthy means
|
||||
shape, color or boolean "1")
|
||||
transistor:
|
||||
default:
|
||||
name: Transistor
|
||||
description: Forwards the bottom input if the side input is truthy (a shape,
|
||||
color or "1").
|
||||
mirrored:
|
||||
name: Transistor
|
||||
description: Forwards the bottom input if the side input is truthy (a shape,
|
||||
color or "1").
|
||||
description: Издает значение "1" если хотя бы один вход положительный. (Положительный - значит ресурс,
|
||||
цвет или логическое значение "1").
|
||||
transistor:
|
||||
default:
|
||||
name: Транзистор
|
||||
description: Пропускает нижний сигнал, если боковой сигнал положительный (ресурс,
|
||||
цвет или логическое значение "1").
|
||||
mirrored:
|
||||
name: Транзистор
|
||||
description: Пропускает нижний сигнал, если боковой сигнал положительный (ресурс,
|
||||
цвет или логическое значение "1").
|
||||
filter:
|
||||
default:
|
||||
name: Filter
|
||||
description: Connect a signal to route all matching items to the top and the
|
||||
remaining to the right. Can be controlled with boolean signals
|
||||
too.
|
||||
name: Фильтр
|
||||
description: Подключите сигнал, чтобы направить все подходящие ресурсы наверх,
|
||||
а остальные направо. Также контролируемо логическими
|
||||
сигналами.
|
||||
display:
|
||||
default:
|
||||
name: Display
|
||||
description: Connect a signal to show it on the display - It can be a shape,
|
||||
color or boolean.
|
||||
name: Экран
|
||||
description: Подключите сигнал, чтобы отобразить его на экране. Это может ресурс, цвет
|
||||
или логическое значение (1 / 0).
|
||||
reader:
|
||||
default:
|
||||
name: Belt Reader
|
||||
description: Allows to measure the average belt throughput. Outputs the last
|
||||
read item on the wires layer (once unlocked).
|
||||
name: Измеритель
|
||||
description: Позволяет измерять среднюю пропускную способность конвейера. Отображает последний
|
||||
прошедший ресурс на слое с проводами (когда разблокировано).
|
||||
analyzer:
|
||||
default:
|
||||
name: Shape Analyzer
|
||||
description: Analyzes the top right quadrant of the lowest layer of the shape
|
||||
and returns its shape and color.
|
||||
name: Анализатор Фигур
|
||||
description: Анализирует правую верхнюю часть низшего слоя фигуры
|
||||
и возвращает ее форму и цвет.
|
||||
comparator:
|
||||
default:
|
||||
name: Compare
|
||||
description: Returns boolean "1" if both signals are exactly equal. Can compare
|
||||
shapes, items and booleans.
|
||||
name: Сравнить
|
||||
description: Возвращает значение "1" если оба сигнала полностью одинаковы. Может сравнивать
|
||||
фигуры, цвета и логические значения.
|
||||
virtual_processor:
|
||||
default:
|
||||
name: Virtual Cutter
|
||||
description: Virtually cuts the shape into two halves.
|
||||
name: Виртуальный Резак
|
||||
description: Виртуально разрезает фигуру пополам.
|
||||
rotater:
|
||||
name: Virtual Rotater
|
||||
description: Virtually rotates the shape, both clockwise and counter-clockwise.
|
||||
name: Виртуальный Вращатель
|
||||
description: Виртуально вращает фигуру как по часовой стрелке, так и против часовой стрелки.
|
||||
unstacker:
|
||||
name: Virtual Unstacker
|
||||
description: Virtually extracts the topmost layer to the right output and the
|
||||
remaining ones to the left.
|
||||
name: Виртуальный Разъединитель
|
||||
description: Виртуально извлекает самый верхний слой фигуры направо,
|
||||
а все остальное направо.
|
||||
stacker:
|
||||
name: Virtual Stacker
|
||||
description: Virtually stacks the right shape onto the left.
|
||||
name: Виртуальный Объединитель
|
||||
description: Виртуально помещает правый предмет поверх левого.
|
||||
painter:
|
||||
name: Virtual Painter
|
||||
description: Virtually paints the shape from the bottom input with the shape on
|
||||
the right input.
|
||||
name: Виртуальный Покрасчик
|
||||
description: Виртуально окрашивает фигуру из нижнего входа цветом из
|
||||
правого входа.
|
||||
item_producer:
|
||||
default:
|
||||
name: Item Producer
|
||||
description: Available in sandbox mode only, outputs the given signal from the
|
||||
wires layer on the regular layer.
|
||||
name: Генератор Ресурсов
|
||||
description: Доступен только в режиме песочницы, производит заданный на
|
||||
слое с проводами сигнал на обычном слое.
|
||||
storyRewards:
|
||||
reward_cutter_and_trash:
|
||||
title: Разрезание Фигур
|
||||
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: Разблокирован <strong>резак</strong>, который разрезает фигуры пополам
|
||||
по вертикали <strong>независимо от ориентации</strong>!<br><br>Не забудьте избавляться от излишков,
|
||||
иначе <strong>он забьется и остановится</strong> - для этого
|
||||
я также открыл для Вас <strong>мусорку</strong>, которая уничтожает
|
||||
все, что в нее попадает!
|
||||
reward_rotater:
|
||||
title: Вращение
|
||||
desc: Разблокирован <strong>вращатель</strong>! Он поворачивает фигуры по
|
||||
@ -616,9 +612,9 @@ storyRewards:
|
||||
правого входа <strong>наложится</strong> на фигуру из левого!
|
||||
reward_splitter:
|
||||
title: Разделитель / Соединитель
|
||||
desc: You have unlocked a <strong>splitter</strong> variant of the
|
||||
<strong>balancer</strong> - It accepts one input and splits them
|
||||
into two!
|
||||
desc: Разблокирован <strong>разделитель</strong> один из вариантов
|
||||
<strong>балансера</strong> - он принимает один вход и разделяет его
|
||||
на два!
|
||||
reward_tunnel:
|
||||
title: Туннель
|
||||
desc: Разблокирован <strong>туннель</strong>! Теперь вы можете транспортировать
|
||||
@ -630,10 +626,9 @@ storyRewards:
|
||||
<strong>нажмите 'T', чтобы переключить вариант</strong>!
|
||||
reward_miner_chainable:
|
||||
title: Цепной Экстрактор
|
||||
desc: "You have unlocked the <strong>chained extractor</strong>! It can
|
||||
<strong>forward its resources</strong> to other extractors so you
|
||||
can more efficiently extract resources!<br><br> PS: The old
|
||||
extractor has been replaced in your toolbar now!"
|
||||
desc: "Разблокирован <strong>цепной экстрактор</strong>! Он может <strong>передавать
|
||||
свои ресурсы</strong> другим экстракторам, чтобы вы могли эффективнее извлекать ресурсы!<br><br>
|
||||
PS: Старый экстрактор был заменен в панели инструментов!"
|
||||
reward_underground_belt_tier_2:
|
||||
title: Туннель II
|
||||
desc: Разблокирован новый вариант <strong>туннеля</strong> с <strong>большей
|
||||
@ -649,18 +644,18 @@ storyRewards:
|
||||
одновременно</strong>, потребляя только один краситель вместо двух!
|
||||
reward_storage:
|
||||
title: Буферное Хранилище
|
||||
desc: You have unlocked the <strong>storage</strong> building - It allows you to
|
||||
store items up to a given capacity!<br><br> It priorities the left
|
||||
output, so you can also use it as an <strong>overflow gate</strong>!
|
||||
desc: Разблокировано <strong>буферное хранилище</strong> - оно позволяет
|
||||
хранить в нем ресурсы пока есть место! <br><br> Левый выход в
|
||||
приоритете, может быть использован как <strong>буфер</strong>!
|
||||
reward_freeplay:
|
||||
title: Свободная игра
|
||||
desc: You did it! You unlocked the <strong>free-play mode</strong>! This means
|
||||
that shapes are now <strong>randomly</strong> generated!<br><br>
|
||||
Since the hub will require a <strong>throughput</strong> from now
|
||||
on, I highly recommend to build a machine which automatically
|
||||
delivers the requested shape!<br><br> The HUB outputs the requested
|
||||
shape on the wires layer, so all you have to do is to analyze it and
|
||||
automatically configure your factory based on that.
|
||||
desc: У Вас получилось! Разблокирован <strong>свободный режим</strong>! Это означает
|
||||
что теперь фигуры будут генерироваться <strong>случайно</strong>!<br><br>
|
||||
Так как ХАБ отныне будет требовать определенную <strong>пропускную способность</strong>,
|
||||
я настоятельно рекомендую построить механизм, автоматически
|
||||
доставляющий запрашиваемую фигуру!<br><br> ХАБ выводит запрашиваемую
|
||||
фигуру на слое с проводами, так что все, что необходимо сделать, - это
|
||||
проанализировать ее и автоматически настроить вашу фабрику.
|
||||
reward_blueprints:
|
||||
title: Чертежи
|
||||
desc: Теперь вы можете <strong>копировать и вставлять</strong> части вашей
|
||||
@ -678,70 +673,69 @@ storyRewards:
|
||||
title: Следующий уровень
|
||||
desc: Поздравляем! Кстати, больше контента планируется для полной версии!
|
||||
reward_balancer:
|
||||
title: Balancer
|
||||
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!<br><br>
|
||||
title: Балансер
|
||||
desc: Многофункциональный <strong>балансер</strong> разблокирован - он может
|
||||
быть использован для строительства огромных фабрик, <strong>разделяя и объединяя ресурсы</strong>
|
||||
на множество конвейеров!<br><br>
|
||||
reward_merger:
|
||||
title: Compact Merger
|
||||
desc: You have unlocked a <strong>merger</strong> variant of the
|
||||
<strong>balancer</strong> - It accepts two inputs and merges them
|
||||
into one belt!
|
||||
title: Компактный Соединитель
|
||||
desc: Разблокирован <strong>соединитель</strong> - вариант
|
||||
<strong>балансера</strong> - он принимает два входа и объединяет их
|
||||
в один конвейер.
|
||||
reward_belt_reader:
|
||||
title: Belt reader
|
||||
desc: You have now unlocked the <strong>belt reader</strong>! It allows you to
|
||||
measure the throughput of a belt.<br><br>And wait until you unlock
|
||||
wires - then it gets really useful!
|
||||
title: Измеритель
|
||||
desc: Разблокирован <strong>измеритель</strong>! Он позволяет
|
||||
измерять пропускную способность конвейера.<br><br>А как полезен он будет,
|
||||
когда вы разблокируете провода!
|
||||
reward_rotater_180:
|
||||
title: Rotater (180 degrees)
|
||||
desc: You just unlocked the 180 degress <strong>rotater</strong>! - It allows
|
||||
you to rotate a shape by 180 degress (Surprise! :D)
|
||||
title: Вращатель (180 градусов)
|
||||
desc: Разблокирован <strong>rotater</strong> на 180 градусов! - Он позволяет
|
||||
вращать фигур на 180 градусов (Сюрприз! :D)
|
||||
reward_display:
|
||||
title: Display
|
||||
desc: "You have unlocked the <strong>Display</strong> - Connect a signal on the
|
||||
wires layer to visualize it!<br><br> PS: Did you notice the belt
|
||||
reader and storage output their last read item? Try showing it on a
|
||||
display!"
|
||||
title: Экран
|
||||
desc: "Разблокирован <strong>Экран</strong> - Подключите сигнал на слое
|
||||
с проводами чтобы отобразить его!<br><br> PS: Заметили ли вы, что измеритель
|
||||
и буферное хранилище отображают последний ресурс, прошедший через них? Попробуйте
|
||||
отобразить его на экране!"
|
||||
reward_constant_signal:
|
||||
title: Constant Signal
|
||||
desc: You unlocked the <strong>constant signal</strong> building on the wires
|
||||
layer! This is useful to connect it to <strong>item filters</strong>
|
||||
for example.<br><br> The constant signal can emit a
|
||||
<strong>shape</strong>, <strong>color</strong> or
|
||||
<strong>boolean</strong> (1 / 0).
|
||||
title: Постоянный Сигнал
|
||||
desc: Разблокирован <strong>постоянный сигнал</strong> на слое с проводами!
|
||||
Он полезен для подключения к <strong>фильтрам</strong>,
|
||||
например.<br><br> Постоянный сигнал может издавать <strong>фигуру</strong>, <strong>цвет</strong> или
|
||||
<strong>логическое значение</strong> (1 / 0).
|
||||
reward_logic_gates:
|
||||
title: Logic Gates
|
||||
desc: You unlocked <strong>logic gates</strong>! You don't have to be excited
|
||||
about this, but it's actually super cool!<br><br> With those gates
|
||||
you can now compute AND, OR, XOR and NOT operations.<br><br> As a
|
||||
bonus on top I also just gave you a <strong>transistor</strong>!
|
||||
title: Логические Элементы
|
||||
desc: Разблокированы <strong>логические элементы</strong>! Вы не обязаны радоваться
|
||||
по этому поводу, но вообще это очень круто!<br><br> С этими элементами
|
||||
теперь вы можете производить И, ИЛИ, исключающее ИЛИ и НЕ операции.<br><br>
|
||||
Как бонус, я также дал вам <strong>транзистор</strong>!
|
||||
reward_virtual_processing:
|
||||
title: Virtual Processing
|
||||
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, rotater, 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
|
||||
regulary.<br><br> Whatever you choose, remember to have fun!
|
||||
title: Виртуальное Производство
|
||||
desc: Только что я открыл вам множество новых построек, которые позволят
|
||||
<strong>симулировать производство фигур</strong>!<br><br> Теперь вы
|
||||
можете симулировать резак, вращатель, объединитель и др. на слое с проводами!
|
||||
Теперь у вас есть три варианта продолжения игры:<br><br> - Построить
|
||||
<strong>автоматический механизм</strong> для производства любой
|
||||
фигуры, запрашиваемой ХАБ (рекомендую попробовать!).<br><br> - Построить
|
||||
что-то клевое, используя провода.<br><br> - Продолжить обычную
|
||||
игру. <br><br> Что бы вы не выбрали, не забывайте хорошо проводить время!
|
||||
reward_wires_painter_and_levers:
|
||||
title: Wires & Quad Painter
|
||||
desc: "You just unlocked the <strong>Wires Layer</strong>: It is a separate
|
||||
layer on top of the regular layer and introduces a lot of new
|
||||
mechanics!<br><br> For the beginning I unlocked you the <strong>Quad
|
||||
Painter</strong> - Connect the slots you would like to paint with on
|
||||
the wires layer!<br><br> To switch to the wires layer, press
|
||||
title: Провода & Покрасчик (4 входа)
|
||||
desc: "Разблокирован <strong>Слой с Проводами</strong>. Это отдельный
|
||||
слой поверх обычного слоя, добавляющий множество новых
|
||||
механик!<br><br> Для начала я разблокировал <strong>Покрасчик
|
||||
на четыре входа</strong> - соедините ячейки, которые вы бы хотели окрасить на
|
||||
слое с проводами!<br><br> Чтобы переключиться на слой слой с проводами, нажмите
|
||||
<strong>E</strong>."
|
||||
reward_filter:
|
||||
title: Item Filter
|
||||
desc: You unlocked the <strong>Item Filter</strong>! It will route items either
|
||||
to the top or the right output depending on whether they match the
|
||||
signal from the wires layer or not.<br><br> You can also pass in a
|
||||
boolean signal (1 / 0) to entirely activate or disable it.
|
||||
title: Фильтр
|
||||
desc: Разблокирован <strong>Фильтр</strong>! Он направит ресурсы
|
||||
наверх или направо в зависмости от того, совпадают ли они с
|
||||
установленным сигналом. <br><br> Вы также можете передавать
|
||||
логические значения (1 / 0), чтобы полностью отключить или включить его.
|
||||
reward_demo_end:
|
||||
title: End of Demo
|
||||
desc: You have reached the end of the demo version!
|
||||
title: Конец Демо
|
||||
desc: Вы достигли конца демоверсии игры!
|
||||
settings:
|
||||
title: Настройки
|
||||
categories:
|
||||
@ -835,9 +829,9 @@ settings:
|
||||
description: Включает виньетирование, которое затемняет углы экрана и облегчает
|
||||
чтение текста.
|
||||
autosaveInterval:
|
||||
title: Интервал авто-сохранения
|
||||
title: Интервал автосохранения
|
||||
description: Управляет тем, как часто игра автоматически сохраняется. Также
|
||||
здесь можно полностью отключить авто-сохранение.
|
||||
здесь можно полностью отключить автосохранение.
|
||||
intervals:
|
||||
one_minute: 1 Минута
|
||||
two_minutes: 2 Минуты
|
||||
@ -864,47 +858,46 @@ settings:
|
||||
установлен. С этой настройкой может быть удобнее, при частом
|
||||
переключении между различными типами зданий.
|
||||
soundVolume:
|
||||
title: Sound Volume
|
||||
description: Set the volume for sound effects
|
||||
title: Громкость Звука
|
||||
description: Задает громкость звуковых эффектов.
|
||||
musicVolume:
|
||||
title: Music Volume
|
||||
description: Set the volume for music
|
||||
description: Задает громкость музыки.
|
||||
lowQualityMapResources:
|
||||
title: Low Quality Map Resources
|
||||
description: Simplifies the rendering of resources on the map when zoomed in to
|
||||
improve performance. It even looks cleaner, so be sure to try it
|
||||
out!
|
||||
title: Низкое качество ресурсов на карте
|
||||
description: Упрощает отображение ресурсов на карте при приближении для
|
||||
улучшения производительности. Оно даже выглядит аккуратнее, поэтому обязательно
|
||||
попробуйте!
|
||||
disableTileGrid:
|
||||
title: Disable Grid
|
||||
description: Disabling the tile grid can help with the performance. This also
|
||||
makes the game look cleaner!
|
||||
title: Отключить Сетку
|
||||
description: Отключение разделительной сетки может помочь улучшить производительность. Кроме того,
|
||||
делает игру визуально проще!
|
||||
clearCursorOnDeleteWhilePlacing:
|
||||
title: Clear Cursor on Right Click
|
||||
description: Enabled by default, clears the cursor whenever you right click
|
||||
while you have a building selected for placement. If disabled,
|
||||
you can delete buildings by right-clicking while placing a
|
||||
building.
|
||||
title: Очистить Курсор на ПКМ
|
||||
description: Включено по умолчанию, очищает курсор от выбранной постройки
|
||||
при нажатии на ПКМ. Если отключено, вы можете удалять постройки
|
||||
при нажатии на ПКМ во время строительства.
|
||||
lowQualityTextures:
|
||||
title: Low quality textures (Ugly)
|
||||
description: Uses low quality textures to save performance. This will make the
|
||||
game look very ugly!
|
||||
title: Низкое качество текстур (Некрасиво)
|
||||
description: Использует низкое качество текстур, чтобы улучшить производительность. Это сделает
|
||||
игру очень некрасивой!
|
||||
displayChunkBorders:
|
||||
title: Display Chunk Borders
|
||||
description: The game is divided into chunks of 16x16 tiles, if this setting is
|
||||
enabled the borders of each chunk are displayed.
|
||||
title: Отображать границы чанков
|
||||
description: Эта игра разделена на чанки, состоящие из 16x16 ячеек, если эта настройка
|
||||
включена, границы чанков будут отображаться.
|
||||
pickMinerOnPatch:
|
||||
title: Pick miner on resource patch
|
||||
description: Enabled by default, selects the miner if you use the pipette when
|
||||
hovering a resource patch.
|
||||
title: Выбрать Экстрактор над Жилой
|
||||
description: Включено по умолчанию, выбирает экстрактор, если использовать пипетку
|
||||
над жилой с ресурсами.
|
||||
simplifiedBelts:
|
||||
title: Simplified Belts (Ugly)
|
||||
description: Does not render belt items except when hovering the belt to save
|
||||
performance. I do not recommend to play with this setting if you
|
||||
do not absolutely need the performance.
|
||||
title: Упрощенные Конвейеры (Некрасиво)
|
||||
description: Не отображает ресурсы, находящиеся на конвейере, если не навести курсор для улучшения
|
||||
производительности. Не рекомендую играть с этой настройкой, если вас
|
||||
устраивает производительность.
|
||||
enableMousePan:
|
||||
title: Enable Mouse Pan
|
||||
description: Allows to move the map by moving the cursor to the edges of the
|
||||
screen. The speed depends on the Movement Speed setting.
|
||||
title: Включить Перемещение Мышкой
|
||||
description: Позволяет двигать карту, перемещая курсор к краям
|
||||
экрана. Скорость зависит от настройки Скорости движения.
|
||||
rangeSliderPercentage: <amount> %
|
||||
keybindings:
|
||||
title: Настройки управления
|
||||
@ -951,9 +944,9 @@ keybindings:
|
||||
massSelectStart: Модификатор для выделения области
|
||||
massSelectSelectMultiple: Выбрать несколько областей
|
||||
massSelectCopy: Копировать область
|
||||
placementDisableAutoOrientation: Отключить авто-определение направления
|
||||
placementDisableAutoOrientation: Отключить автоопределение направления
|
||||
placeMultiple: Оставаться в режиме размещения
|
||||
placeInverse: Инвертировать авто-определение направления конвейеров
|
||||
placeInverse: Инвертировать автоопределение направления конвейеров
|
||||
pasteLastBlueprint: Вставить последний чертеж
|
||||
massSelectCut: Вырезать область
|
||||
exportScreenshot: Экспорт всей Базы в виде Изображения
|
||||
@ -964,21 +957,21 @@ keybindings:
|
||||
menuClose: Закрыть меню
|
||||
switchLayers: Переключить слои
|
||||
wire: Энергетический провод
|
||||
balancer: Balancer
|
||||
storage: Storage
|
||||
constant_signal: Constant Signal
|
||||
logic_gate: Logic Gate
|
||||
lever: Switch (regular)
|
||||
filter: Filter
|
||||
wire_tunnel: Wire Crossing
|
||||
display: Display
|
||||
reader: Belt Reader
|
||||
virtual_processor: Virtual Cutter
|
||||
transistor: Transistor
|
||||
analyzer: Shape Analyzer
|
||||
comparator: Compare
|
||||
item_producer: Item Producer (Sandbox)
|
||||
copyWireValue: "Wires: Copy value below cursor"
|
||||
balancer: Балансер
|
||||
storage: Буферное Хранилище
|
||||
constant_signal: Постоянный Сигнал
|
||||
logic_gate: Логический Элемент
|
||||
lever: Переключатель (обычный)
|
||||
filter: Фильтр
|
||||
wire_tunnel: Пересечение Проводов
|
||||
display: Экран
|
||||
reader: Измеритель
|
||||
virtual_processor: Виртуальный Резак
|
||||
transistor: Транзистор
|
||||
analyzer: Анализатор Фигур
|
||||
comparator: Сравнить
|
||||
item_producer: Генератор Ресурсов (Песочница)
|
||||
copyWireValue: "Провода: скопировать значение под курсором"
|
||||
about:
|
||||
title: Об игре
|
||||
body: >-
|
||||
@ -988,7 +981,8 @@ about:
|
||||
|
||||
Если вы хотите внести свой вклад игре - <a href="<githublink>" target="_blank">shapez.io в github</a>.<br><br>
|
||||
|
||||
Эта игра не была бы возможна без большого сообщества в дискорде, которое собралось вокруг моих игр - Вам действительно стоит присоединиться к <a href="<discordlink>" target="_blank">серверу Discord!</a>!<br><br>
|
||||
Эта игра не была бы возможна без большого сообщества в дискорде, которое собралось вокруг моих игр - Вам действительно стоит присоединиться к
|
||||
<a href="<discordlink>" target="_blank">серверу Discord!</a>!<br><br>
|
||||
|
||||
Саундтрек сделал <a href="https://soundcloud.com/pettersumelius" target="_blank">Peppsen</a> - Он потрясающий.<br><br>
|
||||
|
||||
@ -1002,65 +996,57 @@ demo:
|
||||
oneGameLimit: Ограниченность одним сохранением игры
|
||||
customizeKeybindings: Пользовательская настройка Управления
|
||||
exportingBase: Экспорт всей Базы в виде Изображения
|
||||
settingNotAvailable: Не доступно в демо-версии.
|
||||
settingNotAvailable: Недоступно в демоверсии.
|
||||
tips:
|
||||
- The hub accepts input of any kind, not just the current shape!
|
||||
- Make sure your factories are modular - it will pay out!
|
||||
- Don't build too close to the hub, or it will be a huge chaos!
|
||||
- If stacking does not work, try switching the inputs.
|
||||
- You can toggle the belt planner direction by pressing <b>R</b>.
|
||||
- Holding <b>CTRL</b> allows dragging of belts without auto-orientation.
|
||||
- Ratios stay the same, as long as all upgrades are on the same Tier.
|
||||
- Serial execution is more efficient than parallel.
|
||||
- You will unlock more variants of buildings later in the game!
|
||||
- You can use <b>T</b> to switch between different variants.
|
||||
- Symmetry is key!
|
||||
- You can weave different tiers of tunnels.
|
||||
- Try to build compact factories - it will pay out!
|
||||
- The painter has a mirrored variant which you can select with <b>T</b>
|
||||
- Having the right building ratios will maximize efficiency.
|
||||
- At maximum level, 5 extractors will fill a single belt.
|
||||
- Don't forget about tunnels!
|
||||
- You don't need to divide up items evenly for full efficiency.
|
||||
- Holding <b>SHIFT</b> will activate the belt planner, letting you place
|
||||
long lines of belts easily.
|
||||
- Cutters always cut vertically, regardless of their orientation.
|
||||
- To get white mix all three colors.
|
||||
- The storage buffer priorities the first output.
|
||||
- Invest time to build repeatable designs - it's worth it!
|
||||
- Holding <b>CTRL</b> allows to place multiple buildings.
|
||||
- You can hold <b>ALT</b> to invert the direction of placed belts.
|
||||
- Efficiency is key!
|
||||
- Shape patches that are further away from the hub are more complex.
|
||||
- Machines have a limited speed, divide them up for maximum efficiency.
|
||||
- Use balancers to maximize your efficiency.
|
||||
- Organization is important. Try not to cross conveyors too much.
|
||||
- Plan in advance, or it will be a huge chaos!
|
||||
- Don't remove your old factories! You'll need them to unlock upgrades.
|
||||
- Try beating level 20 on your own before seeking for help!
|
||||
- Don't complicate things, try to stay simple and you'll go far.
|
||||
- You may need to re-use factories later in the game. Plan your factories to
|
||||
be re-usable.
|
||||
- Sometimes, you can find a needed shape in the map without creating it with
|
||||
stackers.
|
||||
- Full windmills / pinwheels can never spawn naturally.
|
||||
- Color your shapes before cutting for maximum efficiency.
|
||||
- With modules, space is merely a perception; a concern for mortal men.
|
||||
- Make a separate blueprint factory. They're important for modules.
|
||||
- Have a closer look on the color mixer, and your questions will be answered.
|
||||
- Use <b>CTRL</b> + Click to select an area.
|
||||
- Building too close to the hub can get in the way of later projects.
|
||||
- The pin icon next to each shape in the upgrade list pins it to the screen.
|
||||
- Mix all primary colors together to make white!
|
||||
- You have an infinite map, don't cramp your factory, expand!
|
||||
- Also try Factorio! It's my favorite game.
|
||||
- The quad cutter cuts clockwise starting from the top right!
|
||||
- You can download your savegames in the main menu!
|
||||
- This game has a lot of useful keybindings! Be sure to check out the
|
||||
settings page.
|
||||
- This game has a lot of settings, be sure to check them out!
|
||||
- The marker to your hub has a small compass to indicate its direction!
|
||||
- To clear belts, cut the area and then paste it at the same location.
|
||||
- Press F4 to show your FPS and Tick Rate.
|
||||
- Press F4 twice to show the tile of your mouse and camera.
|
||||
- You can click a pinned shape on the left side to unpin it.
|
||||
- ХАБ принимает любые ресурсы, не только текущую фигуру!
|
||||
- Старайтесь создавать модульные фабрики - вы не пожалеете!
|
||||
- Не стройте слишком близко к ХАБ-у, иначе начнется ужасный хаос!
|
||||
- Если не получается объединить фигуры, попробуйте поменять входы местами!
|
||||
- Вы можете изменить направление конвейера при строительстве, нажав <b>R</b>.
|
||||
- Удерживая <b>CTRL</b>, вы можете перемещать конвейеры без авто ориентации.
|
||||
- Соотношения всегда одинаковы, если уровни улучшений равны.
|
||||
- Последовательное выполнение эффективнее, чем параллельное.
|
||||
- Вам будут открываться новые варианты построек по мере прохождения!
|
||||
- Нажмите <b>T</b>, чтобы переключаться между различными вариантами.
|
||||
- Симметрия - ключ к успеху!
|
||||
- Вы можете переплетать между собой туннели разных уровней.
|
||||
- Попробуйте строить компактные фабрики - вы не пожалеете!
|
||||
- Покрасчик имеет зеркальный вариант, который может быть выбран, нажав <b>T</b>.
|
||||
- Правильные соотношения построек позволяет улучшить эффективность фабрики.
|
||||
- Удерживая <b>SHIFT</b>, вы можете легко строить длинные конвейерные линии.
|
||||
- Резаки всегда разрезают пополам по вертикали вне зависимости от ориентации.
|
||||
- Чтобы получить белый цвет, смешайте все три цвета.
|
||||
- Левый выход Буферного Хранилища - в приоритете.
|
||||
- Вкладывайте время в строительство повторяемых механизмов - оно того стоит!
|
||||
- Удерживая <b>CTRL</b>, можно размещать много построек за раз.
|
||||
- Вы можете удерживать <b>ALT</b>, чтобы инвертировать направление размещенных конвейеров.
|
||||
- Эффективность - ключ к успеху!
|
||||
- Чем дальше от ХАБ-а, тем Жилы с ресурсами сложнее.
|
||||
- Механизмы имеют ограниченную скорость, разбивайте их для максимальной эффективности.
|
||||
- Используйте балансеры, чтобы максимизировать эффективность.
|
||||
- Организация очень важна, старайтесь не пересекать конвейеры слишком часто.
|
||||
- Планируйте заранее, иначе начнется ужасный хаос!
|
||||
- Не удаляйте свои старые фабрики! Они понадобятся вам, чтобы открывать улучшения.
|
||||
- Попробуйте пройти 20-ый уровень самостоятельно, прежде чем искать помощи!
|
||||
- Не усложняйте себе жизнь, старайтесь думать проще и вы достигните больших высот.
|
||||
- Вам может снова понадобиться ваша старая фабрика позже в игре. Старайтесь планировать фабрику, чтобы она могла быть повторно использована.
|
||||
- Иногда, вы можете найти необходимую фигуру на карте, вместо того, чтобы создавать ее самостоятельно.
|
||||
- Полноценные мельницы/вертушки никогда не генерируются натурально.
|
||||
- Окрашивайте свои фигуры, прежде чем разрезать для максимальной эффективности.
|
||||
- С модулями теряется восприятие пространства; забота смертных.
|
||||
- Создайте отдельную фабрику чертежей. Они очень важны для модулей.
|
||||
- Взгляните внимательнее на смешиватель и вы найдете ответы на свои вопросы.
|
||||
- Чтобы выделить область, используйте <b>CTRL</b> + Клик.
|
||||
- Строительство вблизи ХАБ-а может помешать будущим проектам.
|
||||
- Иконка булавки на каждой фигуре закрепляет ее на экране.
|
||||
- Смешайте все три основных цвета, чтобы получить белый!
|
||||
- В вашем распоряжении бесконечная карта! Не загромождайте вашу фабрику, расширяйтесь!
|
||||
- Также попробуйте Factorio. Это моя любимая игра.
|
||||
- Резак(4 входа) разрезает по часовой стрелке, начиная с правой верхней части!
|
||||
- Вы можете скачать свои сохранения в главном меню!
|
||||
- В этой игре множество полезных комбинаций клавиш. Загляните в настройки, чтобы ознакомиться с ними.
|
||||
- В этой игре множество настроек, не забудьте с ними ознакомиться.
|
||||
- Маркер ХАБ-а имеет небольшой компас, указывающий его направление.
|
||||
- Нажмите F4, чтобы показать FPS и Частоту Обновления.
|
||||
- Нажмите F4 дважды, чтобы показать координаты курсора и камеры.
|
||||
- Вы можете нажать на закрепленную фигуру слева, чтобы открепить ее.
|
||||
|
||||
@ -5,7 +5,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
automated production of geometric shapes.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ steamPage:
|
||||
discordLinkShort: Official Discord
|
||||
intro: >-
|
||||
Shapez.io is a relaxed game in which you have to build factories for the
|
||||
automated production of geometric shapes.
|
||||
automated production of geometric shapes.
|
||||
|
||||
As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
|
||||
|
||||