mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
9a2044dbd1
@ -14,13 +14,9 @@ import { AdProviderInterface } from "./platform/ad_provider";
|
|||||||
import { NoAdProvider } from "./platform/ad_providers/no_ad_provider";
|
import { NoAdProvider } from "./platform/ad_providers/no_ad_provider";
|
||||||
import { AnalyticsInterface } from "./platform/analytics";
|
import { AnalyticsInterface } from "./platform/analytics";
|
||||||
import { GoogleAnalyticsImpl } from "./platform/browser/google_analytics";
|
import { GoogleAnalyticsImpl } from "./platform/browser/google_analytics";
|
||||||
import { NoGameAnalytics } from "./platform/browser/no_game_analytics";
|
|
||||||
import { SoundImplBrowser } from "./platform/browser/sound";
|
import { SoundImplBrowser } from "./platform/browser/sound";
|
||||||
import { PlatformWrapperImplBrowser } from "./platform/browser/wrapper";
|
import { PlatformWrapperImplBrowser } from "./platform/browser/wrapper";
|
||||||
import { PlatformWrapperImplElectron } from "./platform/electron/wrapper";
|
import { PlatformWrapperImplElectron } from "./platform/electron/wrapper";
|
||||||
import { GameAnalyticsInterface } from "./platform/game_analytics";
|
|
||||||
import { SoundInterface } from "./platform/sound";
|
|
||||||
import { StorageInterface } from "./platform/storage";
|
|
||||||
import { PlatformWrapperInterface } from "./platform/wrapper";
|
import { PlatformWrapperInterface } from "./platform/wrapper";
|
||||||
import { ApplicationSettings } from "./profile/application_settings";
|
import { ApplicationSettings } from "./profile/application_settings";
|
||||||
import { SavegameManager } from "./savegame/savegame_manager";
|
import { SavegameManager } from "./savegame/savegame_manager";
|
||||||
@ -34,6 +30,12 @@ import { PreloadState } from "./states/preload";
|
|||||||
import { SettingsState } from "./states/settings";
|
import { SettingsState } from "./states/settings";
|
||||||
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
|
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("./platform/game_analytics").GameAnalyticsInterface} GameAnalyticsInterface
|
||||||
|
* @typedef {import("./platform/sound").SoundInterface} SoundInterface
|
||||||
|
* @typedef {import("./platform/storage").StorageInterface} StorageInterface
|
||||||
|
*/
|
||||||
|
|
||||||
const logger = createLogger("application");
|
const logger = createLogger("application");
|
||||||
|
|
||||||
// Set the name of the hidden property and the change event for visibility
|
// Set the name of the hidden property and the change event for visibility
|
||||||
|
@ -1,20 +1,38 @@
|
|||||||
/**
|
/**
|
||||||
|
* @typedef {{ w: number, h: number }} Size
|
||||||
|
* @typedef {{ x: number, y: number }} Position
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* frame: { x: number, y: number, w: number, h: number },
|
* frame: Position & Size,
|
||||||
* rotated: false,
|
* rotated: boolean,
|
||||||
* spriteSourceSize: { x: number, y: number, w: number, h: number },
|
* spriteSourceSize: Position & Size,
|
||||||
* sourceSize: { w: number, h: number},
|
* sourceSize: Size,
|
||||||
* trimmed: true
|
* trimmed: boolean
|
||||||
* }} SpriteDefinition
|
* }} SpriteDefinition
|
||||||
|
*
|
||||||
|
* @typedef {{
|
||||||
|
* app: string,
|
||||||
|
* version: string,
|
||||||
|
* image: string,
|
||||||
|
* format: string,
|
||||||
|
* size: Size,
|
||||||
|
* scale: string,
|
||||||
|
* smartupdate: string
|
||||||
|
* }} AtlasMeta
|
||||||
|
*
|
||||||
|
* @typedef {{
|
||||||
|
* frames: Object.<string, SpriteDefinition>,
|
||||||
|
* meta: AtlasMeta
|
||||||
|
* }} SourceData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export class AtlasDefinition {
|
export class AtlasDefinition {
|
||||||
constructor(sourceData) {
|
/**
|
||||||
this.sourceFileName = sourceData.meta.image;
|
* @param {SourceData} sourceData
|
||||||
this.meta = sourceData.meta;
|
*/
|
||||||
|
constructor({ frames, meta }) {
|
||||||
/** @type {Object.<string, SpriteDefinition>} */
|
this.meta = meta;
|
||||||
this.sourceData = sourceData.frames;
|
this.sourceData = frames;
|
||||||
|
this.sourceFileName = meta.image;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFullSourcePath() {
|
getFullSourcePath() {
|
||||||
@ -22,6 +40,7 @@ export class AtlasDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {AtlasDefinition[]} **/
|
||||||
export const atlasFiles = require
|
export const atlasFiles = require
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
.context("../../../res_built/atlas/", false, /.*\.json/i)
|
.context("../../../res_built/atlas/", false, /.*\.json/i)
|
||||||
|
@ -115,7 +115,6 @@ export class BackgroundResourcesLoader {
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.log("⏰ Finish load: bare game");
|
logger.log("⏰ Finish load: bare game");
|
||||||
Loader.createAtlasLinks();
|
|
||||||
this.bareGameReady = true;
|
this.bareGameReady = true;
|
||||||
initBuildingCodesAfterResourcesLoaded();
|
initBuildingCodesAfterResourcesLoaded();
|
||||||
this.signalBareGameLoaded.dispatch();
|
this.signalBareGameLoaded.dispatch();
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Rectangle } from "./rectangle";
|
|
||||||
import { globalConfig } from "./config";
|
import { globalConfig } from "./config";
|
||||||
|
|
||||||
/* typehints:start */
|
/**
|
||||||
import { GameRoot } from "../game/root";
|
* @typedef {import("../game/root").GameRoot} GameRoot
|
||||||
/* typehints:end */
|
* @typedef {import("./rectangle").Rectangle} Rectangle
|
||||||
|
*/
|
||||||
|
|
||||||
export class DrawParameters {
|
export class DrawParameters {
|
||||||
constructor({ context, visibleRect, desiredAtlasScale, zoomLevel, root }) {
|
constructor({ context, visibleRect, desiredAtlasScale, zoomLevel, root }) {
|
||||||
|
@ -1,18 +1,13 @@
|
|||||||
/* typehints:start */
|
/**
|
||||||
import { AtlasSprite } from "./sprites";
|
* @typedef {import("./sprites").AtlasSprite} AtlasSprite
|
||||||
import { DrawParameters } from "./draw_parameters";
|
* @typedef {import("./draw_parameters").DrawParameters} DrawParameters
|
||||||
/* typehints:end */
|
*/
|
||||||
|
|
||||||
import { Vector } from "./vector";
|
|
||||||
import { Rectangle } from "./rectangle";
|
|
||||||
import { createLogger } from "./logging";
|
|
||||||
|
|
||||||
const logger = createLogger("draw_utils");
|
|
||||||
|
|
||||||
export function initDrawUtils() {
|
export function initDrawUtils() {
|
||||||
CanvasRenderingContext2D.prototype.beginRoundedRect = function (x, y, w, h, r) {
|
CanvasRenderingContext2D.prototype.beginRoundedRect = function (x, y, w, h, r) {
|
||||||
if (r < 0.05) {
|
|
||||||
this.beginPath();
|
this.beginPath();
|
||||||
|
|
||||||
|
if (r < 0.05) {
|
||||||
this.rect(x, y, w, h);
|
this.rect(x, y, w, h);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -20,25 +15,26 @@ export function initDrawUtils() {
|
|||||||
if (w < 2 * r) {
|
if (w < 2 * r) {
|
||||||
r = w / 2;
|
r = w / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h < 2 * r) {
|
if (h < 2 * r) {
|
||||||
r = h / 2;
|
r = h / 2;
|
||||||
}
|
}
|
||||||
this.beginPath();
|
|
||||||
this.moveTo(x + r, y);
|
this.moveTo(x + r, y);
|
||||||
this.arcTo(x + w, y, x + w, y + h, r);
|
this.arcTo(x + w, y, x + w, y + h, r);
|
||||||
this.arcTo(x + w, y + h, x, y + h, r);
|
this.arcTo(x + w, y + h, x, y + h, r);
|
||||||
this.arcTo(x, y + h, x, y, r);
|
this.arcTo(x, y + h, x, y, r);
|
||||||
this.arcTo(x, y, x + w, y, r);
|
this.arcTo(x, y, x + w, y, r);
|
||||||
// this.closePath();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CanvasRenderingContext2D.prototype.beginCircle = function (x, y, r) {
|
CanvasRenderingContext2D.prototype.beginCircle = function (x, y, r) {
|
||||||
if (r < 0.05) {
|
|
||||||
this.beginPath();
|
this.beginPath();
|
||||||
|
|
||||||
|
if (r < 0.05) {
|
||||||
this.rect(x, y, 1, 1);
|
this.rect(x, y, 1, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.beginPath();
|
|
||||||
this.arc(x, y, r, 0, 2.0 * Math.PI);
|
this.arc(x, y, r, 0, 2.0 * Math.PI);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -62,259 +58,3 @@ export function drawRotatedSprite({ parameters, sprite, x, y, angle, size, offse
|
|||||||
parameters.context.rotate(-angle);
|
parameters.context.rotate(-angle);
|
||||||
parameters.context.translate(-x, -y);
|
parameters.context.translate(-x, -y);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawLineFast(context, { x1, x2, y1, y2, color = null, lineSize = 1 }) {
|
|
||||||
const dX = x2 - x1;
|
|
||||||
const dY = y2 - y1;
|
|
||||||
|
|
||||||
const angle = Math.atan2(dY, dX) + 0.0 * Math.PI;
|
|
||||||
const len = Math.hypot(dX, dY);
|
|
||||||
|
|
||||||
context.translate(x1, y1);
|
|
||||||
context.rotate(angle);
|
|
||||||
|
|
||||||
if (color) {
|
|
||||||
context.fillStyle = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.fillRect(0, -lineSize / 2, len, lineSize);
|
|
||||||
|
|
||||||
context.rotate(-angle);
|
|
||||||
context.translate(-x1, -y1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const INSIDE = 0;
|
|
||||||
const LEFT = 1;
|
|
||||||
const RIGHT = 2;
|
|
||||||
const BOTTOM = 4;
|
|
||||||
const TOP = 8;
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
|
|
||||||
|
|
||||||
function computeOutCode(x, y, xmin, xmax, ymin, ymax) {
|
|
||||||
let code = INSIDE;
|
|
||||||
|
|
||||||
if (x < xmin)
|
|
||||||
// to the left of clip window
|
|
||||||
code |= LEFT;
|
|
||||||
else if (x > xmax)
|
|
||||||
// to the right of clip window
|
|
||||||
code |= RIGHT;
|
|
||||||
if (y < ymin)
|
|
||||||
// below the clip window
|
|
||||||
code |= BOTTOM;
|
|
||||||
else if (y > ymax)
|
|
||||||
// above the clip window
|
|
||||||
code |= TOP;
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cohen–Sutherland clipping algorithm clips a line from
|
|
||||||
// P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
|
|
||||||
// diagonal from (xmin, ymin) to (xmax, ymax).
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {CanvasRenderingContext2D} context
|
|
||||||
*/
|
|
||||||
export function drawLineFastClipped(context, rect, { x0, y0, x1, y1, color = null, lineSize = 1 }) {
|
|
||||||
const xmin = rect.x;
|
|
||||||
const ymin = rect.y;
|
|
||||||
const xmax = rect.right();
|
|
||||||
const ymax = rect.bottom();
|
|
||||||
|
|
||||||
// compute outcodes for P0, P1, and whatever point lies outside the clip rectangle
|
|
||||||
let outcode0 = computeOutCode(x0, y0, xmin, xmax, ymin, ymax);
|
|
||||||
let outcode1 = computeOutCode(x1, y1, xmin, xmax, ymin, ymax);
|
|
||||||
let accept = false;
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
|
||||||
while (true) {
|
|
||||||
if (!(outcode0 | outcode1)) {
|
|
||||||
// bitwise OR is 0: both points inside window; trivially accept and exit loop
|
|
||||||
accept = true;
|
|
||||||
break;
|
|
||||||
} else if (outcode0 & outcode1) {
|
|
||||||
// bitwise AND is not 0: both points share an outside zone (LEFT, RIGHT, TOP,
|
|
||||||
// or BOTTOM), so both must be outside window; exit loop (accept is false)
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// failed both tests, so calculate the line segment to clip
|
|
||||||
// from an outside point to an intersection with clip edge
|
|
||||||
let x, y;
|
|
||||||
|
|
||||||
// At least one endpoint is outside the clip rectangle; pick it.
|
|
||||||
let outcodeOut = outcode0 ? outcode0 : outcode1;
|
|
||||||
|
|
||||||
// Now find the intersection point;
|
|
||||||
// use formulas:
|
|
||||||
// slope = (y1 - y0) / (x1 - x0)
|
|
||||||
// x = x0 + (1 / slope) * (ym - y0), where ym is ymin or ymax
|
|
||||||
// y = y0 + slope * (xm - x0), where xm is xmin or xmax
|
|
||||||
// No need to worry about divide-by-zero because, in each case, the
|
|
||||||
// outcode bit being tested guarantees the denominator is non-zero
|
|
||||||
if (outcodeOut & TOP) {
|
|
||||||
// point is above the clip window
|
|
||||||
x = x0 + ((x1 - x0) * (ymax - y0)) / (y1 - y0);
|
|
||||||
y = ymax;
|
|
||||||
} else if (outcodeOut & BOTTOM) {
|
|
||||||
// point is below the clip window
|
|
||||||
x = x0 + ((x1 - x0) * (ymin - y0)) / (y1 - y0);
|
|
||||||
y = ymin;
|
|
||||||
} else if (outcodeOut & RIGHT) {
|
|
||||||
// point is to the right of clip window
|
|
||||||
y = y0 + ((y1 - y0) * (xmax - x0)) / (x1 - x0);
|
|
||||||
x = xmax;
|
|
||||||
} else if (outcodeOut & LEFT) {
|
|
||||||
// point is to the left of clip window
|
|
||||||
y = y0 + ((y1 - y0) * (xmin - x0)) / (x1 - x0);
|
|
||||||
x = xmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we move outside point to intersection point to clip
|
|
||||||
// and get ready for next pass.
|
|
||||||
if (outcodeOut == outcode0) {
|
|
||||||
x0 = x;
|
|
||||||
y0 = y;
|
|
||||||
outcode0 = computeOutCode(x0, y0, xmin, xmax, ymin, ymax);
|
|
||||||
} else {
|
|
||||||
x1 = x;
|
|
||||||
y1 = y;
|
|
||||||
outcode1 = computeOutCode(x1, y1, xmin, xmax, ymin, ymax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (accept) {
|
|
||||||
// Following functions are left for implementation by user based on
|
|
||||||
// their platform (OpenGL/graphics.h etc.)
|
|
||||||
// DrawRectangle(xmin, ymin, xmax, ymax);
|
|
||||||
// LineSegment(x0, y0, x1, y1);
|
|
||||||
drawLineFast(context, {
|
|
||||||
x1: x0,
|
|
||||||
y1: y0,
|
|
||||||
x2: x1,
|
|
||||||
y2: y1,
|
|
||||||
color,
|
|
||||||
lineSize,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an HSL color value to RGB. Conversion formula
|
|
||||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
|
||||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
|
||||||
* returns r, g, and b in the set [0, 255].
|
|
||||||
*
|
|
||||||
* @param {number} h The hue
|
|
||||||
* @param {number} s The saturation
|
|
||||||
* @param {number} l The lightness
|
|
||||||
* @return {Array} The RGB representation
|
|
||||||
*/
|
|
||||||
export function hslToRgb(h, s, l) {
|
|
||||||
let r;
|
|
||||||
let g;
|
|
||||||
let b;
|
|
||||||
|
|
||||||
if (s === 0) {
|
|
||||||
r = g = b = l; // achromatic
|
|
||||||
} else {
|
|
||||||
// tslint:disable-next-line:no-shadowed-variable
|
|
||||||
const hue2rgb = function (p, q, t) {
|
|
||||||
if (t < 0) {
|
|
||||||
t += 1;
|
|
||||||
}
|
|
||||||
if (t > 1) {
|
|
||||||
t -= 1;
|
|
||||||
}
|
|
||||||
if (t < 1 / 6) {
|
|
||||||
return p + (q - p) * 6 * t;
|
|
||||||
}
|
|
||||||
if (t < 1 / 2) {
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
if (t < 2 / 3) {
|
|
||||||
return p + (q - p) * (2 / 3 - t) * 6;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
};
|
|
||||||
|
|
||||||
let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
||||||
let p = 2 * l - q;
|
|
||||||
r = hue2rgb(p, q, h + 1 / 3);
|
|
||||||
g = hue2rgb(p, q, h);
|
|
||||||
b = hue2rgb(p, q, h - 1 / 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function wrapText(context, text, x, y, maxWidth, lineHeight, stroke = false) {
|
|
||||||
var words = text.split(" ");
|
|
||||||
var line = "";
|
|
||||||
|
|
||||||
for (var n = 0; n < words.length; n++) {
|
|
||||||
var testLine = line + words[n] + " ";
|
|
||||||
var metrics = context.measureText(testLine);
|
|
||||||
var testWidth = metrics.width;
|
|
||||||
if (testWidth > maxWidth && n > 0) {
|
|
||||||
if (stroke) {
|
|
||||||
context.strokeText(line, x, y);
|
|
||||||
} else {
|
|
||||||
context.fillText(line, x, y);
|
|
||||||
}
|
|
||||||
line = words[n] + " ";
|
|
||||||
y += lineHeight;
|
|
||||||
} else {
|
|
||||||
line = testLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stroke) {
|
|
||||||
context.strokeText(line, x, y);
|
|
||||||
} else {
|
|
||||||
context.fillText(line, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a rotated trapez, used for spotlight culling
|
|
||||||
* @param {number} x
|
|
||||||
* @param {number} y
|
|
||||||
* @param {number} w
|
|
||||||
* @param {number} h
|
|
||||||
* @param {number} leftHeight
|
|
||||||
* @param {number} angle
|
|
||||||
*/
|
|
||||||
export function rotateTrapezRightFaced(x, y, w, h, leftHeight, angle) {
|
|
||||||
const halfY = y + h / 2;
|
|
||||||
const points = [
|
|
||||||
new Vector(x, halfY - leftHeight / 2),
|
|
||||||
new Vector(x + w, y),
|
|
||||||
new Vector(x, halfY + leftHeight / 2),
|
|
||||||
new Vector(x + w, y + h),
|
|
||||||
];
|
|
||||||
|
|
||||||
return Rectangle.getAroundPointsRotated(points, angle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts values from 0 .. 255 to values like 07, 7f, 5d etc
|
|
||||||
* @param {number} value
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function mapClampedColorValueToHex(value) {
|
|
||||||
const hex = "0123456789abcdef";
|
|
||||||
return hex[Math.floor(value / 16)] + hex[value % 16];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts rgb to a hex string
|
|
||||||
* @param {number} r
|
|
||||||
* @param {number} g
|
|
||||||
* @param {number} b
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function rgbToHex(r, g, b) {
|
|
||||||
return mapClampedColorValueToHex(r) + mapClampedColorValueToHex(g) + mapClampedColorValueToHex(b);
|
|
||||||
}
|
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import { SingletonFactory } from "./singleton_factory";
|
import { SingletonFactory } from "./singleton_factory";
|
||||||
import { Factory } from "./factory";
|
import { Factory } from "./factory";
|
||||||
|
|
||||||
/* typehints:start */
|
/**
|
||||||
import { BaseGameSpeed } from "../game/time/base_game_speed";
|
* @typedef {import("../game/time/base_game_speed").BaseGameSpeed} BaseGameSpeed
|
||||||
import { Component } from "../game/component";
|
* @typedef {import("../game/component").Component} Component
|
||||||
import { BaseItem } from "../game/base_item";
|
* @typedef {import("../game/base_item").BaseItem} BaseItem
|
||||||
import { MetaBuilding } from "../game/meta_building";
|
* @typedef {import("../game/meta_building").MetaBuilding} MetaBuilding
|
||||||
/* typehints:end */
|
|
||||||
|
|
||||||
// These factories are here to remove circular dependencies
|
// These factories are here to remove circular dependencies
|
||||||
|
|
||||||
/** @type {SingletonFactoryTemplate<MetaBuilding>} */
|
/** @type {SingletonFactoryTemplate<MetaBuilding>} */
|
||||||
export let gMetaBuildingRegistry = new SingletonFactory();
|
export let gMetaBuildingRegistry = new SingletonFactory();
|
||||||
|
|
||||||
/** @type {Object.<string, Array<typeof MetaBuilding>>} */
|
/** @type {Object.<string, Array<Class<MetaBuilding>>>} */
|
||||||
export let gBuildingsByCategory = null;
|
export let gBuildingsByCategory = null;
|
||||||
|
|
||||||
/** @type {FactoryTemplate<Component>} */
|
/** @type {FactoryTemplate<Component>} */
|
||||||
@ -28,7 +28,7 @@ export let gItemRegistry = new Factory("item");
|
|||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object.<string, Array<typeof MetaBuilding>>} buildings
|
* @param {Object.<string, Array<Class<MetaBuilding>>>} buildings
|
||||||
*/
|
*/
|
||||||
export function initBuildingsByCategory(buildings) {
|
export function initBuildingsByCategory(buildings) {
|
||||||
gBuildingsByCategory = buildings;
|
gBuildingsByCategory = buildings;
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
/* typehints:start */
|
|
||||||
import { Application } from "../application";
|
|
||||||
/* typehints:end */
|
|
||||||
|
|
||||||
import { AtlasDefinition } from "./atlas_definitions";
|
|
||||||
import { makeOffscreenBuffer } from "./buffer_utils";
|
import { makeOffscreenBuffer } from "./buffer_utils";
|
||||||
import { AtlasSprite, BaseSprite, RegularSprite, SpriteAtlasLink } from "./sprites";
|
import { AtlasSprite, BaseSprite, RegularSprite, SpriteAtlasLink } from "./sprites";
|
||||||
import { cachebust } from "./cachebust";
|
import { cachebust } from "./cachebust";
|
||||||
import { createLogger } from "./logging";
|
import { createLogger } from "./logging";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("../application").Application} Application
|
||||||
|
* @typedef {import("./atlas_definitions").AtlasDefinition} AtlasDefinition;
|
||||||
|
*/
|
||||||
|
|
||||||
const logger = createLogger("loader");
|
const logger = createLogger("loader");
|
||||||
|
|
||||||
const missingSpriteIds = {};
|
const missingSpriteIds = {};
|
||||||
|
|
||||||
class LoaderImpl {
|
class LoaderImpl {
|
||||||
constructor() {
|
constructor() {
|
||||||
/** @type {Application} */
|
|
||||||
this.app = null;
|
this.app = null;
|
||||||
|
|
||||||
/** @type {Map<string, BaseSprite>} */
|
/** @type {Map<string, BaseSprite>} */
|
||||||
@ -23,6 +22,9 @@ class LoaderImpl {
|
|||||||
this.rawImages = [];
|
this.rawImages = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Application} app
|
||||||
|
*/
|
||||||
linkAppAfterBoot(app) {
|
linkAppAfterBoot(app) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.makeSpriteNotFoundCanvas();
|
this.makeSpriteNotFoundCanvas();
|
||||||
@ -58,7 +60,7 @@ class LoaderImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retursn a regular sprite from the cache
|
* Returns a regular sprite from the cache
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
* @returns {RegularSprite}
|
* @returns {RegularSprite}
|
||||||
*/
|
*/
|
||||||
@ -155,44 +157,34 @@ class LoaderImpl {
|
|||||||
* @param {AtlasDefinition} atlas
|
* @param {AtlasDefinition} atlas
|
||||||
* @param {HTMLImageElement} loadedImage
|
* @param {HTMLImageElement} loadedImage
|
||||||
*/
|
*/
|
||||||
internalParseAtlas(atlas, loadedImage) {
|
internalParseAtlas({ meta: { scale }, sourceData }, loadedImage) {
|
||||||
this.rawImages.push(loadedImage);
|
this.rawImages.push(loadedImage);
|
||||||
|
|
||||||
for (const spriteKey in atlas.sourceData) {
|
for (const spriteName in sourceData) {
|
||||||
const spriteData = atlas.sourceData[spriteKey];
|
const { frame, sourceSize, spriteSourceSize } = sourceData[spriteName];
|
||||||
|
|
||||||
let sprite = /** @type {AtlasSprite} */ (this.sprites.get(spriteKey));
|
let sprite = /** @type {AtlasSprite} */ (this.sprites.get(spriteName));
|
||||||
|
|
||||||
if (!sprite) {
|
if (!sprite) {
|
||||||
sprite = new AtlasSprite({
|
sprite = new AtlasSprite(spriteName);
|
||||||
spriteName: spriteKey,
|
this.sprites.set(spriteName, sprite);
|
||||||
});
|
|
||||||
this.sprites.set(spriteKey, sprite);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const link = new SpriteAtlasLink({
|
const link = new SpriteAtlasLink({
|
||||||
packedX: spriteData.frame.x,
|
packedX: frame.x,
|
||||||
packedY: spriteData.frame.y,
|
packedY: frame.y,
|
||||||
packedW: spriteData.frame.w,
|
packedW: frame.w,
|
||||||
packedH: spriteData.frame.h,
|
packedH: frame.h,
|
||||||
packOffsetX: spriteData.spriteSourceSize.x,
|
packOffsetX: spriteSourceSize.x,
|
||||||
packOffsetY: spriteData.spriteSourceSize.y,
|
packOffsetY: spriteSourceSize.y,
|
||||||
atlas: loadedImage,
|
atlas: loadedImage,
|
||||||
w: spriteData.sourceSize.w,
|
w: sourceSize.w,
|
||||||
h: spriteData.sourceSize.h,
|
h: sourceSize.h,
|
||||||
});
|
});
|
||||||
sprite.linksByResolution[atlas.meta.scale] = link;
|
sprite.linksByResolution[scale] = link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the links for the sprites after the atlas has been loaded. Used so we
|
|
||||||
* don't have to store duplicate sprites.
|
|
||||||
*/
|
|
||||||
createAtlasLinks() {
|
|
||||||
// NOT USED
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the canvas which shows the question mark, shown when a sprite was not found
|
* Makes the canvas which shows the question mark, shown when a sprite was not found
|
||||||
*/
|
*/
|
||||||
@ -216,14 +208,9 @@ class LoaderImpl {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
canvas.src = "not-found";
|
canvas.src = "not-found";
|
||||||
|
|
||||||
const resolutions = ["0.1", "0.25", "0.5", "0.75", "1"];
|
const sprite = new AtlasSprite("not-found");
|
||||||
const sprite = new AtlasSprite({
|
["0.1", "0.25", "0.5", "0.75", "1"].forEach(resolution => {
|
||||||
spriteName: "not-found",
|
sprite.linksByResolution[resolution] = new SpriteAtlasLink({
|
||||||
});
|
|
||||||
|
|
||||||
for (let i = 0; i < resolutions.length; ++i) {
|
|
||||||
const res = resolutions[i];
|
|
||||||
const link = new SpriteAtlasLink({
|
|
||||||
packedX: 0,
|
packedX: 0,
|
||||||
packedY: 0,
|
packedY: 0,
|
||||||
w: dims,
|
w: dims,
|
||||||
@ -234,8 +221,8 @@ class LoaderImpl {
|
|||||||
packedH: dims,
|
packedH: dims,
|
||||||
atlas: canvas,
|
atlas: canvas,
|
||||||
});
|
});
|
||||||
sprite.linksByResolution[res] = link;
|
});
|
||||||
}
|
|
||||||
this.spriteNotFoundSprite = sprite;
|
this.spriteNotFoundSprite = sprite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { globalConfig } from "./config";
|
import { globalConfig } from "./config";
|
||||||
import { clamp, epsilonCompare, round2Digits } from "./utils";
|
import { epsilonCompare, round2Digits } from "./utils";
|
||||||
import { Vector } from "./vector";
|
import { Vector } from "./vector";
|
||||||
|
|
||||||
export class Rectangle {
|
export class Rectangle {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { DrawParameters } from "./draw_parameters";
|
import { DrawParameters } from "./draw_parameters";
|
||||||
import { Rectangle } from "./rectangle";
|
import { Rectangle } from "./rectangle";
|
||||||
import { epsilonCompare, round3Digits } from "./utils";
|
import { round3Digits } from "./utils";
|
||||||
|
|
||||||
const floorSpriteCoordinates = false;
|
const floorSpriteCoordinates = false;
|
||||||
|
|
||||||
@ -63,10 +63,9 @@ export class SpriteAtlasLink {
|
|||||||
export class AtlasSprite extends BaseSprite {
|
export class AtlasSprite extends BaseSprite {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {object} param0
|
* @param {string} spriteName
|
||||||
* @param {string} param0.spriteName
|
|
||||||
*/
|
*/
|
||||||
constructor({ spriteName = "sprite" }) {
|
constructor(spriteName = "sprite") {
|
||||||
super();
|
super();
|
||||||
/** @type {Object.<string, SpriteAtlasLink>} */
|
/** @type {Object.<string, SpriteAtlasLink>} */
|
||||||
this.linksByResolution = {};
|
this.linksByResolution = {};
|
||||||
@ -197,8 +196,6 @@ export class AtlasSprite extends BaseSprite {
|
|||||||
destH = intersection.h;
|
destH = intersection.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
// assert(epsilonCompare(scaleW, scaleH), "Sprite should be square for cached rendering");
|
|
||||||
|
|
||||||
if (floorSpriteCoordinates) {
|
if (floorSpriteCoordinates) {
|
||||||
parameters.context.drawImage(
|
parameters.context.drawImage(
|
||||||
link.atlas,
|
link.atlas,
|
||||||
|
@ -1,46 +1,7 @@
|
|||||||
import { globalConfig, IS_DEBUG } from "./config";
|
|
||||||
import { Vector } from "./vector";
|
|
||||||
import { T } from "../translations";
|
import { T } from "../translations";
|
||||||
|
|
||||||
// Constants
|
|
||||||
export const TOP = new Vector(0, -1);
|
|
||||||
export const RIGHT = new Vector(1, 0);
|
|
||||||
export const BOTTOM = new Vector(0, 1);
|
|
||||||
export const LEFT = new Vector(-1, 0);
|
|
||||||
export const ALL_DIRECTIONS = [TOP, RIGHT, BOTTOM, LEFT];
|
|
||||||
|
|
||||||
const bigNumberSuffixTranslationKeys = ["thousands", "millions", "billions", "trillions"];
|
const bigNumberSuffixTranslationKeys = ["thousands", "millions", "billions", "trillions"];
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the build id
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function getBuildId() {
|
|
||||||
if (G_IS_DEV && IS_DEBUG) {
|
|
||||||
return "local-dev";
|
|
||||||
} else if (G_IS_DEV) {
|
|
||||||
return "dev-" + getPlatformName() + "-" + G_BUILD_COMMIT_HASH;
|
|
||||||
} else {
|
|
||||||
return "prod-" + getPlatformName() + "-" + G_BUILD_COMMIT_HASH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the environment id (dev, prod, etc)
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function getEnvironmentId() {
|
|
||||||
if (G_IS_DEV && IS_DEBUG) {
|
|
||||||
return "local-dev";
|
|
||||||
} else if (G_IS_DEV) {
|
|
||||||
return "dev-" + getPlatformName();
|
|
||||||
} else if (G_IS_RELEASE) {
|
|
||||||
return "release-" + getPlatformName();
|
|
||||||
} else {
|
|
||||||
return "staging-" + getPlatformName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if this platform is android
|
* Returns if this platform is android
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
@ -66,7 +27,7 @@ export function isIos() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a platform name
|
* Returns a platform name
|
||||||
* @returns {string}
|
* @returns {"android" | "browser" | "ios" | "standalone" | "unknown"}
|
||||||
*/
|
*/
|
||||||
export function getPlatformName() {
|
export function getPlatformName() {
|
||||||
if (G_IS_STANDALONE) {
|
if (G_IS_STANDALONE) {
|
||||||
@ -96,60 +57,13 @@ export function getIPCRenderer() {
|
|||||||
return ipcRenderer;
|
return ipcRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats a sensitive token by only displaying the first digits of it. Use for
|
|
||||||
* stuff like savegame keys etc which should not appear in the log.
|
|
||||||
* @param {string} key
|
|
||||||
*/
|
|
||||||
export function formatSensitive(key) {
|
|
||||||
if (!key) {
|
|
||||||
return "<null>";
|
|
||||||
}
|
|
||||||
key = key || "";
|
|
||||||
return "[" + key.substr(0, 8) + "...]";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new 2D array with the given fill method
|
|
||||||
* @param {number} w Width
|
|
||||||
* @param {number} h Height
|
|
||||||
* @param {(function(number, number) : any) | number | boolean | string | null | undefined} filler Either Fill method, which should return the content for each cell, or static content
|
|
||||||
* @param {string=} context Optional context for memory tracking
|
|
||||||
* @returns {Array<Array<any>>}
|
|
||||||
*/
|
|
||||||
export function make2DArray(w, h, filler, context = null) {
|
|
||||||
if (typeof filler === "function") {
|
|
||||||
const tiles = new Array(w);
|
|
||||||
for (let x = 0; x < w; ++x) {
|
|
||||||
const row = new Array(h);
|
|
||||||
for (let y = 0; y < h; ++y) {
|
|
||||||
row[y] = filler(x, y);
|
|
||||||
}
|
|
||||||
tiles[x] = row;
|
|
||||||
}
|
|
||||||
return tiles;
|
|
||||||
} else {
|
|
||||||
const tiles = new Array(w);
|
|
||||||
const row = new Array(h);
|
|
||||||
for (let y = 0; y < h; ++y) {
|
|
||||||
row[y] = filler;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let x = 0; x < w; ++x) {
|
|
||||||
tiles[x] = row.slice();
|
|
||||||
}
|
|
||||||
return tiles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a new 2D array with undefined contents
|
* Makes a new 2D array with undefined contents
|
||||||
* @param {number} w
|
* @param {number} w
|
||||||
* @param {number} h
|
* @param {number} h
|
||||||
* @param {string=} context
|
|
||||||
* @returns {Array<Array<any>>}
|
* @returns {Array<Array<any>>}
|
||||||
*/
|
*/
|
||||||
export function make2DUndefinedArray(w, h, context = null) {
|
export function make2DUndefinedArray(w, h) {
|
||||||
const result = new Array(w);
|
const result = new Array(w);
|
||||||
for (let x = 0; x < w; ++x) {
|
for (let x = 0; x < w; ++x) {
|
||||||
result[x] = new Array(h);
|
result[x] = new Array(h);
|
||||||
@ -157,33 +71,6 @@ export function make2DUndefinedArray(w, h, context = null) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears a given 2D array with the given fill method
|
|
||||||
* @param {Array<Array<any>>} array
|
|
||||||
* @param {number} w Width
|
|
||||||
* @param {number} h Height
|
|
||||||
* @param {(function(number, number) : any) | number | boolean | string | null | undefined} filler Either Fill method, which should return the content for each cell, or static content
|
|
||||||
*/
|
|
||||||
export function clear2DArray(array, w, h, filler) {
|
|
||||||
assert(array.length === w, "Array dims mismatch w");
|
|
||||||
assert(array[0].length === h, "Array dims mismatch h");
|
|
||||||
if (typeof filler === "function") {
|
|
||||||
for (let x = 0; x < w; ++x) {
|
|
||||||
const row = array[x];
|
|
||||||
for (let y = 0; y < h; ++y) {
|
|
||||||
row[y] = filler(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (let x = 0; x < w; ++x) {
|
|
||||||
const row = array[x];
|
|
||||||
for (let y = 0; y < h; ++y) {
|
|
||||||
row[y] = filler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new map (an empty object without any props)
|
* Creates a new map (an empty object without any props)
|
||||||
*/
|
*/
|
||||||
@ -215,7 +102,9 @@ export function accessNestedPropertyReverse(obj, keys) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Chooses a random entry of an array
|
* Chooses a random entry of an array
|
||||||
* @param {Array | string} arr
|
* @template T
|
||||||
|
* @param {T[]} arr
|
||||||
|
* @returns {T}
|
||||||
*/
|
*/
|
||||||
export function randomChoice(arr) {
|
export function randomChoice(arr) {
|
||||||
return arr[Math.floor(Math.random() * arr.length)];
|
return arr[Math.floor(Math.random() * arr.length)];
|
||||||
@ -304,23 +193,6 @@ export function arrayDeleteValue(array, value) {
|
|||||||
return arrayDelete(array, index);
|
return arrayDelete(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts a direction into a 0 .. 7 index
|
|
||||||
/**
|
|
||||||
* Converts a direction into a index from 0 .. 7, used for miners, zombies etc which have 8 sprites
|
|
||||||
* @param {Vector} offset direction
|
|
||||||
* @param {boolean} inverse if inverse, the direction is reversed
|
|
||||||
* @returns {number} in range [0, 7]
|
|
||||||
*/
|
|
||||||
export function angleToSpriteIndex(offset, inverse = false) {
|
|
||||||
const twoPi = 2.0 * Math.PI;
|
|
||||||
const factor = inverse ? -1 : 1;
|
|
||||||
const offs = inverse ? 2.5 : 3.5;
|
|
||||||
const angle = (factor * Math.atan2(offset.y, offset.x) + offs * Math.PI) % twoPi;
|
|
||||||
|
|
||||||
const index = Math.round((angle / twoPi) * 8) % 8;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two floats for epsilon equality
|
* Compare two floats for epsilon equality
|
||||||
* @param {number} a
|
* @param {number} a
|
||||||
@ -331,15 +203,6 @@ export function epsilonCompare(a, b, epsilon = 1e-5) {
|
|||||||
return Math.abs(a - b) < epsilon;
|
return Math.abs(a - b) < epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare a float for epsilon equal to 0
|
|
||||||
* @param {number} a
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function epsilonIsZero(a) {
|
|
||||||
return epsilonCompare(a, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interpolates two numbers
|
* Interpolates two numbers
|
||||||
* @param {number} a
|
* @param {number} a
|
||||||
@ -399,17 +262,6 @@ export function findNiceIntegerValue(num) {
|
|||||||
return Math.ceil(findNiceValue(num));
|
return Math.ceil(findNiceValue(num));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Smart rounding + fractional handling
|
|
||||||
* @param {number} n
|
|
||||||
*/
|
|
||||||
function roundSmart(n) {
|
|
||||||
if (n < 100) {
|
|
||||||
return n.toFixed(1);
|
|
||||||
}
|
|
||||||
return Math.round(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a big number
|
* Formats a big number
|
||||||
* @param {number} num
|
* @param {number} num
|
||||||
@ -477,92 +329,12 @@ export function formatBigNumberFull(num, divider = T.global.thousandsDivider) {
|
|||||||
return out.substring(0, out.length - 1);
|
return out.substring(0, out.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Delayes a promise so that it will resolve after a *minimum* amount of time only
|
|
||||||
* @param {Promise<any>} promise The promise to delay
|
|
||||||
* @param {number} minTimeMs The time to make it run at least
|
|
||||||
* @returns {Promise<any>} The delayed promise
|
|
||||||
*/
|
|
||||||
export function artificialDelayedPromise(promise, minTimeMs = 500) {
|
|
||||||
if (G_IS_DEV && globalConfig.debug.noArtificialDelays) {
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
const startTime = performance.now();
|
|
||||||
return promise.then(
|
|
||||||
result => {
|
|
||||||
const timeTaken = performance.now() - startTime;
|
|
||||||
const waitTime = Math.floor(minTimeMs - timeTaken);
|
|
||||||
if (waitTime > 0) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(() => {
|
|
||||||
resolve(result);
|
|
||||||
}, waitTime);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
const timeTaken = performance.now() - startTime;
|
|
||||||
const waitTime = Math.floor(minTimeMs - timeTaken);
|
|
||||||
if (waitTime > 0) {
|
|
||||||
// @ts-ignore
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
reject(error);
|
|
||||||
}, waitTime);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes a sine-based animation which pulsates from 0 .. 1 .. 0
|
|
||||||
* @param {number} time Current time in seconds
|
|
||||||
* @param {number} duration Duration of the full pulse in seconds
|
|
||||||
* @param {number} seed Seed to offset the animation
|
|
||||||
*/
|
|
||||||
export function pulseAnimation(time, duration = 1.0, seed = 0.0) {
|
|
||||||
return Math.sin((time * Math.PI * 2.0) / duration + seed * 5642.86729349) * 0.5 + 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the smallest angle between two angles
|
|
||||||
* @param {number} a
|
|
||||||
* @param {number} b
|
|
||||||
* @returns {number} 0 .. 2 PI
|
|
||||||
*/
|
|
||||||
export function smallestAngle(a, b) {
|
|
||||||
return safeMod(a - b + Math.PI, 2.0 * Math.PI) - Math.PI;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modulo which works for negative numbers
|
|
||||||
* @param {number} n
|
|
||||||
* @param {number} m
|
|
||||||
*/
|
|
||||||
export function safeMod(n, m) {
|
|
||||||
return ((n % m) + m) % m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wraps an angle between 0 and 2 pi
|
|
||||||
* @param {number} angle
|
|
||||||
*/
|
|
||||||
export function wrapAngle(angle) {
|
|
||||||
return safeMod(angle, 2.0 * Math.PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits two frames so the ui is updated
|
* Waits two frames so the ui is updated
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export function waitNextFrame() {
|
export function waitNextFrame() {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve) {
|
||||||
window.requestAnimationFrame(function () {
|
window.requestAnimationFrame(function () {
|
||||||
window.requestAnimationFrame(function () {
|
window.requestAnimationFrame(function () {
|
||||||
resolve();
|
resolve();
|
||||||
@ -617,27 +389,13 @@ export function clamp(v, minimum = 0, maximum = 1) {
|
|||||||
return Math.max(minimum, Math.min(maximum, v));
|
return Math.max(minimum, Math.min(maximum, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Measures how long a function took
|
|
||||||
* @param {string} name
|
|
||||||
* @param {function():void} target
|
|
||||||
*/
|
|
||||||
export function measure(name, target) {
|
|
||||||
const now = performance.now();
|
|
||||||
for (let i = 0; i < 25; ++i) {
|
|
||||||
target();
|
|
||||||
}
|
|
||||||
const dur = (performance.now() - now) / 25.0;
|
|
||||||
console.warn("->", name, "took", dur.toFixed(2), "ms");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to create a new div element
|
* Helper method to create a new div element
|
||||||
* @param {string=} id
|
* @param {string=} id
|
||||||
* @param {Array<string>=} classes
|
* @param {Array<string>=} classes
|
||||||
* @param {string=} innerHTML
|
* @param {string=} innerHTML
|
||||||
*/
|
*/
|
||||||
export function makeDivElement(id = null, classes = [], innerHTML = "") {
|
function makeDivElement(id = null, classes = [], innerHTML = "") {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
if (id) {
|
if (id) {
|
||||||
div.id = id;
|
div.id = id;
|
||||||
@ -662,20 +420,6 @@ export function makeDiv(parent, id = null, classes = [], innerHTML = "") {
|
|||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to create a new div and place before reference Node
|
|
||||||
* @param {Element} parent
|
|
||||||
* @param {Element} referenceNode
|
|
||||||
* @param {string=} id
|
|
||||||
* @param {Array<string>=} classes
|
|
||||||
* @param {string=} innerHTML
|
|
||||||
*/
|
|
||||||
export function makeDivBefore(parent, referenceNode, id = null, classes = [], innerHTML = "") {
|
|
||||||
const div = makeDivElement(id, classes, innerHTML);
|
|
||||||
parent.insertBefore(div, referenceNode);
|
|
||||||
return div;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to create a new button element
|
* Helper method to create a new button element
|
||||||
* @param {Array<string>=} classes
|
* @param {Array<string>=} classes
|
||||||
@ -703,19 +447,6 @@ export function makeButton(parent, classes = [], innerHTML = "") {
|
|||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to create a new button and place before reference Node
|
|
||||||
* @param {Element} parent
|
|
||||||
* @param {Element} referenceNode
|
|
||||||
* @param {Array<string>=} classes
|
|
||||||
* @param {string=} innerHTML
|
|
||||||
*/
|
|
||||||
export function makeButtonBefore(parent, referenceNode, classes = [], innerHTML = "") {
|
|
||||||
const element = makeButtonElement(classes, innerHTML);
|
|
||||||
parent.insertBefore(element, referenceNode);
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all children of the given element
|
* Removes all children of the given element
|
||||||
* @param {Element} elem
|
* @param {Element} elem
|
||||||
@ -728,20 +459,10 @@ export function removeAllChildren(elem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function smartFadeNumber(current, newOne, minFade = 0.01, maxFade = 0.9) {
|
|
||||||
const tolerance = Math.min(current, newOne) * 0.5 + 10;
|
|
||||||
let fade = minFade;
|
|
||||||
if (Math.abs(current - newOne) < tolerance) {
|
|
||||||
fade = maxFade;
|
|
||||||
}
|
|
||||||
|
|
||||||
return current * fade + newOne * (1 - fade);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixes lockstep simulation by converting times like 34.0000000003 to 34.00.
|
* Fixes lockstep simulation by converting times like 34.0000000003 to 34.00.
|
||||||
* We use 3 digits of precision, this allows to store sufficient precision of 1 ms without
|
* We use 3 digits of precision, this allows us to store precision of 1 ms without
|
||||||
* the risk to simulation errors due to resync issues
|
* the risking simulation errors due to resync issues
|
||||||
* @param {number} value
|
* @param {number} value
|
||||||
*/
|
*/
|
||||||
export function quantizeFloat(value) {
|
export function quantizeFloat(value) {
|
||||||
@ -840,37 +561,6 @@ export function isSupportedBrowser() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to create a json schema object
|
|
||||||
* @param {any} properties
|
|
||||||
*/
|
|
||||||
export function schemaObject(properties) {
|
|
||||||
return {
|
|
||||||
type: "object",
|
|
||||||
required: Object.keys(properties).slice(),
|
|
||||||
additionalProperties: false,
|
|
||||||
properties,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quickly
|
|
||||||
* @param {number} x
|
|
||||||
* @param {number} y
|
|
||||||
* @param {number} deg
|
|
||||||
* @returns {Vector}
|
|
||||||
*/
|
|
||||||
export function fastRotateMultipleOf90(x, y, deg) {
|
|
||||||
switch (deg) {
|
|
||||||
case 0: {
|
|
||||||
return new Vector(x, y);
|
|
||||||
}
|
|
||||||
case 90: {
|
|
||||||
return new Vector(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats an amount of seconds into something like "5s ago"
|
* Formats an amount of seconds into something like "5s ago"
|
||||||
* @param {number} secs Seconds
|
* @param {number} secs Seconds
|
||||||
@ -928,31 +618,6 @@ export function formatSeconds(secs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capitalizes the first letter
|
|
||||||
* @param {string} str
|
|
||||||
*/
|
|
||||||
export function capitalizeFirstLetter(str) {
|
|
||||||
return str.substr(0, 1).toUpperCase() + str.substr(1).toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a number like 2.5 to "2.5 items / s"
|
* Formats a number like 2.5 to "2.5 items / s"
|
||||||
* @param {number} speed
|
* @param {number} speed
|
||||||
|
@ -6,7 +6,7 @@ import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
|
|||||||
import { GameRoot } from "../root";
|
import { GameRoot } from "../root";
|
||||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||||
import { T } from "../../translations";
|
import { T } from "../../translations";
|
||||||
import { round1Digit, round2Digits, formatItemsPerSecond } from "../../core/utils";
|
import { formatItemsPerSecond } from "../../core/utils";
|
||||||
|
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
export const enumMinerVariants = { chainable: "chainable" };
|
export const enumMinerVariants = { chainable: "chainable" };
|
||||||
|
@ -44,3 +44,9 @@ export class Component extends BasicSerializableObject {
|
|||||||
}
|
}
|
||||||
/* dev:end */
|
/* dev:end */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TypeScript does not support Abstract Static methods (https://github.com/microsoft/TypeScript/issues/34516)
|
||||||
|
* One workaround is to declare the type of the component and reference that for static methods
|
||||||
|
* @typedef {typeof Component} StaticComponent
|
||||||
|
*/
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { globalConfig } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
import { round3Digits } from "../core/utils";
|
|
||||||
|
|
||||||
const logger = createLogger("dynamic_tickrate");
|
const logger = createLogger("dynamic_tickrate");
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { globalConfig } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
import { queryParamOptions } from "../core/query_parameters";
|
|
||||||
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
|
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
import { enumColors } from "./colors";
|
import { enumColors } from "./colors";
|
||||||
@ -7,7 +6,7 @@ import { enumItemProcessorTypes } from "./components/item_processor";
|
|||||||
import { GameRoot, enumLayer } from "./root";
|
import { GameRoot, enumLayer } from "./root";
|
||||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
||||||
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
|
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
|
||||||
import { UPGRADES, blueprintShape } from "./upgrades";
|
import { UPGRADES } from "./upgrades";
|
||||||
|
|
||||||
export class HubGoals extends BasicSerializableObject {
|
export class HubGoals extends BasicSerializableObject {
|
||||||
static getId() {
|
static getId() {
|
||||||
@ -328,9 +327,7 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
/** @type {Array<import("./shape_definition").ShapeLayer>} */
|
/** @type {Array<import("./shape_definition").ShapeLayer>} */
|
||||||
let layers = [];
|
let layers = [];
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const randomColor = () => randomChoice(Object.values(enumColors));
|
const randomColor = () => randomChoice(Object.values(enumColors));
|
||||||
// @ts-ignore
|
|
||||||
const randomShape = () => randomChoice(Object.values(enumSubShape));
|
const randomShape = () => randomChoice(Object.values(enumSubShape));
|
||||||
|
|
||||||
let anyIsMissingTwo = false;
|
let anyIsMissingTwo = false;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ClickDetector } from "../../../core/click_detector";
|
import { ClickDetector } from "../../../core/click_detector";
|
||||||
import { globalConfig, THIRDPARTY_URLS } from "../../../core/config";
|
import { globalConfig } from "../../../core/config";
|
||||||
import { DrawParameters } from "../../../core/draw_parameters";
|
import { DrawParameters } from "../../../core/draw_parameters";
|
||||||
import { drawRotatedSprite, rotateTrapezRightFaced } from "../../../core/draw_utils";
|
import { drawRotatedSprite } from "../../../core/draw_utils";
|
||||||
import { Loader } from "../../../core/loader";
|
import { Loader } from "../../../core/loader";
|
||||||
import { clamp, makeDiv, removeAllChildren } from "../../../core/utils";
|
import { clamp, makeDiv, removeAllChildren } from "../../../core/utils";
|
||||||
import {
|
import {
|
||||||
@ -323,7 +323,6 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
|
|||||||
|
|
||||||
// Fade in / out
|
// Fade in / out
|
||||||
parameters.context.lineWidth = 1;
|
parameters.context.lineWidth = 1;
|
||||||
// parameters.context.globalAlpha = 0.3 + pulseAnimation(this.root.time.realtimeNow(), 0.9) * 0.7;
|
|
||||||
|
|
||||||
// Determine the bounds and visualize them
|
// Determine the bounds and visualize them
|
||||||
const entityBounds = staticComp.getTileSpaceBounds();
|
const entityBounds = staticComp.getTileSpaceBounds();
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { makeDiv, randomInt } from "../../../core/utils";
|
import { makeDiv } from "../../../core/utils";
|
||||||
import { SOUNDS } from "../../../platform/sound";
|
import { SOUNDS } from "../../../platform/sound";
|
||||||
import { enumNotificationType } from "./notifications";
|
import { enumNotificationType } from "./notifications";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { IS_DEMO } from "../../../core/config";
|
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
|
|
||||||
export class HUDGameMenu extends BaseHUDPart {
|
export class HUDGameMenu extends BaseHUDPart {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ClickDetector } from "../../../core/click_detector";
|
import { ClickDetector } from "../../../core/click_detector";
|
||||||
import { formatBigNumber, makeDiv, arrayDelete, arrayDeleteValue } from "../../../core/utils";
|
import { formatBigNumber, makeDiv, arrayDeleteValue } from "../../../core/utils";
|
||||||
import { ShapeDefinition } from "../../shape_definition";
|
import { ShapeDefinition } from "../../shape_definition";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { blueprintShape, UPGRADES } from "../../upgrades";
|
import { blueprintShape, UPGRADES } from "../../upgrades";
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { makeDiv, formatSeconds, formatBigNumberFull } from "../../../core/utils";
|
import { makeDiv, formatBigNumberFull } from "../../../core/utils";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
import { InputReceiver } from "../../../core/input_receiver";
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||||
import { ItemProcessorComponent } from "../../components/item_processor";
|
|
||||||
import { BeltComponent } from "../../components/belt";
|
import { BeltComponent } from "../../components/belt";
|
||||||
import { IS_DEMO } from "../../../core/config";
|
|
||||||
|
|
||||||
export class HUDSettingsMenu extends BaseHUDPart {
|
export class HUDSettingsMenu extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
@ -57,16 +55,7 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
returnToMenu() {
|
returnToMenu() {
|
||||||
// if (IS_DEMO) {
|
|
||||||
// const { cancel, deleteGame } = this.root.hud.parts.dialogs.showWarning(
|
|
||||||
// T.dialogs.leaveNotPossibleInDemo.title,
|
|
||||||
// T.dialogs.leaveNotPossibleInDemo.desc,
|
|
||||||
// ["cancel:good", "deleteGame:bad"]
|
|
||||||
// );
|
|
||||||
// deleteGame.add(() => this.root.gameState.goBackToMenu());
|
|
||||||
// } else {
|
|
||||||
this.root.gameState.goBackToMenu();
|
this.root.gameState.goBackToMenu();
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
goToSettings() {
|
goToSettings() {
|
||||||
@ -102,7 +91,6 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
|||||||
show() {
|
show() {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
document.body.classList.add("ingameDialogOpen");
|
document.body.classList.add("ingameDialogOpen");
|
||||||
// this.background.classList.add("visible");
|
|
||||||
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
||||||
|
|
||||||
const totalMinutesPlayed = Math.ceil(this.root.time.now() / 60);
|
const totalMinutesPlayed = Math.ceil(this.root.time.now() / 60);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { InputReceiver } from "../../../core/input_receiver";
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
import { makeButton, makeDiv, removeAllChildren, capitalizeFirstLetter } from "../../../core/utils";
|
import { makeButton, makeDiv, removeAllChildren } from "../../../core/utils";
|
||||||
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { enumAnalyticsDataSource } from "../../production_analytics";
|
import { enumAnalyticsDataSource } from "../../production_analytics";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
@ -7,6 +7,14 @@ import { DynamicDomAttach } from "../dynamic_dom_attach";
|
|||||||
import { enumDisplayMode, HUDShapeStatisticsHandle } from "./statistics_handle";
|
import { enumDisplayMode, HUDShapeStatisticsHandle } from "./statistics_handle";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capitalizes the first letter
|
||||||
|
* @param {string} str
|
||||||
|
*/
|
||||||
|
function capitalizeFirstLetter(str) {
|
||||||
|
return str.substr(0, 1).toUpperCase() + str.substr(1).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
export class HUDStatistics extends BaseHUDPart {
|
export class HUDStatistics extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
this.background = makeDiv(parent, "ingame_HUD_Statistics", ["ingameDialog"]);
|
this.background = makeDiv(parent, "ingame_HUD_Statistics", ["ingameDialog"]);
|
||||||
|
@ -5,7 +5,6 @@ import { Entity } from "./entity";
|
|||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { BaseItem } from "./base_item";
|
import { BaseItem } from "./base_item";
|
||||||
import { MapChunkView } from "./map_chunk_view";
|
import { MapChunkView } from "./map_chunk_view";
|
||||||
import { randomInt } from "../core/utils";
|
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
|
|
||||||
const logger = createLogger("map");
|
const logger = createLogger("map");
|
||||||
|
@ -28,25 +28,13 @@ export class MapChunk {
|
|||||||
this.tileY = y * globalConfig.mapChunkSize;
|
this.tileY = y * globalConfig.mapChunkSize;
|
||||||
|
|
||||||
/** @type {Array<Array<?Entity>>} */
|
/** @type {Array<Array<?Entity>>} */
|
||||||
this.contents = make2DUndefinedArray(
|
this.contents = make2DUndefinedArray(globalConfig.mapChunkSize, globalConfig.mapChunkSize);
|
||||||
globalConfig.mapChunkSize,
|
|
||||||
globalConfig.mapChunkSize,
|
|
||||||
"map-chunk@" + this.x + "|" + this.y
|
|
||||||
);
|
|
||||||
|
|
||||||
/** @type {Array<Array<?Entity>>} */
|
/** @type {Array<Array<?Entity>>} */
|
||||||
this.wireContents = make2DUndefinedArray(
|
this.wireContents = make2DUndefinedArray(globalConfig.mapChunkSize, globalConfig.mapChunkSize);
|
||||||
globalConfig.mapChunkSize,
|
|
||||||
globalConfig.mapChunkSize,
|
|
||||||
"map-chunk-wires@" + this.x + "|" + this.y
|
|
||||||
);
|
|
||||||
|
|
||||||
/** @type {Array<Array<?BaseItem>>} */
|
/** @type {Array<Array<?BaseItem>>} */
|
||||||
this.lowerLayer = make2DUndefinedArray(
|
this.lowerLayer = make2DUndefinedArray(globalConfig.mapChunkSize, globalConfig.mapChunkSize);
|
||||||
globalConfig.mapChunkSize,
|
|
||||||
globalConfig.mapChunkSize,
|
|
||||||
"map-chunk-lower@" + this.x + "|" + this.y
|
|
||||||
);
|
|
||||||
|
|
||||||
/** @type {Array<Entity>} */
|
/** @type {Array<Entity>} */
|
||||||
this.containedEntities = [];
|
this.containedEntities = [];
|
||||||
|
@ -1,15 +1,6 @@
|
|||||||
import { MapChunk } from "./map_chunk";
|
import { MapChunk } from "./map_chunk";
|
||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { globalConfig } from "../core/config";
|
|
||||||
import { DrawParameters } from "../core/draw_parameters";
|
import { DrawParameters } from "../core/draw_parameters";
|
||||||
import { round1Digit } from "../core/utils";
|
|
||||||
import { Rectangle } from "../core/rectangle";
|
|
||||||
import { createLogger } from "../core/logging";
|
|
||||||
import { smoothenDpi } from "../core/dpi_manager";
|
|
||||||
import { THEME } from "./theme";
|
|
||||||
|
|
||||||
const logger = createLogger("chunk");
|
|
||||||
const chunkSizePixels = globalConfig.mapChunkSize * globalConfig.tileSize;
|
|
||||||
|
|
||||||
export class MapChunkView extends MapChunk {
|
export class MapChunkView extends MapChunk {
|
||||||
/**
|
/**
|
||||||
|
14
src/js/globals.d.ts
vendored
14
src/js/globals.d.ts
vendored
@ -131,22 +131,24 @@ declare interface Math {
|
|||||||
degrees(number): number;
|
degrees(number): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare type Class<T = unknown> = new (...args: any[]) => T;
|
||||||
|
|
||||||
declare interface String {
|
declare interface String {
|
||||||
padStart(size: number, fill?: string): string;
|
padStart(size: number, fill?: string): string;
|
||||||
padEnd(size: number, fill: string): string;
|
padEnd(size: number, fill: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare interface FactoryTemplate<T> {
|
declare interface FactoryTemplate<T> {
|
||||||
entries: Array<new (...args: any[]) => T>;
|
entries: Array<Class<T>>;
|
||||||
entryIds: Array<string>;
|
entryIds: Array<string>;
|
||||||
idToEntry: any;
|
idToEntry: any;
|
||||||
|
|
||||||
getId(): string;
|
getId(): string;
|
||||||
getAllIds(): Array<string>;
|
getAllIds(): Array<string>;
|
||||||
register(entry: new (...args: any[]) => T): void;
|
register(entry: Class<T>): void;
|
||||||
hasId(id: string): boolean;
|
hasId(id: string): boolean;
|
||||||
findById(id: string): new (...args: any[]) => T;
|
findById(id: string): Class<T>;
|
||||||
getEntries(): Array<new (...args: any[]) => T>;
|
getEntries(): Array<Class<T>>;
|
||||||
getNumEntries(): number;
|
getNumEntries(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,10 +158,10 @@ declare interface SingletonFactoryTemplate<T> {
|
|||||||
|
|
||||||
getId(): string;
|
getId(): string;
|
||||||
getAllIds(): Array<string>;
|
getAllIds(): Array<string>;
|
||||||
register(classHandle: new (...args: any[]) => T): void;
|
register(classHandle: Class<T>): void;
|
||||||
hasId(id: string): boolean;
|
hasId(id: string): boolean;
|
||||||
findById(id: string): T;
|
findById(id: string): T;
|
||||||
findByClass(classHandle: new (...args: any[]) => T): T;
|
findByClass(classHandle: Class<T>): T;
|
||||||
getEntries(): Array<T>;
|
getEntries(): Array<T>;
|
||||||
getNumEntries(): number;
|
getNumEntries(): number;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
/* typehints:start */
|
/**
|
||||||
import { Application } from "../application";
|
* @typedef {import("../application").Application} Application
|
||||||
import { ShapeDefinition } from "../game/shape_definition";
|
*/
|
||||||
import { Savegame } from "../savegame/savegame";
|
|
||||||
/* typehints:end */
|
|
||||||
|
|
||||||
export class GameAnalyticsInterface {
|
export class GameAnalyticsInterface {
|
||||||
constructor(app) {
|
constructor(app) {
|
||||||
|
@ -221,7 +221,7 @@ export const allApplicationSettings = [
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
new EnumSetting("refreshRate", {
|
new EnumSetting("refreshRate", {
|
||||||
options: ["60", "100", "120", "144", "165", "250", G_IS_DEV ? "10" : "500"],
|
options: ["60", "75", "100", "120", "144", "165", "250", G_IS_DEV ? "10" : "500"],
|
||||||
valueGetter: rate => rate,
|
valueGetter: rate => rate,
|
||||||
textGetter: rate => rate + " Hz",
|
textGetter: rate => rate + " Hz",
|
||||||
category: enumCategories.advanced,
|
category: enumCategories.advanced,
|
||||||
|
@ -1,8 +1,3 @@
|
|||||||
/* typehints:start */
|
|
||||||
import { Application } from "../application";
|
|
||||||
import { GameRoot } from "../game/root";
|
|
||||||
/* typehints:end */
|
|
||||||
|
|
||||||
import { ReadWriteProxy } from "../core/read_write_proxy";
|
import { ReadWriteProxy } from "../core/read_write_proxy";
|
||||||
import { ExplainedResult } from "../core/explained_result";
|
import { ExplainedResult } from "../core/explained_result";
|
||||||
import { SavegameSerializer } from "./savegame_serializer";
|
import { SavegameSerializer } from "./savegame_serializer";
|
||||||
@ -18,20 +13,29 @@ import { SavegameInterface_V1005 } from "./schemas/1005";
|
|||||||
|
|
||||||
const logger = createLogger("savegame");
|
const logger = createLogger("savegame");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("../application").Application} Application
|
||||||
|
* @typedef {import("../game/root").GameRoot} GameRoot
|
||||||
|
* @typedef {import("./savegame_typedefs").SavegameData} SavegameData
|
||||||
|
* @typedef {import("./savegame_typedefs").SavegameMetadata} SavegameMetadata
|
||||||
|
* @typedef {import("./savegame_typedefs").SavegameStats} SavegameStats
|
||||||
|
* @typedef {import("./savegame_typedefs").SerializedGame} SerializedGame
|
||||||
|
*/
|
||||||
|
|
||||||
export class Savegame extends ReadWriteProxy {
|
export class Savegame extends ReadWriteProxy {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {Application} app
|
* @param {Application} app
|
||||||
* @param {object} param0
|
* @param {object} param0
|
||||||
* @param {string} param0.internalId
|
* @param {string} param0.internalId
|
||||||
* @param {import("./savegame_manager").SavegameMetadata} param0.metaDataRef Handle to the meta data
|
* @param {SavegameMetadata} param0.metaDataRef Handle to the meta data
|
||||||
*/
|
*/
|
||||||
constructor(app, { internalId, metaDataRef }) {
|
constructor(app, { internalId, metaDataRef }) {
|
||||||
super(app, "savegame-" + internalId + ".bin");
|
super(app, "savegame-" + internalId + ".bin");
|
||||||
this.internalId = internalId;
|
this.internalId = internalId;
|
||||||
this.metaDataRef = metaDataRef;
|
this.metaDataRef = metaDataRef;
|
||||||
|
|
||||||
/** @type {import("./savegame_typedefs").SavegameData} */
|
/** @type {SavegameData} */
|
||||||
this.currentData = this.getDefaultData();
|
this.currentData = this.getDefaultData();
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
@ -65,7 +69,7 @@ export class Savegame extends ReadWriteProxy {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the savegames default data
|
* Returns the savegames default data
|
||||||
* @returns {import("./savegame_typedefs").SavegameData}
|
* @returns {SavegameData}
|
||||||
*/
|
*/
|
||||||
getDefaultData() {
|
getDefaultData() {
|
||||||
return {
|
return {
|
||||||
@ -78,7 +82,7 @@ export class Savegame extends ReadWriteProxy {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrates the savegames data
|
* Migrates the savegames data
|
||||||
* @param {import("./savegame_typedefs").SavegameData} data
|
* @param {SavegameData} data
|
||||||
*/
|
*/
|
||||||
migrate(data) {
|
migrate(data) {
|
||||||
if (data.version < 1000) {
|
if (data.version < 1000) {
|
||||||
@ -115,7 +119,7 @@ export class Savegame extends ReadWriteProxy {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies the savegames data
|
* Verifies the savegames data
|
||||||
* @param {import("./savegame_typedefs").SavegameData} data
|
* @param {SavegameData} data
|
||||||
*/
|
*/
|
||||||
verify(data) {
|
verify(data) {
|
||||||
if (!data.dump) {
|
if (!data.dump) {
|
||||||
@ -140,7 +144,7 @@ export class Savegame extends ReadWriteProxy {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns the statistics of the savegame
|
* Returns the statistics of the savegame
|
||||||
* @returns {import("./savegame_typedefs").SavegameStats}
|
* @returns {SavegameStats}
|
||||||
*/
|
*/
|
||||||
getStatistics() {
|
getStatistics() {
|
||||||
return this.currentData.stats;
|
return this.currentData.stats;
|
||||||
@ -163,7 +167,7 @@ export class Savegame extends ReadWriteProxy {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current game dump
|
* Returns the current game dump
|
||||||
* @returns {import("./savegame_typedefs").SerializedGame}
|
* @returns {SerializedGame}
|
||||||
*/
|
*/
|
||||||
getCurrentDump() {
|
getCurrentDump() {
|
||||||
return this.currentData.dump;
|
return this.currentData.dump;
|
||||||
|
@ -7,31 +7,21 @@ const logger = createLogger("savegame_manager");
|
|||||||
|
|
||||||
const Rusha = require("rusha");
|
const Rusha = require("rusha");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("./savegame_typedefs").SavegamesData} SavegamesData
|
||||||
|
* @typedef {import("./savegame_typedefs").SavegameMetadata} SavegameMetadata
|
||||||
|
*/
|
||||||
|
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
export const enumLocalSavegameStatus = {
|
export const enumLocalSavegameStatus = {
|
||||||
offline: "offline",
|
offline: "offline",
|
||||||
synced: "synced",
|
synced: "synced",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{
|
|
||||||
* lastUpdate: number,
|
|
||||||
* version: number,
|
|
||||||
* internalId: string,
|
|
||||||
* level: number
|
|
||||||
* }} SavegameMetadata
|
|
||||||
*
|
|
||||||
* @typedef {{
|
|
||||||
* version: number,
|
|
||||||
* savegames: Array<SavegameMetadata>
|
|
||||||
* }} SavegamesData
|
|
||||||
*/
|
|
||||||
|
|
||||||
export class SavegameManager extends ReadWriteProxy {
|
export class SavegameManager extends ReadWriteProxy {
|
||||||
constructor(app) {
|
constructor(app) {
|
||||||
super(app, "savegames.bin");
|
super(app, "savegames.bin");
|
||||||
|
|
||||||
/** @type {SavegamesData} */
|
|
||||||
this.currentData = this.getDefaultData();
|
this.currentData = this.getDefaultData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
/* typehints:start */
|
|
||||||
import { Component } from "../game/component";
|
|
||||||
import { GameRoot } from "../game/root";
|
|
||||||
/* typehints:end */
|
|
||||||
|
|
||||||
import { ExplainedResult } from "../core/explained_result";
|
import { ExplainedResult } from "../core/explained_result";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
// import { BuildingComponent } from "../components/impl/building";
|
|
||||||
import { gComponentRegistry } from "../core/global_registries";
|
import { gComponentRegistry } from "../core/global_registries";
|
||||||
import { SerializerInternal } from "./serializer_internal";
|
import { SerializerInternal } from "./serializer_internal";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("../game/component").Component} Component
|
||||||
|
* @typedef {import("../game/component").StaticComponent} StaticComponent
|
||||||
|
* @typedef {import("../game/entity").Entity} Entity
|
||||||
|
* @typedef {import("../game/root").GameRoot} GameRoot
|
||||||
|
* @typedef {import("../savegame/savegame_typedefs").SerializedGame} SerializedGame
|
||||||
|
*/
|
||||||
|
|
||||||
const logger = createLogger("savegame_serializer");
|
const logger = createLogger("savegame_serializer");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows to serialize a savegame
|
* Serializes a savegame
|
||||||
*/
|
*/
|
||||||
export class SavegameSerializer {
|
export class SavegameSerializer {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -26,7 +28,7 @@ export class SavegameSerializer {
|
|||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
generateDumpFromGameRoot(root, sanityChecks = true) {
|
generateDumpFromGameRoot(root, sanityChecks = true) {
|
||||||
// Now store generic savegame payload
|
/** @type {SerializedGame} */
|
||||||
const data = {
|
const data = {
|
||||||
camera: root.camera.serialize(),
|
camera: root.camera.serialize(),
|
||||||
time: root.time.serialize(),
|
time: root.time.serialize(),
|
||||||
@ -35,11 +37,10 @@ export class SavegameSerializer {
|
|||||||
hubGoals: root.hubGoals.serialize(),
|
hubGoals: root.hubGoals.serialize(),
|
||||||
pinnedShapes: root.hud.parts.pinnedShapes.serialize(),
|
pinnedShapes: root.hud.parts.pinnedShapes.serialize(),
|
||||||
waypoints: root.hud.parts.waypoints.serialize(),
|
waypoints: root.hud.parts.waypoints.serialize(),
|
||||||
|
entities: this.internal.serializeEntityArray(root.entityMgr.entities),
|
||||||
beltPaths: root.systemMgr.systems.belt.serializePaths(),
|
beltPaths: root.systemMgr.systems.belt.serializePaths(),
|
||||||
};
|
};
|
||||||
|
|
||||||
data.entities = this.internal.serializeEntityArray(root.entityMgr.entities);
|
|
||||||
|
|
||||||
if (!G_IS_RELEASE) {
|
if (!G_IS_RELEASE) {
|
||||||
if (sanityChecks) {
|
if (sanityChecks) {
|
||||||
// Sanity check
|
// Sanity check
|
||||||
@ -55,7 +56,7 @@ export class SavegameSerializer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies if there are logical errors in the savegame
|
* Verifies if there are logical errors in the savegame
|
||||||
* @param {object} savegame
|
* @param {SerializedGame} savegame
|
||||||
* @returns {ExplainedResult}
|
* @returns {ExplainedResult}
|
||||||
*/
|
*/
|
||||||
verifyLogicalErrors(savegame) {
|
verifyLogicalErrors(savegame) {
|
||||||
@ -66,11 +67,10 @@ export class SavegameSerializer {
|
|||||||
const seenUids = [];
|
const seenUids = [];
|
||||||
|
|
||||||
// Check for duplicate UIDS
|
// Check for duplicate UIDS
|
||||||
for (const entityListId in savegame.entities) {
|
for (let i = 0; i < savegame.entities.length; ++i) {
|
||||||
for (let i = 0; i < savegame.entities[entityListId].length; ++i) {
|
/** @type {Entity} */
|
||||||
const list = savegame.entities[entityListId][i];
|
const entity = savegame.entities[i];
|
||||||
for (let k = 0; k < list.length; ++k) {
|
|
||||||
const entity = list[k];
|
|
||||||
const uid = entity.uid;
|
const uid = entity.uid;
|
||||||
if (!Number.isInteger(uid)) {
|
if (!Number.isInteger(uid)) {
|
||||||
return ExplainedResult.bad("Entity has invalid uid: " + uid);
|
return ExplainedResult.bad("Entity has invalid uid: " + uid);
|
||||||
@ -82,14 +82,11 @@ export class SavegameSerializer {
|
|||||||
|
|
||||||
// Verify components
|
// Verify components
|
||||||
if (!entity.components) {
|
if (!entity.components) {
|
||||||
return ExplainedResult.bad(
|
return ExplainedResult.bad("Entity is missing key 'components': " + JSON.stringify(entity));
|
||||||
"Entity is missing key 'components': " + JSON.stringify(entity)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const components = entity.components;
|
const components = entity.components;
|
||||||
for (const componentId in components) {
|
for (const componentId in components) {
|
||||||
// Verify component data
|
|
||||||
const componentData = components[componentId];
|
|
||||||
const componentClass = gComponentRegistry.findById(componentId);
|
const componentClass = gComponentRegistry.findById(componentId);
|
||||||
|
|
||||||
// Check component id is known
|
// Check component id is known
|
||||||
@ -97,10 +94,13 @@ export class SavegameSerializer {
|
|||||||
return ExplainedResult.bad("Unknown component id: " + componentId);
|
return ExplainedResult.bad("Unknown component id: " + componentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check component data is ok
|
// Verify component data
|
||||||
const componentVerifyError = /** @type {typeof Component} */ (componentClass).verify(
|
const componentData = components[componentId];
|
||||||
|
const componentVerifyError = /** @type {StaticComponent} */ (componentClass).verify(
|
||||||
componentData
|
componentData
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check component data is ok
|
||||||
if (componentVerifyError) {
|
if (componentVerifyError) {
|
||||||
return ExplainedResult.bad(
|
return ExplainedResult.bad(
|
||||||
"Component " + componentId + " has invalid data: " + componentVerifyError
|
"Component " + componentId + " has invalid data: " + componentVerifyError
|
||||||
@ -108,15 +108,13 @@ export class SavegameSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ExplainedResult.good();
|
return ExplainedResult.good();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to load the savegame from a given dump
|
* Tries to load the savegame from a given dump
|
||||||
* @param {import("./savegame_typedefs").SerializedGame} savegame
|
* @param {SerializedGame} savegame
|
||||||
* @param {GameRoot} root
|
* @param {GameRoot} root
|
||||||
* @returns {ExplainedResult}
|
* @returns {ExplainedResult}
|
||||||
*/
|
*/
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
import { Entity } from "../game/entity";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{
|
|
||||||
* }} SavegameStats
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @typedef {import("../game/entity").Entity} Entity
|
||||||
|
*
|
||||||
|
* @typedef {{}} SavegameStats
|
||||||
*
|
*
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* camera: any,
|
* camera: any,
|
||||||
* time: any,
|
* time: any,
|
||||||
@ -21,13 +14,25 @@ import { Entity } from "../game/entity";
|
|||||||
* entities: Array<Entity>,
|
* entities: Array<Entity>,
|
||||||
* beltPaths: Array<any>
|
* beltPaths: Array<any>
|
||||||
* }} SerializedGame
|
* }} SerializedGame
|
||||||
*/
|
*
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* version: number,
|
* version: number,
|
||||||
* dump: SerializedGame,
|
* dump: SerializedGame,
|
||||||
* stats: SavegameStats,
|
* stats: SavegameStats,
|
||||||
* lastUpdate: number,
|
* lastUpdate: number,
|
||||||
* }} SavegameData
|
* }} SavegameData
|
||||||
|
*
|
||||||
|
* @typedef {{
|
||||||
|
* lastUpdate: number,
|
||||||
|
* version: number,
|
||||||
|
* internalId: string,
|
||||||
|
* level: number
|
||||||
|
* }} SavegameMetadata
|
||||||
|
*
|
||||||
|
* @typedef {{
|
||||||
|
* version: number,
|
||||||
|
* savegames: Array<SavegameMetadata>
|
||||||
|
* }} SavegamesData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export default {};
|
||||||
|
@ -43,6 +43,9 @@ export class SavegameInterface_V1001 extends SavegameInterface_V1000 {
|
|||||||
for (let i = 0; i < entities.length; ++i) {
|
for (let i = 0; i < entities.length; ++i) {
|
||||||
const entity = entities[i];
|
const entity = entities[i];
|
||||||
|
|
||||||
|
// FIXME - https://github.com/tobspr/shapez.io/issues/514
|
||||||
|
// Broken in https://github.com/tobspr/shapez.io/commit/bf2eee908fedb84dbbabd359a200c446020a340e
|
||||||
|
/** @type any **/
|
||||||
const staticComp = entity.components.StaticMapEntity;
|
const staticComp = entity.components.StaticMapEntity;
|
||||||
const beltComp = entity.components.Belt;
|
const beltComp = entity.components.Belt;
|
||||||
if (staticComp) {
|
if (staticComp) {
|
||||||
|
@ -4,7 +4,7 @@ import { BasicSerializableObject } from "./serialization";
|
|||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
import { Vector } from "../core/vector";
|
import { Vector } from "../core/vector";
|
||||||
import { round4Digits, schemaObject, accessNestedPropertyReverse } from "../core/utils";
|
import { round4Digits } from "../core/utils";
|
||||||
export const globalJsonSchemaDefs = {};
|
export const globalJsonSchemaDefs = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,6 +28,19 @@ export function schemaToJsonSchema(schema) {
|
|||||||
return jsonSchema;
|
return jsonSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to create a json schema object
|
||||||
|
* @param {any} properties
|
||||||
|
*/
|
||||||
|
function schemaObject(properties) {
|
||||||
|
return {
|
||||||
|
type: "object",
|
||||||
|
required: Object.keys(properties).slice(),
|
||||||
|
additionalProperties: false,
|
||||||
|
properties,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base serialization data type
|
* Base serialization data type
|
||||||
*/
|
*/
|
||||||
@ -75,23 +88,6 @@ export class BaseDataType {
|
|||||||
return {
|
return {
|
||||||
$ref: "#/definitions/" + key,
|
$ref: "#/definitions/" + key,
|
||||||
};
|
};
|
||||||
|
|
||||||
// return this.getAsJsonSchemaUncached();
|
|
||||||
// if (!globalJsonSchemaDefs[key]) {
|
|
||||||
// // schema.$id = key;
|
|
||||||
// globalJsonSchemaDefs[key] = {
|
|
||||||
// $id: key,
|
|
||||||
// definitions: {
|
|
||||||
// ["d-" + key]: schema
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// $ref: key + "#/definitions/d-" + key
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // return this.getAsJsonSchemaUncached();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { GameState } from "../core/game_state";
|
import { GameState } from "../core/game_state";
|
||||||
import { cachebust } from "../core/cachebust";
|
import { cachebust } from "../core/cachebust";
|
||||||
import { globalConfig, IS_DEBUG, IS_DEMO, THIRDPARTY_URLS } from "../core/config";
|
import { globalConfig, IS_DEMO, THIRDPARTY_URLS } from "../core/config";
|
||||||
import {
|
import {
|
||||||
makeDiv,
|
makeDiv,
|
||||||
makeButtonElement,
|
makeButtonElement,
|
||||||
formatSecondsToTimeAgo,
|
formatSecondsToTimeAgo,
|
||||||
generateFileDownload,
|
|
||||||
waitNextFrame,
|
waitNextFrame,
|
||||||
isSupportedBrowser,
|
isSupportedBrowser,
|
||||||
makeButton,
|
makeButton,
|
||||||
@ -14,9 +13,29 @@ import {
|
|||||||
import { ReadWriteProxy } from "../core/read_write_proxy";
|
import { ReadWriteProxy } from "../core/read_write_proxy";
|
||||||
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
||||||
import { T } from "../translations";
|
import { T } from "../translations";
|
||||||
import { PlatformWrapperImplBrowser } from "../platform/browser/wrapper";
|
|
||||||
import { getApplicationSettingById } from "../profile/application_settings";
|
import { getApplicationSettingById } from "../profile/application_settings";
|
||||||
import { EnumSetting } from "../profile/setting_types";
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("../savegame/savegame_typedefs").SavegameMetadata} SavegameMetadata
|
||||||
|
* @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 {
|
export class MainMenuState extends GameState {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -128,7 +147,6 @@ export class MainMenuState extends GameState {
|
|||||||
const closeLoader = this.dialogs.showLoadingDialog();
|
const closeLoader = this.dialogs.showLoadingDialog();
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.addEventListener("load", event => {
|
reader.addEventListener("load", event => {
|
||||||
// @ts-ignore
|
|
||||||
const contents = event.target.result;
|
const contents = event.target.result;
|
||||||
let realContent;
|
let realContent;
|
||||||
|
|
||||||
@ -394,7 +412,7 @@ export class MainMenuState extends GameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} game
|
* @param {SavegameMetadata} game
|
||||||
*/
|
*/
|
||||||
resumeGame(game) {
|
resumeGame(game) {
|
||||||
this.app.analytics.trackUiClick("resume_game");
|
this.app.analytics.trackUiClick("resume_game");
|
||||||
@ -419,7 +437,7 @@ export class MainMenuState extends GameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} game
|
* @param {SavegameMetadata} game
|
||||||
*/
|
*/
|
||||||
deleteGame(game) {
|
deleteGame(game) {
|
||||||
this.app.analytics.trackUiClick("delete_game");
|
this.app.analytics.trackUiClick("delete_game");
|
||||||
@ -447,7 +465,7 @@ export class MainMenuState extends GameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} game
|
* @param {SavegameMetadata} game
|
||||||
*/
|
*/
|
||||||
downloadGame(game) {
|
downloadGame(game) {
|
||||||
this.app.analytics.trackUiClick("download_game");
|
this.app.analytics.trackUiClick("download_game");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { GameState } from "../core/game_state";
|
import { GameState } from "../core/game_state";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { findNiceValue, waitNextFrame } from "../core/utils";
|
import { findNiceValue } from "../core/utils";
|
||||||
import { cachebust } from "../core/cachebust";
|
import { cachebust } from "../core/cachebust";
|
||||||
import { PlatformWrapperImplBrowser } from "../platform/browser/wrapper";
|
import { PlatformWrapperImplBrowser } from "../platform/browser/wrapper";
|
||||||
import { T, autoDetectLanguageId, updateApplicationLanguage } from "../translations";
|
import { T, autoDetectLanguageId, updateApplicationLanguage } from "../translations";
|
||||||
@ -228,12 +228,8 @@ export class PreloadState extends GameState {
|
|||||||
this.statusBar.style.width = percentage + "%";
|
this.statusBar.style.width = percentage + "%";
|
||||||
this.statusBarText.innerText = findNiceValue(percentage) + "%";
|
this.statusBarText.innerText = findNiceValue(percentage) + "%";
|
||||||
|
|
||||||
if (G_IS_DEV) {
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
|
||||||
// return waitNextFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
showFailMessage(text) {
|
showFailMessage(text) {
|
||||||
logger.error("App init failed:", text);
|
logger.error("App init failed:", text);
|
||||||
@ -279,11 +275,6 @@ export class PreloadState extends GameState {
|
|||||||
if (confirm("Are you sure you want to reset the app? This will delete all your savegames")) {
|
if (confirm("Are you sure you want to reset the app? This will delete all your savegames")) {
|
||||||
this.resetApp();
|
this.resetApp();
|
||||||
}
|
}
|
||||||
// const signals = this.dialogs.showWarning(T.preload.reset_app_warning.title, T.preload.reset_app_warning.desc, [
|
|
||||||
// "delete:bad:timeout",
|
|
||||||
// "cancel:good",
|
|
||||||
// ]);
|
|
||||||
// signals.delete.add(this.resetApp, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetApp() {
|
resetApp() {
|
||||||
|
@ -33,13 +33,13 @@ steamPage:
|
|||||||
shapez.io est un jeu dans lequel vous devrez construire des usines pour automatiser la création et la combinaison de formes de plus en plus complexes sur une carte infinie.
|
shapez.io est un jeu dans lequel vous devrez construire des usines pour automatiser la création et la combinaison de formes de plus en plus complexes sur une carte infinie.
|
||||||
Lors de la livraison des formes requises vous progresserez et débloquerez des améliorations pour accélerer votre usine.
|
Lors de la livraison des formes requises vous progresserez et débloquerez des améliorations pour accélerer votre usine.
|
||||||
|
|
||||||
Au vu de l'augmantation des demandes de formes, vous devrez agrandir votre usine pour répondre à la forte demande - Mais n'oubliez pas les ressources, vous drevrez vous étendre au milieu de cette [b]carte infinie[/b] !
|
Au vu de l'augmentation des demandes de formes, vous devrez agrandir votre usine pour répondre à la forte demande - Mais n'oubliez pas les ressources, vous drevrez vous étendre au milieu de cette [b]carte infinie[/b] !
|
||||||
|
|
||||||
Bientôt vous devrez mixer les couleurs et peindre vos formes avec - Combinez les ressources de couleurs rouge, verte et bleue pour produire différentes couleurs et peindre les formes avec pour satisfaire la demande.
|
Bientôt vous devrez mixer les couleurs et peindre vos formes avec - Combinez les ressources de couleurs rouge, verte et bleue pour produire différentes couleurs et peindre les formes avec pour satisfaire la demande.
|
||||||
|
|
||||||
Ce jeu propose 18 niveaux progressifs (qui devraient déjà vous occuper des heures!) mais j'ajoute constamment de nouveau contenus - Il y en a beaucoup de prévus !
|
Ce jeu propose 18 niveaux progressifs (qui devraient déjà vous occuper quelques heures !) mais j'ajoute constamment de nouveau contenus - Il y en a beaucoup de prévus !
|
||||||
|
|
||||||
Acheter le jeu vous donne accès à la version complète qui a des fonctionnalitées additionnelles et vous recevrez aussi un accès à des fonctionnalitées fraîchement développées.
|
Acheter le jeu vous donne accès à la version complète qui a des fonctionnalités additionnelles et vous recevrez aussi un accès à des fonctionnalités fraîchement développées.
|
||||||
|
|
||||||
[b]Avantages de la version complète (standalone)[/b]
|
[b]Avantages de la version complète (standalone)[/b]
|
||||||
|
|
||||||
@ -59,9 +59,9 @@ steamPage:
|
|||||||
|
|
||||||
[list]
|
[list]
|
||||||
[*] Différentes cartes et challenges (e.g. carte avec obstacles)
|
[*] Différentes cartes et challenges (e.g. carte avec obstacles)
|
||||||
[*] Puzzles (Délivrer la forme requise avec une zone limitée/jeu de batîments)
|
[*] Puzzles (Délivrer la forme requise avec une zone limitée/jeu de bâtiments)
|
||||||
[*] Un mode histoire où les batîments ont un coût
|
[*] Un mode histoire où les bâtiments ont un coût
|
||||||
[*] Générateur de carte configurable (configuration des ressources/formes taille/densitée, graine et plus)
|
[*] Générateur de carte configurable (configuration des ressources/formes/taille/densitée, seed et plus)
|
||||||
[*] Plus de formes
|
[*] Plus de formes
|
||||||
[*] Amélioration des performances (Le jeu tourne déjà plutot bien !)
|
[*] Amélioration des performances (Le jeu tourne déjà plutot bien !)
|
||||||
[*] Et bien plus !
|
[*] Et bien plus !
|
||||||
@ -127,7 +127,7 @@ global:
|
|||||||
control: CTRL
|
control: CTRL
|
||||||
alt: ALT
|
alt: ALT
|
||||||
escape: ESC
|
escape: ESC
|
||||||
shift: SHIFT
|
shift: MAJ
|
||||||
space: ESPACE
|
space: ESPACE
|
||||||
|
|
||||||
demoBanners:
|
demoBanners:
|
||||||
@ -146,7 +146,7 @@ mainMenu:
|
|||||||
|
|
||||||
# This is shown when using firefox and other browsers which are not supported.
|
# This is shown when using firefox and other browsers which are not supported.
|
||||||
browserWarning: >-
|
browserWarning: >-
|
||||||
Désolé, mais ce jeu est connu pour tourner lentement sur votre navigateur web ! Procurez-vous la version complète ou téléchargez Chrome pour une meilleure expérience.
|
Désolé, ce jeu est connu pour tourner lentement sur votre navigateur web ! Procurez-vous la version complète ou téléchargez Chrome pour une meilleure expérience.
|
||||||
|
|
||||||
savegameLevel: Niveau <x>
|
savegameLevel: Niveau <x>
|
||||||
savegameLevelUnknown: Niveau inconnu
|
savegameLevelUnknown: Niveau inconnu
|
||||||
@ -234,12 +234,12 @@ dialogs:
|
|||||||
massDeleteConfirm:
|
massDeleteConfirm:
|
||||||
title: Confirmation de suppression
|
title: Confirmation de suppression
|
||||||
desc: >-
|
desc: >-
|
||||||
Vous allez supprimer pas mal de bâtiments (<count> pour être exact) ! Êtes vous certains de vouloir faire cela ?
|
Vous allez supprimer pas mal de bâtiments (<count> pour être exact) ! Êtes vous certains de vouloir faire ça ?
|
||||||
|
|
||||||
massCutConfirm:
|
massCutConfirm:
|
||||||
title: Confirmer la coupure
|
title: Confirmer la coupure
|
||||||
desc: >-
|
desc: >-
|
||||||
Vous vous apprêtez à couper beaucoup de bâtiments (<count> pour être précis) ! Êtes-vous certains de vouloir faire cela ?
|
Vous vous apprêtez à couper beaucoup de bâtiments (<count> pour être précis) ! Êtes-vous certains de vouloir faire ça ?
|
||||||
|
|
||||||
blueprintsNotUnlocked:
|
blueprintsNotUnlocked:
|
||||||
title: Pas encore débloqué
|
title: Pas encore débloqué
|
||||||
@ -351,10 +351,10 @@ ingame:
|
|||||||
description: Affiche le nombre de formes stockées dans votre bâtiment central.
|
description: Affiche le nombre de formes stockées dans votre bâtiment central.
|
||||||
produced:
|
produced:
|
||||||
title: Produit
|
title: Produit
|
||||||
description: Affiche tous les formes que votre usine entière produit, en incluant les formes intermédiaires.
|
description: Affiche tous les formes que votre usine produit, en incluant les formes intermédiaires.
|
||||||
delivered:
|
delivered:
|
||||||
title: Délivré
|
title: Délivré
|
||||||
description: Affiche les formes qui ont été livrées dans votre centre.
|
description: Affiche les formes qui ont été livrées dans votre bâtiment central.
|
||||||
noShapesProduced: Aucune forme n'a été produite jusqu'à présent.
|
noShapesProduced: Aucune forme n'a été produite jusqu'à présent.
|
||||||
|
|
||||||
# Displays the shapes per minute, e.g. '523 / m'
|
# Displays the shapes per minute, e.g. '523 / m'
|
||||||
@ -398,7 +398,7 @@ ingame:
|
|||||||
Connectez l'extracteur avec un <strong>convoyeur</strong> vers votre centre !<br><br>Astuce: <strong>Cliquez et faites glisser</strong> le convoyeur avec votre souris !
|
Connectez l'extracteur avec un <strong>convoyeur</strong> vers votre centre !<br><br>Astuce: <strong>Cliquez et faites glisser</strong> le convoyeur avec votre souris !
|
||||||
|
|
||||||
1_3_expand: >-
|
1_3_expand: >-
|
||||||
Ceci n'est <strong>PAS</strong> un jeu incrémental et inactif ! Construisez plus d'extracteurs et de convoyeurs pour atteindre plus vite votre votre but.<br><br>Astuce: Gardez <strong>SHIFT</strong> enfoncé pour placer plusieurs extracteurs, et utilisez <strong>R</strong> pour les faire pivoter.
|
Ceci n'est <strong>PAS</strong> un jeu incrémental et inactif ! Construisez plus d'extracteurs et de convoyeurs pour atteindre plus vite votre votre but.<br><br>Astuce: Gardez <strong>MAJ</strong> enfoncé pour placer plusieurs extracteurs, et utilisez <strong>R</strong> pour les faire pivoter.
|
||||||
|
|
||||||
colors:
|
colors:
|
||||||
red: Rouge
|
red: Rouge
|
||||||
@ -487,8 +487,8 @@ buildings:
|
|||||||
name: Pivoteur inversé
|
name: Pivoteur inversé
|
||||||
description: Fait pivoter une forme de 90 degrés vers la gauche.
|
description: Fait pivoter une forme de 90 degrés vers la gauche.
|
||||||
fl:
|
fl:
|
||||||
name: Rotate (180)
|
name: Pivoteur (180)
|
||||||
description: Rotates shapes by 180 degrees.
|
description: Fait pivoter les formes de 90 degrés.
|
||||||
|
|
||||||
stacker:
|
stacker:
|
||||||
default:
|
default:
|
||||||
@ -707,9 +707,9 @@ settings:
|
|||||||
Affiche ou non le bouton 'Afficher un indice' dans le coin inférieur gauche.
|
Affiche ou non le bouton 'Afficher un indice' dans le coin inférieur gauche.
|
||||||
|
|
||||||
language:
|
language:
|
||||||
title: Langage
|
title: Langue
|
||||||
description: >-
|
description: >-
|
||||||
Change le langage. Toutes les traductions sont des contributions des utilisateurs et pourraient être partiellement incomplètes !
|
Change la langue. Toutes les traductions sont des contributions des utilisateurs et pourraient être partiellement incomplètes !
|
||||||
|
|
||||||
movementSpeed:
|
movementSpeed:
|
||||||
title: Vitesse de déplacement
|
title: Vitesse de déplacement
|
||||||
|
@ -155,6 +155,7 @@ mainMenu:
|
|||||||
savegameLevel: <x>. szint
|
savegameLevel: <x>. szint
|
||||||
savegameLevelUnknown: Ismeretlen szint
|
savegameLevelUnknown: Ismeretlen szint
|
||||||
|
|
||||||
|
|
||||||
dialogs:
|
dialogs:
|
||||||
buttons:
|
buttons:
|
||||||
ok: OK
|
ok: OK
|
||||||
@ -327,7 +328,7 @@ ingame:
|
|||||||
# Notifications on the lower right
|
# Notifications on the lower right
|
||||||
notifications:
|
notifications:
|
||||||
newUpgrade: Egy új fejlesztés elérhető!
|
newUpgrade: Egy új fejlesztés elérhető!
|
||||||
gameSaved: A játékállás el lett mentve.
|
gameSaved: A játékállás mentve.
|
||||||
|
|
||||||
# The "Upgrades" window
|
# The "Upgrades" window
|
||||||
shop:
|
shop:
|
||||||
@ -353,7 +354,7 @@ ingame:
|
|||||||
title: Gyártva
|
title: Gyártva
|
||||||
description: Az összes eddig legyártott alakzatod, beleértve a köztes alakzatokat is.
|
description: Az összes eddig legyártott alakzatod, beleértve a köztes alakzatokat is.
|
||||||
delivered:
|
delivered:
|
||||||
title: Kézbesítve
|
title: Beszállítva
|
||||||
description: Az összes alakzat, amely jelenleg kézbesítés alatt van a központba.
|
description: Az összes alakzat, amely jelenleg kézbesítés alatt van a központba.
|
||||||
noShapesProduced: Még nem gyártottál egy alazkatot sem.
|
noShapesProduced: Még nem gyártottál egy alazkatot sem.
|
||||||
|
|
||||||
@ -364,8 +365,8 @@ ingame:
|
|||||||
settingsMenu:
|
settingsMenu:
|
||||||
playtime: Játékidő
|
playtime: Játékidő
|
||||||
|
|
||||||
buildingsPlaced: Épület
|
buildingsPlaced: Épületek száma:
|
||||||
beltsPlaced: Futószalag
|
beltsPlaced: Futószalagok hossza:
|
||||||
|
|
||||||
buttons:
|
buttons:
|
||||||
continue: Folytatás
|
continue: Folytatás
|
||||||
@ -406,7 +407,7 @@ ingame:
|
|||||||
blue: Kék
|
blue: Kék
|
||||||
yellow: Sárga
|
yellow: Sárga
|
||||||
purple: Lila
|
purple: Lila
|
||||||
cyan: Cián
|
cyan: Világoskék
|
||||||
white: Fehér
|
white: Fehér
|
||||||
uncolored: Színezetlen
|
uncolored: Színezetlen
|
||||||
black: Fekete
|
black: Fekete
|
||||||
@ -434,91 +435,91 @@ shopUpgrades:
|
|||||||
buildings:
|
buildings:
|
||||||
belt:
|
belt:
|
||||||
default:
|
default:
|
||||||
name: &belt Conveyor Belt
|
name: &belt Futószalag
|
||||||
description: Transports items, hold and drag to place multiple.
|
description: Elemeket szállít, tartsd nyomva az egérgombot egyszerre több lerakásához.
|
||||||
|
|
||||||
miner: # Internal name for the Extractor
|
miner: # Internal name for the Extractor
|
||||||
default:
|
default:
|
||||||
name: &miner Extractor
|
name: &miner Bányász
|
||||||
description: Place over a shape or color to extract it.
|
description: Tedd egy alakzatra vagy színre a kibányászásához.
|
||||||
|
|
||||||
chainable:
|
chainable:
|
||||||
name: Extractor (Chain)
|
name: Bányász (összekapcsolható)
|
||||||
description: Place over a shape or color to extract it. Can be chained.
|
description: Tedd egy alakzatra vagy színre a kibányászásához. Több egymáshoz kapcsolható.
|
||||||
|
|
||||||
underground_belt: # Internal name for the Tunnel
|
underground_belt: # Internal name for the Tunnel
|
||||||
default:
|
default:
|
||||||
name: &underground_belt Tunnel
|
name: &underground_belt Alagút
|
||||||
description: Allows to tunnel resources under buildings and belts.
|
description: Segítségével futószalagok és épületek alatt átvezethetők az elemek.
|
||||||
|
|
||||||
tier2:
|
tier2:
|
||||||
name: Tunnel Tier II
|
name: Alagút II
|
||||||
description: Allows to tunnel resources under buildings and belts.
|
description: Segítségével futószalagok és épületek alatt átvezethetők az elemek.
|
||||||
|
|
||||||
splitter: # Internal name for the Balancer
|
splitter: # Internal name for the Balancer
|
||||||
default:
|
default:
|
||||||
name: &splitter Balancer
|
name: &splitter Elosztó
|
||||||
description: Multifunctional - Evenly distributes all inputs onto all outputs.
|
description: Többfunkciós - Egyenletesen szétosztja a bementeket a kimenetekre.
|
||||||
|
|
||||||
compact:
|
compact:
|
||||||
name: Merger (compact)
|
name: Egyesítő (kompakt)
|
||||||
description: Merges two conveyor belts into one.
|
description: Két futószalagot egyesít.
|
||||||
|
|
||||||
compact-inverse:
|
compact-inverse:
|
||||||
name: Merger (compact)
|
name: Egyesítő (kompakt)
|
||||||
description: Merges two conveyor belts into one.
|
description: Két futószalagot egyesít.
|
||||||
|
|
||||||
cutter:
|
cutter:
|
||||||
default:
|
default:
|
||||||
name: &cutter Cutter
|
name: &cutter Vágó
|
||||||
description: Cuts shapes from top to bottom and outputs both halfs. <strong>If you use only one part, be sure to destroy the other part or it will stall!</strong>
|
description: Függőlegesen félbevágja az alakzatokat. <strong>Ha csak az egyik felet akarod használni, ne felejtsd el a másikat kukába küldeni, különben eldugítja!</strong>
|
||||||
quad:
|
quad:
|
||||||
name: Cutter (Quad)
|
name: Vágó (negyedelő)
|
||||||
description: Cuts shapes into four parts. <strong>If you use only one part, be sure to destroy the other part or it will stall!</strong>
|
description: Négyfelé vágja az alakzatokat. Cuts shapes into four parts. <strong>Ha csak az egyik felet akarod használni, ne felejtsd el a többit a kukába küldeni, különben eldugítja!</strong>
|
||||||
|
|
||||||
rotater:
|
rotater:
|
||||||
default:
|
default:
|
||||||
name: &rotater Rotate
|
name: &rotater Forgató
|
||||||
description: Rotates shapes clockwise by 90 degrees.
|
description: Elforgatja az alakzatot óramutató irányában 90 fokkal.
|
||||||
ccw:
|
ccw:
|
||||||
name: Rotate (CCW)
|
name: Forgató (fordított)
|
||||||
description: Rotates shapes counter clockwise by 90 degrees.
|
description: Elforgatja az alakzatot óramutatóval ellentétesen 90 fokkal.
|
||||||
fl:
|
fl:
|
||||||
name: Rotate (180)
|
name: Forgató (180)
|
||||||
description: Rotates shapes by 180 degrees.
|
description: Elforgatja az alakzatot 180 fokkal.
|
||||||
|
|
||||||
stacker:
|
stacker:
|
||||||
default:
|
default:
|
||||||
name: &stacker Stacker
|
name: &stacker Egyesítő
|
||||||
description: Stacks both items. If they can not be merged, the right item is placed above the left item.
|
description: Egyesít két elemet. Ha nem lehet összeilleszteni őket, a jobboldali elem a baloldali tetejére kerül.
|
||||||
|
|
||||||
mixer:
|
mixer:
|
||||||
default:
|
default:
|
||||||
name: &mixer Color Mixer
|
name: &mixer Színkeverő
|
||||||
description: Mixes two colors using additive blending.
|
description: Összekever két színt összeadó színkeveréssel.
|
||||||
|
|
||||||
painter:
|
painter:
|
||||||
default:
|
default:
|
||||||
name: &painter Painter
|
name: &painter Festő
|
||||||
description: &painter_desc Colors the whole shape on the left input with the color from the right input.
|
description: &painter_desc Beszínezi az alakzatot a baloldali bemeneten a jobboldali bemeneten érkező színnel.
|
||||||
double:
|
double:
|
||||||
name: Painter (Double)
|
name: Festő (Dupla)
|
||||||
description: Colors the shapes on the left inputs with the color from the top input.
|
description: Beszínezi az alakzatokat a baloldali bemeneteken a fenti bemeneten érkező színnel.
|
||||||
quad:
|
quad:
|
||||||
name: Painter (Quad)
|
name: Festő (Négyszeres)
|
||||||
description: Allows to color each quadrant of the shape with a different color.
|
description: Az alakzat négy negyedét különböző színekkel lehet vele színezni.
|
||||||
mirrored:
|
mirrored:
|
||||||
name: *painter
|
name: *painter
|
||||||
description: *painter_desc
|
description: *painter_desc
|
||||||
|
|
||||||
trash:
|
trash:
|
||||||
default:
|
default:
|
||||||
name: &trash Trash
|
name: &trash Kuka
|
||||||
description: Accepts inputs from all sides and destroys them. Forever.
|
description: Bármelyik irányból lehet hozzá csatlakozni, és megsemmisíti a beleküldött elemeket. Örökre.
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
name: Storage
|
name: Tároló
|
||||||
description: Stores excess items, up to a given capacity. Can be used as an overflow gate.
|
description: Tárolja a fölös elemeket egy bizonyos kapacitásig.
|
||||||
hub:
|
hub:
|
||||||
deliver: Deliver
|
deliver: Deliver
|
||||||
toUnlock: to unlock
|
toUnlock: to unlock
|
||||||
|
@ -411,7 +411,7 @@ ingame:
|
|||||||
cyan: シアン
|
cyan: シアン
|
||||||
white: 白
|
white: 白
|
||||||
uncolored: 無色
|
uncolored: 無色
|
||||||
black: Black
|
black: 黒
|
||||||
shapeViewer:
|
shapeViewer:
|
||||||
title: レイヤー
|
title: レイヤー
|
||||||
empty: 空
|
empty: 空
|
||||||
@ -491,8 +491,8 @@ buildings:
|
|||||||
name: 回転機 (逆)
|
name: 回転機 (逆)
|
||||||
description: 形を反時計回り方向に90度回転します。
|
description: 形を反時計回り方向に90度回転します。
|
||||||
fl:
|
fl:
|
||||||
name: Rotate (180)
|
name: 回転機 (180)
|
||||||
description: Rotates shapes by 180 degrees.
|
description: 形を180度回転します。
|
||||||
|
|
||||||
stacker:
|
stacker:
|
||||||
default:
|
default:
|
||||||
@ -533,20 +533,20 @@ buildings:
|
|||||||
advanced_processor:
|
advanced_processor:
|
||||||
default:
|
default:
|
||||||
name: Color Inverter
|
name: Color Inverter
|
||||||
description: Accepts a color or shape and inverts it.
|
description: 入力された色や形の色を反転します。
|
||||||
energy_generator:
|
energy_generator:
|
||||||
deliver: Deliver
|
deliver: Deliver
|
||||||
toGenerateEnergy: For
|
toGenerateEnergy: For
|
||||||
default:
|
default:
|
||||||
name: Energy Generator
|
name: エネルギー発電機
|
||||||
description: Generates energy by consuming shapes.
|
description: 入力された形を使って、エネルギーを発電します。
|
||||||
wire_crossings:
|
wire_crossings:
|
||||||
default:
|
default:
|
||||||
name: Wire Splitter
|
name: ワイヤー分配機
|
||||||
description: Splits a energy wire into two.
|
description: 1つのワイヤーを2つのワイヤーに分配します。
|
||||||
merger:
|
merger:
|
||||||
name: Wire Merger
|
name: ワイヤー合流機
|
||||||
description: Merges two energy wires into one.
|
description: 2つのワイヤーを1つのワイヤーに合流します。
|
||||||
|
|
||||||
storyRewards:
|
storyRewards:
|
||||||
# Those are the rewards gained from completing the store
|
# Those are the rewards gained from completing the store
|
||||||
|
@ -23,6 +23,9 @@ steamPage:
|
|||||||
# This is the short text appearing on the steam page
|
# This is the short text appearing on the steam page
|
||||||
shortText: shapez.io é um jogo sobre construir fábricas, automatizando a criação e combinação de formas cada vez mais complexas num mapa infinito.
|
shortText: shapez.io é um jogo sobre construir fábricas, automatizando a criação e combinação de formas cada vez mais complexas num mapa infinito.
|
||||||
|
|
||||||
|
# This is the text shown above the Discord link
|
||||||
|
discordLink: Discord Oficial - Converse comigo!
|
||||||
|
|
||||||
# This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page.
|
# This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page.
|
||||||
# NOTICE:
|
# NOTICE:
|
||||||
# - Do not translate the first line (This is the gif image at the start of the store)
|
# - Do not translate the first line (This is the gif image at the start of the store)
|
||||||
@ -31,6 +34,7 @@ steamPage:
|
|||||||
[img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img]
|
[img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img]
|
||||||
|
|
||||||
shapez.io é um jogo sobre construir fábricas, automatizando a criação e combinação de formas cada vez mais complexas num mapa infinito.
|
shapez.io é um jogo sobre construir fábricas, automatizando a criação e combinação de formas cada vez mais complexas num mapa infinito.
|
||||||
|
|
||||||
Após a entrega das formas requisitadas você progredirá no jogo e desbloqueará melhorias para acelerar sua fábrica.
|
Após a entrega das formas requisitadas você progredirá no jogo e desbloqueará melhorias para acelerar sua fábrica.
|
||||||
|
|
||||||
Conforme sua demanda por formas aumenta, você irá que aumentar sua fábrica para alcançar-la - Mas não se esqueça dos recursos, você precisará expandir pelo [b]mapa infinito[/b]!
|
Conforme sua demanda por formas aumenta, você irá que aumentar sua fábrica para alcançar-la - Mas não se esqueça dos recursos, você precisará expandir pelo [b]mapa infinito[/b]!
|
||||||
@ -82,8 +86,6 @@ steamPage:
|
|||||||
[*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Ajude a traduzir[/url]
|
[*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Ajude a traduzir[/url]
|
||||||
[/list]
|
[/list]
|
||||||
|
|
||||||
discordLink: Discord Oficial - Converse comigo!
|
|
||||||
|
|
||||||
global:
|
global:
|
||||||
loading: Carregando
|
loading: Carregando
|
||||||
error: Erro
|
error: Erro
|
||||||
@ -134,14 +136,19 @@ demoBanners:
|
|||||||
# This is the "advertisement" shown in the main menu and other various places
|
# This is the "advertisement" shown in the main menu and other various places
|
||||||
title: Versão Demo
|
title: Versão Demo
|
||||||
intro: >-
|
intro: >-
|
||||||
Pegue a versão completa para desbloquear todas os recursos
|
Pegue a versão completa para desbloquear todas os recursos!
|
||||||
|
|
||||||
mainMenu:
|
mainMenu:
|
||||||
play: Jogar
|
play: Jogar
|
||||||
|
continue: Continuar
|
||||||
|
newGame: Novo jogo
|
||||||
changelog: Changelog
|
changelog: Changelog
|
||||||
|
subreddit: Reddit
|
||||||
importSavegame: Importar
|
importSavegame: Importar
|
||||||
openSourceHint: Esse jogo tem código aberto!
|
openSourceHint: Esse jogo tem código aberto!
|
||||||
discordLink: Discord oficial
|
discordLink: Discord oficial
|
||||||
|
helpTranslate: Ajude a traduzir!
|
||||||
|
madeBy: Feito por <author-link>
|
||||||
|
|
||||||
# This is shown when using firefox and other browsers which are not supported.
|
# This is shown when using firefox and other browsers which are not supported.
|
||||||
browserWarning: >-
|
browserWarning: >-
|
||||||
@ -150,12 +157,6 @@ mainMenu:
|
|||||||
savegameLevel: Nível <x>
|
savegameLevel: Nível <x>
|
||||||
savegameLevelUnknown: Nível desconhecido
|
savegameLevelUnknown: Nível desconhecido
|
||||||
|
|
||||||
helpTranslate: Ajude a traduzir!
|
|
||||||
continue: Continuar
|
|
||||||
newGame: Novo jogo
|
|
||||||
madeBy: Feito por <author-link>
|
|
||||||
subreddit: Reddit
|
|
||||||
|
|
||||||
dialogs:
|
dialogs:
|
||||||
buttons:
|
buttons:
|
||||||
ok: OK
|
ok: OK
|
||||||
@ -163,11 +164,11 @@ dialogs:
|
|||||||
cancel: Cancelar
|
cancel: Cancelar
|
||||||
later: Voltar
|
later: Voltar
|
||||||
restart: Reiniciar
|
restart: Reiniciar
|
||||||
reset: Reset
|
reset: Resetar
|
||||||
getStandalone: Obter versão completa
|
getStandalone: Obter versão completa
|
||||||
deleteGame: Sei o que estou fazendo
|
deleteGame: Sei o que estou fazendo
|
||||||
viewUpdate: Atualizações
|
viewUpdate: Atualizações
|
||||||
showUpgrades: Ver melhorias
|
showUpgrades: Melhorias
|
||||||
showKeybindings: Controles
|
showKeybindings: Controles
|
||||||
|
|
||||||
importSavegameError:
|
importSavegameError:
|
||||||
@ -198,7 +199,7 @@ dialogs:
|
|||||||
restartRequired:
|
restartRequired:
|
||||||
title: Ação necessária
|
title: Ação necessária
|
||||||
text: >-
|
text: >-
|
||||||
Voce precisa reiniciar o jogo para aplicar as mudanças.
|
Você precisa reiniciar o jogo para aplicar as mudanças.
|
||||||
|
|
||||||
editKeybinding:
|
editKeybinding:
|
||||||
title: Alterar tecla
|
title: Alterar tecla
|
||||||
@ -236,6 +237,16 @@ dialogs:
|
|||||||
desc: >-
|
desc: >-
|
||||||
Você está deletando vários objetos (<count> para ser exato)! Você quer continuar?
|
Você está deletando vários objetos (<count> para ser exato)! Você quer continuar?
|
||||||
|
|
||||||
|
massCutConfirm:
|
||||||
|
title: Confirmar corte
|
||||||
|
desc: >-
|
||||||
|
Você está cortando vários objetos (<count> para ser exato)! Você quer continuar?
|
||||||
|
|
||||||
|
massCutInsufficientConfirm:
|
||||||
|
title: Confirmar Corte
|
||||||
|
desc: >-
|
||||||
|
You can not afford to paste this area! Are you sure you want to cut it?
|
||||||
|
|
||||||
blueprintsNotUnlocked:
|
blueprintsNotUnlocked:
|
||||||
title: Não desbloqueado ainda
|
title: Não desbloqueado ainda
|
||||||
desc: >-
|
desc: >-
|
||||||
@ -252,35 +263,24 @@ dialogs:
|
|||||||
|
|
||||||
createMarker:
|
createMarker:
|
||||||
title: Nova Marcação
|
title: Nova Marcação
|
||||||
desc: Dê um nome com significado, também pode adicionar <strong>um pequeno código</strong> de uma forma. (Pode ser gerado <a href="https://viewer.shapez.io" target="_blank">aqui</a>)
|
|
||||||
titleEdit: Editar Marcador
|
titleEdit: Editar Marcador
|
||||||
|
desc: Dê um nome com significado, também pode adicionar <strong>um pequeno código</strong> de uma forma. (Pode ser gerado <a href="https://viewer.shapez.io" target="_blank">aqui</a>)
|
||||||
|
|
||||||
markerDemoLimit:
|
markerDemoLimit:
|
||||||
desc: >-
|
desc: Você só pode criar dois marcadores na versão demo. Adquira a versão completa para marcadores ilimitados!
|
||||||
Você só pode criar dois marcadores na versão demo. Adquira a versão completa para marcadores ilimitados!
|
|
||||||
|
|
||||||
massCutConfirm:
|
|
||||||
title: Confirmar corte
|
|
||||||
desc: >-
|
|
||||||
Você está cortando vários objetos (<count> para ser exato)! Você quer continuar?
|
|
||||||
|
|
||||||
exportScreenshotWarning:
|
exportScreenshotWarning:
|
||||||
title: Exportar captura de tela
|
title: Exportar captura de tela
|
||||||
desc: >-
|
desc: Você está prestes a exportar uma captura de tela da sua base. Note que isso pode ser bastante lento para uma base grande, e até mesmo pode travar o jogo!
|
||||||
Você está prestes a exportar uma captura de tela da sua base. Note que isso pode ser bastante lento para uma base grande, e até mesmo pode travar o jogo!
|
|
||||||
|
|
||||||
massCutInsufficientConfirm:
|
|
||||||
title: Confirmar Corte
|
|
||||||
desc: You can not afford to paste this area! Are you sure you want to cut it?
|
|
||||||
|
|
||||||
ingame:
|
ingame:
|
||||||
# This is shown in the top left corner and displays useful keybindings in
|
# This is shown in the top left corner and displays useful keybindings in
|
||||||
# every situation
|
# every situation
|
||||||
keybindingsOverlay:
|
keybindingsOverlay:
|
||||||
moveMap: Mover
|
moveMap: Mover
|
||||||
|
selectBuildings: Selecionar área
|
||||||
stopPlacement: Parar
|
stopPlacement: Parar
|
||||||
rotateBuilding: Rotação
|
rotateBuilding: Rotacionar
|
||||||
placeMultiple: Colocar vários
|
placeMultiple: Colocar vários
|
||||||
reverseOrientation: Inverter orientação
|
reverseOrientation: Inverter orientação
|
||||||
disableAutoOrientation: Desligar orientação automática
|
disableAutoOrientation: Desligar orientação automática
|
||||||
@ -288,17 +288,27 @@ ingame:
|
|||||||
placeBuilding: Construir objeto
|
placeBuilding: Construir objeto
|
||||||
createMarker: Criar marcador
|
createMarker: Criar marcador
|
||||||
delete: Destruir
|
delete: Destruir
|
||||||
selectBuildings: Selecionar área
|
|
||||||
pasteLastBlueprint: Colar último projeto
|
pasteLastBlueprint: Colar último projeto
|
||||||
|
|
||||||
lockBeltDirection: Ativar Planejador de Esteiras
|
lockBeltDirection: Ativar Planejador de Esteiras
|
||||||
plannerSwitchSide: Flip planner side
|
plannerSwitchSide: Girar Planejador
|
||||||
cutSelection: Cortar
|
cutSelection: Cortar
|
||||||
copySelection: Copiar
|
copySelection: Copiar
|
||||||
clearSelection: Limpar Seleção
|
clearSelection: Limpar Seleção
|
||||||
pipette: Conta-Gotas
|
pipette: Conta-Gotas
|
||||||
switchLayers: Trocar Camadas
|
switchLayers: Trocar Camadas
|
||||||
|
|
||||||
|
# Names of the colors, used for the color blind mode
|
||||||
|
colors:
|
||||||
|
red: Vermelho
|
||||||
|
green: Verde
|
||||||
|
blue: Azul
|
||||||
|
yellow: Amarelo
|
||||||
|
purple: Roxo
|
||||||
|
cyan: Ciano
|
||||||
|
white: Branco
|
||||||
|
black: Preto
|
||||||
|
uncolored: Sem cor
|
||||||
|
|
||||||
# Everything related to placing buildings (I.e. as soon as you selected a building
|
# Everything related to placing buildings (I.e. as soon as you selected a building
|
||||||
# from the toolbar)
|
# from the toolbar)
|
||||||
buildingPlacement:
|
buildingPlacement:
|
||||||
@ -324,7 +334,7 @@ ingame:
|
|||||||
levelCompleteNotification:
|
levelCompleteNotification:
|
||||||
# <level> is replaced by the actual level, so this gets 'Level 03' for example.
|
# <level> is replaced by the actual level, so this gets 'Level 03' for example.
|
||||||
levelTitle: Nível <level>
|
levelTitle: Nível <level>
|
||||||
completed: Completado
|
completed: Concluído
|
||||||
unlockText: Desbloqueado <reward>!
|
unlockText: Desbloqueado <reward>!
|
||||||
buttonNextLevel: Próximo Nível
|
buttonNextLevel: Próximo Nível
|
||||||
|
|
||||||
@ -336,13 +346,14 @@ ingame:
|
|||||||
# The "Upgrades" window
|
# The "Upgrades" window
|
||||||
shop:
|
shop:
|
||||||
title: Melhorias
|
title: Melhorias
|
||||||
buttonUnlock: Comprar
|
buttonUnlock: Melhorar
|
||||||
|
|
||||||
# Gets replaced to e.g. "Tier IX"
|
# Gets replaced to e.g. "Tier IX"
|
||||||
tier: Nível <x>
|
tier: Nível <x>
|
||||||
|
|
||||||
# The roman number for each tier
|
# The roman number for each tier
|
||||||
tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X]
|
tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X]
|
||||||
|
|
||||||
maximumLevel: NÍVEL MÁXIMO (Velocidade x<currentMult>)
|
maximumLevel: NÍVEL MÁXIMO (Velocidade x<currentMult>)
|
||||||
|
|
||||||
# The "Statistics" window
|
# The "Statistics" window
|
||||||
@ -392,6 +403,12 @@ ingame:
|
|||||||
description: Clique com o botão esquerdo do mouse em um marcador para pular, clique com o botão direito do mouse para excluí-lo. <br><br> Pressione <keybinding> para criar um marcador a partir da exibição atual ou <strong>clique com o botão direito do mouse</strong> para criar um marcador no local selecionado.
|
description: Clique com o botão esquerdo do mouse em um marcador para pular, clique com o botão direito do mouse para excluí-lo. <br><br> Pressione <keybinding> para criar um marcador a partir da exibição atual ou <strong>clique com o botão direito do mouse</strong> para criar um marcador no local selecionado.
|
||||||
creationSuccessNotification: Marcador criado.
|
creationSuccessNotification: Marcador criado.
|
||||||
|
|
||||||
|
# Shape viewer
|
||||||
|
shapeViewer:
|
||||||
|
title: Camadas
|
||||||
|
empty: Vazio
|
||||||
|
copyKey: Copiar Chave
|
||||||
|
|
||||||
# Interactive tutorial
|
# Interactive tutorial
|
||||||
interactiveTutorial:
|
interactiveTutorial:
|
||||||
title: Tutorial
|
title: Tutorial
|
||||||
@ -403,46 +420,38 @@ ingame:
|
|||||||
1_3_expand: >-
|
1_3_expand: >-
|
||||||
Este <strong>NÃO</strong> é um jogo inativo! Construa mais extratores e esteiras para concluir o objetivo mais rapidamente.<br><br>Dica, segure <strong>SHIFT</strong> para colocar vários extratores e use <strong>R</strong> para girá-los.
|
Este <strong>NÃO</strong> é um jogo inativo! Construa mais extratores e esteiras para concluir o objetivo mais rapidamente.<br><br>Dica, segure <strong>SHIFT</strong> para colocar vários extratores e use <strong>R</strong> para girá-los.
|
||||||
|
|
||||||
colors:
|
|
||||||
red: Vermelho
|
|
||||||
green: Verde
|
|
||||||
blue: Azul
|
|
||||||
yellow: Amarelo
|
|
||||||
purple: Roxo
|
|
||||||
cyan: Ciano
|
|
||||||
white: Branco
|
|
||||||
black: Preto
|
|
||||||
uncolored: Sem cor
|
|
||||||
shapeViewer:
|
|
||||||
title: Camadas
|
|
||||||
empty: Vazio
|
|
||||||
copyKey: Copiar Chave
|
|
||||||
|
|
||||||
# All shop upgrades
|
# All shop upgrades
|
||||||
shopUpgrades:
|
shopUpgrades:
|
||||||
belt:
|
belt:
|
||||||
name: Esteiras, Distribuidores e Túneis
|
name: Esteiras, Distribuidores e Túneis
|
||||||
description: Velocidade x<currentMult> → x<newMult>
|
description: Velocidade x<currentMult> → x<newMult>
|
||||||
|
|
||||||
miner:
|
miner:
|
||||||
name: Extração
|
name: Extração
|
||||||
description: Velocidade x<currentMult> → x<newMult>
|
description: Velocidade x<currentMult> → x<newMult>
|
||||||
|
|
||||||
processors:
|
processors:
|
||||||
name: Corte, Rotação & Montagem
|
name: Corte, Rotação e Montagem
|
||||||
description: Velocidade x<currentMult> → x<newMult>
|
description: Velocidade x<currentMult> → x<newMult>
|
||||||
|
|
||||||
painting:
|
painting:
|
||||||
name: Mistura & Pintura
|
name: Mistura e Pintura
|
||||||
description: Velocidade x<currentMult> → x<newMult>
|
description: Velocidade x<currentMult> → x<newMult>
|
||||||
|
|
||||||
# Buildings and their name / description
|
# Buildings and their name / description
|
||||||
buildings:
|
buildings:
|
||||||
|
hub:
|
||||||
|
deliver: Entregue
|
||||||
|
toUnlock: para desbloquear
|
||||||
|
levelShortcut: LVL
|
||||||
|
|
||||||
belt:
|
belt:
|
||||||
default:
|
default:
|
||||||
name: &belt Esteira Transportadora
|
name: &belt Esteira Transportadora
|
||||||
description: Transporta itens; mantenha pressionado e arraste para colocar vários.
|
description: Transporta itens; mantenha pressionado e arraste para colocar vários.
|
||||||
|
|
||||||
|
wire:
|
||||||
|
default:
|
||||||
|
name: &wire Fio de Energia
|
||||||
|
description: Permite transportar energia.
|
||||||
|
|
||||||
miner: # Internal name for the Extractor
|
miner: # Internal name for the Extractor
|
||||||
default:
|
default:
|
||||||
name: &miner Extrator
|
name: &miner Extrator
|
||||||
@ -482,6 +491,11 @@ buildings:
|
|||||||
name: Cortador (Quádruplo)
|
name: Cortador (Quádruplo)
|
||||||
description: Corta as formas em quatro partes. <strong>Se você usar apenas uma parte, não se esqueça de destruir as outras, ou ela irá parar a produção!</strong>
|
description: Corta as formas em quatro partes. <strong>Se você usar apenas uma parte, não se esqueça de destruir as outras, ou ela irá parar a produção!</strong>
|
||||||
|
|
||||||
|
advanced_processor:
|
||||||
|
default:
|
||||||
|
name: &advanced_processor Inversor de Cor
|
||||||
|
description: Aceita uma cor ou forma e a inverte.
|
||||||
|
|
||||||
rotater:
|
rotater:
|
||||||
default:
|
default:
|
||||||
name: &rotater Rotacionador
|
name: &rotater Rotacionador
|
||||||
@ -490,8 +504,8 @@ buildings:
|
|||||||
name: Rotacionador (Anti-horário)
|
name: Rotacionador (Anti-horário)
|
||||||
description: Gira as formas no sentido anti-horário em 90 graus.
|
description: Gira as formas no sentido anti-horário em 90 graus.
|
||||||
fl:
|
fl:
|
||||||
name: Rotate (180)
|
name: Rotacionador (180)
|
||||||
description: Rotates shapes by 180 degrees.
|
description: Gira as formas em 180 graus.
|
||||||
|
|
||||||
stacker:
|
stacker:
|
||||||
default:
|
default:
|
||||||
@ -507,16 +521,18 @@ buildings:
|
|||||||
default:
|
default:
|
||||||
name: &painter Pintor
|
name: &painter Pintor
|
||||||
description: &painter_desc Colore a forma inteira na entrada esquerda com a cor da entrada direita.
|
description: &painter_desc Colore a forma inteira na entrada esquerda com a cor da entrada direita.
|
||||||
double:
|
|
||||||
name: Pintor (Duplo)
|
|
||||||
description: Colore as duas formas na entrada esquerda com a cor da entrada direita.
|
|
||||||
quad:
|
|
||||||
name: Pintor (Quádruplo)
|
|
||||||
description: Permite colorir cada quadrante da forma com uma cor diferente.
|
|
||||||
mirrored:
|
mirrored:
|
||||||
name: *painter
|
name: *painter
|
||||||
description: *painter_desc
|
description: *painter_desc
|
||||||
|
|
||||||
|
double:
|
||||||
|
name: Pintor (Duplo)
|
||||||
|
description: Colore as formas na entrada esquerda com a cor da entrada superior.
|
||||||
|
quad:
|
||||||
|
name: Pintor (Quádruplo)
|
||||||
|
description: Permite colorir cada quadrante da forma com uma cor diferente.
|
||||||
|
|
||||||
trash:
|
trash:
|
||||||
default:
|
default:
|
||||||
name: &trash Lixo
|
name: &trash Lixo
|
||||||
@ -525,29 +541,22 @@ buildings:
|
|||||||
storage:
|
storage:
|
||||||
name: Estoque
|
name: Estoque
|
||||||
description: Armazena itens em excesso, até uma determinada capacidade. Pode ser usado como uma porta de transbordamento.
|
description: Armazena itens em excesso, até uma determinada capacidade. Pode ser usado como uma porta de transbordamento.
|
||||||
hub:
|
|
||||||
deliver: Entregue
|
|
||||||
toUnlock: para desbloquear
|
|
||||||
levelShortcut: LVL
|
|
||||||
wire:
|
|
||||||
default:
|
|
||||||
name: &wire Fio de Energia
|
|
||||||
|
|
||||||
description: Permite transportar energia.
|
|
||||||
advanced_processor:
|
|
||||||
default:
|
|
||||||
name: &advanced_processor Inversor de Cor
|
|
||||||
description: Aceita uma cor ou forma e a inverte.
|
|
||||||
energy_generator:
|
energy_generator:
|
||||||
deliver: Entregar
|
deliver: Entregar
|
||||||
|
|
||||||
|
# This will be shown before the amount, so for example 'For 123 Energy'
|
||||||
toGenerateEnergy: Para
|
toGenerateEnergy: Para
|
||||||
|
|
||||||
default:
|
default:
|
||||||
name: &energy_generator Gerador de Energia
|
name: &energy_generator Gerador de Energia
|
||||||
description: Consome formas para gerar energia.
|
description: Consome formas para gerar energia.
|
||||||
|
|
||||||
wire_crossings:
|
wire_crossings:
|
||||||
default:
|
default:
|
||||||
name: &wire_crossings Divisor de Fios
|
name: &wire_crossings Divisor de Fios
|
||||||
description: Divide um fio de energia em dois.
|
description: Divide um fio de energia em dois.
|
||||||
|
|
||||||
merger:
|
merger:
|
||||||
name: Misturador de Fios
|
name: Misturador de Fios
|
||||||
description: Une dois fios de energia em um.
|
description: Une dois fios de energia em um.
|
||||||
@ -556,7 +565,7 @@ storyRewards:
|
|||||||
# Those are the rewards gained from completing the store
|
# Those are the rewards gained from completing the store
|
||||||
reward_cutter_and_trash:
|
reward_cutter_and_trash:
|
||||||
title: Cortando formas
|
title: Cortando formas
|
||||||
desc: Voce desbloqueou <strong>cortador</strong> - corte de formas pela metade <strong>verticalmente</strong> independentemente de sua orientação!<br><br> Certifique-se de se livrar do lixo, ou então <strong> ele irá parar a produção </strong> - Para esse propósito, eu lhe dei uma lixeira, que destrói tudo o que você coloca nela!
|
desc: Você desbloqueou <strong>cortador</strong> - corte de formas pela metade <strong>verticalmente</strong> independentemente de sua orientação!<br><br> Certifique-se de se livrar do lixo, ou então <strong>ele irá parar a produção</strong> - Para esse propósito, eu lhe dei uma lixeira, que destrói tudo o que você coloca nela!
|
||||||
|
|
||||||
reward_rotater:
|
reward_rotater:
|
||||||
title: Rotação
|
title: Rotação
|
||||||
@ -597,7 +606,8 @@ storyRewards:
|
|||||||
|
|
||||||
reward_splitter_compact:
|
reward_splitter_compact:
|
||||||
title: Distribuidor compacto
|
title: Distribuidor compacto
|
||||||
desc: Você desbloqueou uma variante compacta do <strong>Distribuidor</strong> - ele aceita duas entradas e as une em uma!
|
desc: >-
|
||||||
|
Você desbloqueou uma variante compacta do <strong>Distribuidor</strong> - ele aceita duas entradas e as une em uma!
|
||||||
|
|
||||||
reward_cutter_quad:
|
reward_cutter_quad:
|
||||||
title: Cortador quádruplo
|
title: Cortador quádruplo
|
||||||
@ -637,9 +647,9 @@ storyRewards:
|
|||||||
settings:
|
settings:
|
||||||
title: opções
|
title: opções
|
||||||
categories:
|
categories:
|
||||||
general: General
|
general: Geral
|
||||||
userInterface: User Interface
|
userInterface: Interface de Usuário
|
||||||
advanced: Advanced
|
advanced: Avançado
|
||||||
|
|
||||||
versionBadges:
|
versionBadges:
|
||||||
dev: Desenvolvedor
|
dev: Desenvolvedor
|
||||||
@ -653,23 +663,58 @@ settings:
|
|||||||
description: >-
|
description: >-
|
||||||
Altera o tamanho da fonte do usuário. A interface ainda será dimensionada com base na resolução do dispositivo, mas essa configuração controla a escala do texto.
|
Altera o tamanho da fonte do usuário. A interface ainda será dimensionada com base na resolução do dispositivo, mas essa configuração controla a escala do texto.
|
||||||
scales:
|
scales:
|
||||||
super_small: Super pequeno
|
super_small: Super Pequeno
|
||||||
small: Pequeno
|
small: Pequeno
|
||||||
regular: Normal
|
regular: Normal
|
||||||
large: Grande
|
large: Grande
|
||||||
huge: Gigante
|
huge: Gigante
|
||||||
|
|
||||||
|
autosaveInterval:
|
||||||
|
title: Intervalo de gravação automática
|
||||||
|
description: >-
|
||||||
|
Controla a frequência com que o jogo salva automaticamente. Você também pode desativá-lo totalmente aqui.
|
||||||
|
|
||||||
|
intervals:
|
||||||
|
one_minute: 1 Minuto
|
||||||
|
two_minutes: 2 Minutos
|
||||||
|
five_minutes: 5 Minutos
|
||||||
|
ten_minutes: 10 Minutos
|
||||||
|
twenty_minutes: 20 Minutos
|
||||||
|
disabled: Desativado
|
||||||
|
|
||||||
scrollWheelSensitivity:
|
scrollWheelSensitivity:
|
||||||
title: Sensibilidade do zoom
|
title: Sensibilidade do zoom
|
||||||
description: >-
|
description: >-
|
||||||
Altera a sensibilidade do zoom (roda do mouse ou touchpad).
|
Altera a sensibilidade do zoom (roda do mouse ou touchpad).
|
||||||
sensitivity:
|
sensitivity:
|
||||||
super_slow: Super lento
|
super_slow: Super Lento
|
||||||
slow: Lento
|
slow: Lento
|
||||||
regular: Normal
|
regular: Normal
|
||||||
fast: Rápido
|
fast: Rápido
|
||||||
super_fast: Super Rápido
|
super_fast: Super Rápido
|
||||||
|
|
||||||
|
movementSpeed:
|
||||||
|
title: Velocidade da câmera
|
||||||
|
description: >-
|
||||||
|
Altera a velocidade com que a câmera se move com o teclado.
|
||||||
|
speeds:
|
||||||
|
super_slow: Super Lento
|
||||||
|
slow: Lento
|
||||||
|
regular: Normal
|
||||||
|
fast: Rápido
|
||||||
|
super_fast: Super Rápido
|
||||||
|
extremely_fast: Extremamente Rápido
|
||||||
|
|
||||||
|
language:
|
||||||
|
title: Idioma
|
||||||
|
description: >-
|
||||||
|
Altera o idioma. Todas as traduções são contribuições de usuários e podem estar incompletas!
|
||||||
|
|
||||||
|
enableColorBlindHelper:
|
||||||
|
title: Modo daltônico.
|
||||||
|
description: >-
|
||||||
|
Permite várias ferramentas que permitem jogar se você é daltônico.
|
||||||
|
|
||||||
fullscreen:
|
fullscreen:
|
||||||
title: Tela Cheia
|
title: Tela Cheia
|
||||||
description: >-
|
description: >-
|
||||||
@ -678,7 +723,7 @@ settings:
|
|||||||
soundsMuted:
|
soundsMuted:
|
||||||
title: Som
|
title: Som
|
||||||
description: >-
|
description: >-
|
||||||
Se ligado o jogo fica mudo
|
Se ligado, o jogo fica mudo.
|
||||||
|
|
||||||
musicMuted:
|
musicMuted:
|
||||||
title: Música
|
title: Música
|
||||||
@ -689,7 +734,6 @@ settings:
|
|||||||
title: Tema
|
title: Tema
|
||||||
description: >-
|
description: >-
|
||||||
Escolha o tema entre (Claro / Escuro).
|
Escolha o tema entre (Claro / Escuro).
|
||||||
|
|
||||||
themes:
|
themes:
|
||||||
dark: Escuro
|
dark: Escuro
|
||||||
light: Claro
|
light: Claro
|
||||||
@ -709,63 +753,30 @@ settings:
|
|||||||
description: >-
|
description: >-
|
||||||
Se ativado, oferece dicas e tutoriais enquanto se joga. Além disso, esconde certos elementos da interface até certo ponto, para facilitar o começo do jogo.
|
Se ativado, oferece dicas e tutoriais enquanto se joga. Além disso, esconde certos elementos da interface até certo ponto, para facilitar o começo do jogo.
|
||||||
|
|
||||||
language:
|
|
||||||
title: Idioma
|
|
||||||
description: >-
|
|
||||||
Altera o idioma. Todas as traduções são contribuições de usuários e podem estar incompletas!
|
|
||||||
|
|
||||||
movementSpeed:
|
|
||||||
title: Velocidade da câmera
|
|
||||||
description: Altera a velocidade com que a câmera se move com o teclado.
|
|
||||||
speeds:
|
|
||||||
super_slow: Super Lento
|
|
||||||
slow: Lento
|
|
||||||
regular: Normal
|
|
||||||
fast: Rápido
|
|
||||||
super_fast: Super Rápido
|
|
||||||
extremely_fast: Extremamente Rápido
|
|
||||||
enableTunnelSmartplace:
|
enableTunnelSmartplace:
|
||||||
title: Túneis inteligentes
|
title: Túneis inteligentes
|
||||||
description: >-
|
description: >-
|
||||||
Quando colocados, irão remover automaticamente esteiras desnecessárias.
|
Quando colocados, irão remover automaticamente esteiras desnecessárias. Isso também permite arrastar túneis e túneis em excesso serão removidos.
|
||||||
Isso também permite arrastar túneis e túneis em excesso serão removidos.
|
|
||||||
vignette:
|
vignette:
|
||||||
title: Vignette
|
title: Vinheta
|
||||||
description: >-
|
description: >-
|
||||||
Permite o modo vinheta que escurece os cantos da tela e facilita a
|
Permite o modo vinheta que escurece os cantos da tela e facilita a leitura do texto.
|
||||||
leitura do texto.
|
|
||||||
|
|
||||||
autosaveInterval:
|
|
||||||
title: Intervalo de gravação automática
|
|
||||||
description: >-
|
|
||||||
Controla a frequência com que o jogo salva automaticamente.
|
|
||||||
Você também pode desativá-lo totalmente aqui.
|
|
||||||
intervals:
|
|
||||||
one_minute: 1 Minuto
|
|
||||||
two_minutes: 2 Minutos
|
|
||||||
five_minutes: 5 Minutos
|
|
||||||
ten_minutes: 10 Minutos
|
|
||||||
twenty_minutes: 20 Minutos
|
|
||||||
disabled: Desativado
|
|
||||||
compactBuildingInfo:
|
|
||||||
title: Informações compactas sobre construções
|
|
||||||
description: >-
|
|
||||||
Reduz as caixas de informações dos construções, mostrando apenas suas proporções.
|
|
||||||
Caso contrário, uma descrição e imagem são mostradas.
|
|
||||||
disableCutDeleteWarnings:
|
|
||||||
title: Desativar avisos de recorte / exclusão
|
|
||||||
description: >-
|
|
||||||
Desative as caixas de diálogo de aviso exibidas ao cortar / excluir
|
|
||||||
mais de 100 entidades.
|
|
||||||
|
|
||||||
enableColorBlindHelper:
|
|
||||||
title: Modo daltônico.
|
|
||||||
description: Permite várias ferramentas que permitem jogar se você é daltônico.
|
|
||||||
rotationByBuilding:
|
rotationByBuilding:
|
||||||
title: Rotação por tipo de construção
|
title: Rotação por tipo de construção
|
||||||
description: >-
|
description: >-
|
||||||
Cada tipo de construção lembra a rotação que você definiu pela última vez individualmente.
|
Cada tipo de construção lembra a rotação que você definiu pela última vez individualmente. Isso pode ser mais confortável se você alternar frequentemente entre a colocação de diferentes tipos de construção.
|
||||||
Isso pode ser mais confortável se você alternar frequentemente entre a colocação de diferentes tipos de construção.
|
|
||||||
|
compactBuildingInfo:
|
||||||
|
title: Informações compactas sobre construções
|
||||||
|
description: >-
|
||||||
|
Reduz as caixas de informações dos construções, mostrando apenas suas proporções. Caso contrário, uma descrição e imagem são mostradas.
|
||||||
|
|
||||||
|
disableCutDeleteWarnings:
|
||||||
|
title: Desativar avisos de recorte / exclusão
|
||||||
|
description: >-
|
||||||
|
Desative as caixas de diálogo de aviso exibidas ao cortar / excluir mais de 100 entidades.
|
||||||
|
|
||||||
keybindings:
|
keybindings:
|
||||||
title: Controles
|
title: Controles
|
||||||
@ -790,6 +801,7 @@ keybindings:
|
|||||||
mapMoveRight: Mover para direita
|
mapMoveRight: Mover para direita
|
||||||
mapMoveDown: Mover para baixo
|
mapMoveDown: Mover para baixo
|
||||||
mapMoveLeft: Mover para a esquerda
|
mapMoveLeft: Mover para a esquerda
|
||||||
|
mapMoveFaster: Mover mais rápido
|
||||||
centerMap: Centralizar mapa
|
centerMap: Centralizar mapa
|
||||||
|
|
||||||
mapZoomIn: Aproximar
|
mapZoomIn: Aproximar
|
||||||
@ -798,12 +810,12 @@ keybindings:
|
|||||||
|
|
||||||
menuOpenShop: Melhorias
|
menuOpenShop: Melhorias
|
||||||
menuOpenStats: Estatísticas
|
menuOpenStats: Estatísticas
|
||||||
|
menuClose: Fechar Menu
|
||||||
|
|
||||||
toggleHud: Ocultar Interface
|
toggleHud: Ocultar Interface
|
||||||
toggleFPSInfo: Mostrar FPS e Debug Info
|
toggleFPSInfo: Mostrar FPS e Debug Info
|
||||||
switchLayers: Alternar Camadas
|
switchLayers: Alternar Camadas
|
||||||
exportScreenshot: Exportar Base inteira como Imagem
|
exportScreenshot: Exportar Base Inteira como Imagem
|
||||||
|
|
||||||
belt: *belt
|
belt: *belt
|
||||||
splitter: *splitter
|
splitter: *splitter
|
||||||
underground_belt: *underground_belt
|
underground_belt: *underground_belt
|
||||||
@ -824,41 +836,33 @@ keybindings:
|
|||||||
Modifier: Rotação anti-horária
|
Modifier: Rotação anti-horária
|
||||||
cycleBuildingVariants: Variações
|
cycleBuildingVariants: Variações
|
||||||
confirmMassDelete: Confirmar exclusão em massa
|
confirmMassDelete: Confirmar exclusão em massa
|
||||||
|
pasteLastBlueprint: Colar último projeto
|
||||||
cycleBuildings: Trocar de construção
|
cycleBuildings: Trocar de construção
|
||||||
|
lockBeltDirection: Ativar planejador de correia
|
||||||
|
switchDirectionLockSide: >-
|
||||||
|
Planejador: Mudar de lado
|
||||||
|
|
||||||
massSelectStart: Segure e arraste para começar
|
massSelectStart: Segure e arraste para começar
|
||||||
massSelectSelectMultiple: Selecionar mais áreas
|
massSelectSelectMultiple: Selecionar mais áreas
|
||||||
massSelectCopy: Copiar área
|
massSelectCopy: Copiar área
|
||||||
|
massSelectCut: Cortar área
|
||||||
|
|
||||||
placementDisableAutoOrientation: Desligar orientação automática
|
placementDisableAutoOrientation: Desligar orientação automática
|
||||||
placeMultiple: Permanecer no modo de construção
|
placeMultiple: Permanecer no modo de construção
|
||||||
placeInverse: Inverter orientação de esteira
|
placeInverse: Inverter orientação de esteira
|
||||||
pasteLastBlueprint: Colar último projeto
|
|
||||||
massSelectCut: Cortar área
|
|
||||||
mapMoveFaster: Mover mais rápido
|
|
||||||
lockBeltDirection: Ativar planejador de correia
|
|
||||||
switchDirectionLockSide: "Planejador: Mudar de lado"
|
|
||||||
menuClose: Fechar Menu
|
|
||||||
|
|
||||||
about:
|
about:
|
||||||
title: Sobre o jogo
|
title: Sobre o jogo
|
||||||
body: >-
|
body: >-
|
||||||
Esse jogo tem código aberto e é desenvolvido por <a href="https://github.com/tobspr"
|
Esse jogo tem código aberto e é desenvolvido por <a href="https://github.com/tobspr" target="_blank">Tobias Springer</a> (esse sou eu).<br><br>
|
||||||
target="_blank">Tobias Springer</a> (esse sou eu).<br><br>
|
|
||||||
|
|
||||||
Se quiser contribuir, confira <a href="<githublink>"
|
Se quiser contribuir, confira <a href="<githublink>" target="_blank">shapez.io no github</a>.<br><br>
|
||||||
target="_blank">shapez.io no github</a>.<br><br>
|
|
||||||
|
|
||||||
O jogo não seria possível sem a comunidade incrível do Discord sobre
|
O jogo não seria possível sem a comunidade incrível do Discord sobre os meus jogos - Junte-se à comunidade no <a href="<discordlink>" target="_blank">servidor do Discord</a>!<br><br>
|
||||||
os meus jogos - Junte-se à comunidade no <a href="<discordlink>"
|
|
||||||
target="_blank">servidor do Discord</a>!<br><br>
|
|
||||||
|
|
||||||
A trilha sonora foi feita por <a href="https://soundcloud.com/pettersumelius"
|
A trilha sonora foi feita por <a href="https://soundcloud.com/pettersumelius" target="_blank">Peppsen</a> - Ele é demais.<br><br>
|
||||||
target="_blank">Peppsen</a> - Ele é demais.<br><br>
|
|
||||||
|
|
||||||
Finalmente, agradeço muito ao meu melhor amigo
|
Finalmente, agradeço muito ao meu melhor amigo <a href="https://github.com/niklas-dahl" target="_blank">Niklas</a> - Sem nossas sessões de Factorio, esse jogo nunca teria existido.
|
||||||
<a href="https://github.com/niklas-dahl" target="_blank">Niklas</a> - Sem nossas sessões de Factorio,
|
|
||||||
esse jogo nunca teria existido.
|
|
||||||
|
|
||||||
changelog:
|
changelog:
|
||||||
title: Alterações
|
title: Alterações
|
||||||
|
@ -488,8 +488,8 @@ buildings:
|
|||||||
name: Вращатель (Обр.)
|
name: Вращатель (Обр.)
|
||||||
description: Поворачивает фигуры против часовой стрелки на 90 градусов.
|
description: Поворачивает фигуры против часовой стрелки на 90 градусов.
|
||||||
fl:
|
fl:
|
||||||
name: Rotate (180)
|
name: Вращатель (180)
|
||||||
description: Rotates shapes by 180 degrees.
|
description: Вращает фигуры на 180 градусов.
|
||||||
|
|
||||||
stacker:
|
stacker:
|
||||||
default:
|
default:
|
||||||
@ -635,9 +635,9 @@ storyRewards:
|
|||||||
settings:
|
settings:
|
||||||
title: Настройки
|
title: Настройки
|
||||||
categories:
|
categories:
|
||||||
general: General
|
general: Основные
|
||||||
userInterface: User Interface
|
userInterface: Интерфейс
|
||||||
advanced: Advanced
|
advanced: Продвинутые
|
||||||
|
|
||||||
versionBadges:
|
versionBadges:
|
||||||
dev: Разработчик
|
dev: Разработчик
|
||||||
|
@ -176,7 +176,7 @@ mainMenu:
|
|||||||
|
|
||||||
# This is shown when using firefox and other browsers which are not supported.
|
# This is shown when using firefox and other browsers which are not supported.
|
||||||
browserWarning: >-
|
browserWarning: >-
|
||||||
很抱歉, 本游戏在当前浏览器上可能运行缓慢! 使用chrome或者获取独立版以得到更好的体验。
|
很抱歉, 本游戏在当前浏览器上可能运行缓慢! 使用 Chrome 或者获取独立版以得到更好的体验。
|
||||||
|
|
||||||
savegameLevel: 第<x>关
|
savegameLevel: 第<x>关
|
||||||
savegameLevelUnknown:
|
savegameLevelUnknown:
|
||||||
@ -592,7 +592,7 @@ storyRewards:
|
|||||||
reward_painter:
|
reward_painter:
|
||||||
title: 上色
|
title: 上色
|
||||||
desc: >-
|
desc: >-
|
||||||
恭喜!你解锁了<strong>上色机</strong>。 开采一些颜色 (就像你开采图形一样) 将其在上色机中与图形结合来将图形上色!<br><br>PS: 如果你患有色盲,可以在设置中启用<strong>色盲模式</strong>!
|
恭喜!你解锁了<strong>上色机</strong>。开采一些颜色 (就像你开采图形一样) 将其在上色机中与图形结合来将图形上色!<br><br>PS:如果你患有色盲,可以在设置中启用<strong>色盲模式</strong>!
|
||||||
|
|
||||||
reward_mixer:
|
reward_mixer:
|
||||||
title: 混合颜色
|
title: 混合颜色
|
||||||
@ -612,7 +612,7 @@ storyRewards:
|
|||||||
|
|
||||||
reward_rotater_ccw:
|
reward_rotater_ccw:
|
||||||
title: 逆时针旋转
|
title: 逆时针旋转
|
||||||
desc: 恭喜!你解锁了<strong>旋转机</strong>的<strong>逆时针</strong>变体。这个变体可以逆时针旋转图形。选择旋转机然后按“T”键来选取这个变体。
|
desc: 恭喜!你解锁了<strong>旋转机</strong>的<strong>逆时针</strong>变体。这个变体可以逆时针旋转图形。选择旋转机然后按"T"键来选取这个变体。
|
||||||
|
|
||||||
reward_miner_chainable:
|
reward_miner_chainable:
|
||||||
title: 链式开采机
|
title: 链式开采机
|
||||||
@ -654,7 +654,7 @@ storyRewards:
|
|||||||
no_reward:
|
no_reward:
|
||||||
title: 下一关
|
title: 下一关
|
||||||
desc: >-
|
desc: >-
|
||||||
这一关没有奖励,但是下一关有!<br><br> PS: 你生产过的<strong>所有</strong>图形都会被用来<strong>升级建筑</strong>。
|
这一关没有奖励,但是下一关有!<br><br> PS:你生产过的<strong>所有</strong>图形都会被用来<strong>升级建筑</strong>。
|
||||||
|
|
||||||
no_reward_freeplay:
|
no_reward_freeplay:
|
||||||
title: 下一关
|
title: 下一关
|
||||||
@ -729,7 +729,7 @@ settings:
|
|||||||
refreshRate:
|
refreshRate:
|
||||||
title: 模拟频率、刷新频率
|
title: 模拟频率、刷新频率
|
||||||
description: >-
|
description: >-
|
||||||
如果你的显示器是144hz的,请在这里更改刷新频率,这样游戏可以正确地根据你的屏幕进行模拟。但是如果你的电脑性能不佳,提高刷新频率可能降低帧数。
|
如果你的显示器是 144Hz 的,请在这里更改刷新频率,这样游戏可以正确地根据你的屏幕进行模拟。但是如果你的电脑性能不佳,提高刷新频率可能降低帧数。
|
||||||
# description: >-
|
# description: >-
|
||||||
# If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates. This might actually decrease the FPS if your computer is too slow.
|
# If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates. This might actually decrease the FPS if your computer is too slow.
|
||||||
|
|
||||||
@ -799,7 +799,7 @@ settings:
|
|||||||
keybindings:
|
keybindings:
|
||||||
title: 按键设置
|
title: 按键设置
|
||||||
hint: >-
|
hint: >-
|
||||||
提示:使用CTRL、SHIFT、ALT! 这些建在放置建筑时有不同的效果。
|
提示:使用 CTRL、SHIFT、ALT!这些建在放置建筑时有不同的效果。
|
||||||
# hint: >-
|
# hint: >-
|
||||||
# Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different placement options.
|
# Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different placement options.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user