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

Wegame version & DLC Translation in Chinese

This commit is contained in:
tobspr 2021-05-25 09:19:57 +02:00
parent 65721e0837
commit b3d1204d9c
18 changed files with 332 additions and 222 deletions

1
.gitignore vendored
View File

@ -47,6 +47,7 @@ res_built
gulp/runnable-texturepacker.jar gulp/runnable-texturepacker.jar
tmp_standalone_files tmp_standalone_files
tmp_standalone_files_china tmp_standalone_files_china
tmp_standalone_files_wegame
# Local config # Local config
config.local.js config.local.js

View File

@ -139,7 +139,12 @@ gulp.task("main.webserver", () => {
); );
}); });
function serve({ standalone, chineseVersion = false }) { /**
*
* @param {object} param0
* @param {"web"|"standalone"|"china"|"wegame"} param0.version
*/
function serve({ version = "web" }) {
browserSync.init({ browserSync.init({
server: buildFolder, server: buildFolder,
port: 3005, port: 3005,
@ -163,7 +168,7 @@ function serve({ standalone, chineseVersion = false }) {
gulp.watch(["../src/**/*.scss"], gulp.series("css.dev")); gulp.watch(["../src/**/*.scss"], gulp.series("css.dev"));
// Watch .html files, those trigger a html rebuild // Watch .html files, those trigger a html rebuild
gulp.watch("../src/**/*.html", gulp.series(standalone ? "html.standalone-dev" : "html.dev")); gulp.watch("../src/**/*.html", gulp.series(version === "web" ? "html.dev" : "html.standalone-dev"));
// Watch sound files // Watch sound files
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], gulp.series("sounds.dev")); // gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], gulp.series("sounds.dev"));
@ -199,14 +204,25 @@ function serve({ standalone, chineseVersion = false }) {
return gulp.src(path).pipe(browserSync.reload({ stream: true })); return gulp.src(path).pipe(browserSync.reload({ stream: true }));
}); });
// Start the webpack watching server (Will never return) switch (version) {
if (standalone) { case "web": {
gulp.series("js.standalone-dev.watch")(() => true);
} else {
if (chineseVersion) {
gulp.series("china.js.dev.watch")(() => true);
} else {
gulp.series("js.dev.watch")(() => true); gulp.series("js.dev.watch")(() => true);
break;
}
case "standalone": {
gulp.series("js.standalone-dev.watch")(() => true);
break;
}
case "china": {
gulp.series("china.js.dev.watch")(() => true);
break;
}
case "wegame": {
gulp.series("wegame.js.dev.watch")(() => true);
break;
}
default: {
throw new Error("Unknown version " + version);
} }
} }
} }
@ -294,7 +310,7 @@ gulp.task(
// Builds everything (standalone-prod) // Builds everything (standalone-prod)
for (const prefix of ["", "china."]) { for (const prefix of ["", "china.", "wegame."]) {
gulp.task( gulp.task(
prefix + "step.standalone-prod.code", prefix + "step.standalone-prod.code",
gulp.series("sounds.fullbuildHQ", "translations.fullBuild", prefix + "js.standalone-prod") gulp.series("sounds.fullbuildHQ", "translations.fullBuild", prefix + "js.standalone-prod")
@ -327,25 +343,41 @@ gulp.task(
); );
gulp.task("main.deploy.prod", gulp.series("utils.requireCleanWorkingTree", "build.prod", "ftp.upload.prod")); gulp.task("main.deploy.prod", gulp.series("utils.requireCleanWorkingTree", "build.prod", "ftp.upload.prod"));
gulp.task("main.deploy.all", gulp.series("main.deploy.staging", "main.deploy.prod")); gulp.task("main.deploy.all", gulp.series("main.deploy.staging", "main.deploy.prod"));
// steam
gulp.task("regular.main.standalone", gulp.series("build.standalone-prod", "standalone.package.prod")); gulp.task("regular.main.standalone", gulp.series("build.standalone-prod", "standalone.package.prod"));
// china
gulp.task( gulp.task(
"china.main.standalone", "china.main.standalone",
gulp.series("china.build.standalone-prod", "china.standalone.package.prod") gulp.series("china.build.standalone-prod", "china.standalone.package.prod")
); );
gulp.task("standalone.all", gulp.series("regular.main.standalone", "china.main.standalone"));
// wegame
gulp.task(
"wegame.main.standalone",
gulp.series("wegame.build.standalone-prod", "wegame.standalone.package.prod")
);
// all (except wegame)
gulp.task("standalone.all", gulp.series("regular.main.standalone", "wegame.main.standalone"));
// Live-development // Live-development
gulp.task( gulp.task(
"main.serveDev", "main.serveDev",
gulp.series("build.dev", () => serve({ standalone: false })) gulp.series("build.dev", () => serve({ version: "web" }))
); );
gulp.task( gulp.task(
"main.serveStandalone", "main.serveStandalone",
gulp.series("build.standalone.dev", () => serve({ standalone: true })) gulp.series("build.standalone.dev", () => serve({ version: "standalone" }))
); );
gulp.task( gulp.task(
"china.main.serveDev", "china.main.serveDev",
gulp.series("build.dev", () => serve({ standalone: false, chineseVersion: true })) gulp.series("build.dev", () => serve({ version: "china" }))
);
gulp.task(
"wegame.main.serveDev",
gulp.series("build.dev", () => serve({ version: "wegame" }))
); );
gulp.task("default", gulp.series("main.serveDev")); gulp.task("default", gulp.series("main.serveDev"));

View File

@ -59,6 +59,36 @@ function gulptasksJS($, gulp, buildFolder, browserSync) {
.pipe(gulp.dest(buildFolder)); .pipe(gulp.dest(buildFolder));
}); });
//// DEV WEGAME
gulp.task("wegame.js.dev.watch", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
watch: true,
wegameVersion: true,
})
)
)
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
gulp.task("wegame.js.dev", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.config.js")({
wegameVersion: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
//// STAGING //// STAGING
gulp.task("js.staging.transpiled", () => { gulp.task("js.staging.transpiled", () => {
@ -208,6 +238,23 @@ function gulptasksJS($, gulp, buildFolder, browserSync) {
) )
.pipe(gulp.dest(buildFolder)); .pipe(gulp.dest(buildFolder));
}); });
gulp.task("wegame.js.standalone-prod", () => {
return gulp
.src("../src/js/main.js")
.pipe(
$.webpackStream(
requireUncached("./webpack.production.config.js")({
enableAssert: false,
environment: "prod",
es6: true,
standalone: true,
wegameVersion: true,
})
)
)
.pipe(gulp.dest(buildFolder));
});
} }
module.exports = { module.exports = {

View File

@ -21,6 +21,11 @@ function gulptasksStandalone($, gulp) {
suffix: "china", suffix: "china",
taskPrefix: "china.", taskPrefix: "china.",
}, },
{
tempDestDir: path.join(__dirname, "..", "tmp_standalone_files_wegame"),
suffix: "wegame",
taskPrefix: "wegame.",
},
]; ];
for (const { tempDestDir, suffix, taskPrefix } of targets) { for (const { tempDestDir, suffix, taskPrefix } of targets) {

View File

@ -6,7 +6,7 @@ const { getRevision, getVersion, getAllResourceImages } = require("./buildutils"
const lzString = require("lz-string"); const lzString = require("lz-string");
const CircularDependencyPlugin = require("circular-dependency-plugin"); const CircularDependencyPlugin = require("circular-dependency-plugin");
module.exports = ({ watch = false, standalone = false, chineseVersion = false }) => { module.exports = ({ watch = false, standalone = false, chineseVersion = false, wegameVersion = false }) => {
return { return {
mode: "development", mode: "development",
devtool: "cheap-source-map", devtool: "cheap-source-map",
@ -35,6 +35,7 @@ module.exports = ({ watch = false, standalone = false, chineseVersion = false })
lzString.compressToEncodedURIComponent("http://localhost:10005/v1") lzString.compressToEncodedURIComponent("http://localhost:10005/v1")
), ),
G_CHINA_VERSION: JSON.stringify(chineseVersion), G_CHINA_VERSION: JSON.stringify(chineseVersion),
G_WEGAME_VERSION: JSON.stringify(wegameVersion),
G_IS_DEV: "true", G_IS_DEV: "true",
G_IS_RELEASE: "false", G_IS_RELEASE: "false",
G_IS_MOBILE_APP: "false", G_IS_MOBILE_APP: "false",

View File

@ -17,6 +17,7 @@ module.exports = ({
isBrowser = true, isBrowser = true,
mobileApp = false, mobileApp = false,
chineseVersion = false, chineseVersion = false,
wegameVersion = false,
}) => { }) => {
const globalDefs = { const globalDefs = {
assert: enableAssert ? "window.assert" : "false && window.assert", assert: enableAssert ? "window.assert" : "false && window.assert",
@ -25,6 +26,7 @@ module.exports = ({
G_IS_DEV: "false", G_IS_DEV: "false",
G_CHINA_VERSION: JSON.stringify(chineseVersion), G_CHINA_VERSION: JSON.stringify(chineseVersion),
G_WEGAME_VERSION: JSON.stringify(wegameVersion),
G_IS_RELEASE: environment === "prod" ? "true" : "false", G_IS_RELEASE: environment === "prod" ? "true" : "false",
G_IS_STANDALONE: standalone ? "true" : "false", G_IS_STANDALONE: standalone ? "true" : "false",
G_IS_BROWSER: isBrowser ? "true" : "false", G_IS_BROWSER: isBrowser ? "true" : "false",

BIN
res/logo_wegame.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -12,8 +12,13 @@ import { cachebust } from "./cachebust";
const logger = createLogger("background_loader"); const logger = createLogger("background_loader");
export function getLogoSprite() {
// @todo: ugh, in a hurry
return G_WEGAME_VERSION ? "logo_wegame.png" : G_CHINA_VERSION ? "logo_cn.png" : "logo.png";
}
const essentialMainMenuSprites = [ const essentialMainMenuSprites = [
G_CHINA_VERSION ? "logo_cn.png" : "logo.png", getLogoSprite(),
...G_ALL_UI_IMAGES.filter(src => src.startsWith("ui/") && src.indexOf(".gif") < 0), ...G_ALL_UI_IMAGES.filter(src => src.startsWith("ui/") && src.indexOf(".gif") < 0),
]; ];
const essentialMainMenuSounds = [ const essentialMainMenuSounds = [

View File

@ -66,6 +66,8 @@ const preparementShape = "CpRpCp--:SwSwSwSw";
// Tiers need % of the previous tier as requirement too // Tiers need % of the previous tier as requirement too
const tierGrowth = 2.5; const tierGrowth = 2.5;
const chinaShapes = G_WEGAME_VERSION || G_CHINA_VERSION;
/** /**
* Generates all upgrades * Generates all upgrades
* @returns {Object<string, UpgradeTiers>} */ * @returns {Object<string, UpgradeTiers>} */
@ -144,7 +146,7 @@ function generateUpgrades(limitedVersion = false) {
{ {
required: [ required: [
{ {
shape: G_CHINA_VERSION shape: chinaShapes
? "CyCyCyCy:CyCyCyCy:RyRyRyRy:RuRuRuRu" ? "CyCyCyCy:CyCyCyCy:RyRyRyRy:RuRuRuRu"
: "CbRbRbCb:CwCwCwCw:WbWbWbWb", : "CbRbRbCb:CwCwCwCw:WbWbWbWb",
amount: 50000, amount: 50000,
@ -205,7 +207,7 @@ function generateUpgrades(limitedVersion = false) {
{ {
required: [ required: [
{ {
shape: G_CHINA_VERSION ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw", shape: chinaShapes ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw",
amount: 6500, amount: 6500,
}, },
], ],
@ -382,7 +384,7 @@ export function generateLevelDefinitions(limitedVersion = false) {
// 13 // 13
// Tunnel Tier 2 // Tunnel Tier 2
{ {
shape: G_CHINA_VERSION ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw", // painting t3 shape: chinaShapes ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw", // painting t3
required: 3800, required: 3800,
reward: enumHubGoalRewards.reward_underground_belt_tier_2, reward: enumHubGoalRewards.reward_underground_belt_tier_2,
}, },
@ -391,7 +393,7 @@ export function generateLevelDefinitions(limitedVersion = false) {
...(limitedVersion ...(limitedVersion
? [ ? [
{ {
shape: G_CHINA_VERSION ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw", shape: chinaShapes ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw",
required: 0, required: 0,
reward: enumHubGoalRewards.reward_demo_end, reward: enumHubGoalRewards.reward_demo_end,
}, },
@ -425,7 +427,7 @@ export function generateLevelDefinitions(limitedVersion = false) {
// 17 // 17
// Double painter // Double painter
{ {
shape: G_CHINA_VERSION shape: chinaShapes
? "CyCyCyCy:CyCyCyCy:RyRyRyRy:RuRuRuRu" ? "CyCyCyCy:CyCyCyCy:RyRyRyRy:RuRuRuRu"
: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants) : "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
required: 20000, required: 20000,
@ -467,7 +469,7 @@ export function generateLevelDefinitions(limitedVersion = false) {
// 22 // 22
// Constant signal // Constant signal
{ {
shape: G_CHINA_VERSION shape: chinaShapes
? "RrSySrSy:RyCrCwCr:CyCyRyCy" ? "RrSySrSy:RyCrCwCr:CyCyRyCy"
: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy", : "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
required: 25000, required: 25000,
@ -477,7 +479,7 @@ export function generateLevelDefinitions(limitedVersion = false) {
// 23 // 23
// Display // Display
{ {
shape: G_CHINA_VERSION shape: chinaShapes
? "CrCrCrCr:CwCwCwCw:WwWwWwWw:CrCrCrCr" ? "CrCrCrCr:CwCwCwCw:WwWwWwWw:CrCrCrCr"
: "CcSyCcSy:SyCcSyCc:CcSyCcSy", : "CcSyCcSy:SyCcSyCc:CcSyCcSy",
required: 25000, required: 25000,
@ -486,7 +488,7 @@ export function generateLevelDefinitions(limitedVersion = false) {
// 24 Logic gates // 24 Logic gates
{ {
shape: G_CHINA_VERSION shape: chinaShapes
? "Su----Su:RwRwRwRw:Cu----Cu:CwCwCwCw" ? "Su----Su:RwRwRwRw:Cu----Cu:CwCwCwCw"
: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy", : "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
required: 25000, required: 25000,

1
src/js/globals.d.ts vendored
View File

@ -20,6 +20,7 @@ declare const G_ALL_UI_IMAGES: Array<string>;
declare const G_IS_RELEASE: boolean; declare const G_IS_RELEASE: boolean;
declare const G_CHINA_VERSION: boolean; declare const G_CHINA_VERSION: boolean;
declare const G_WEGAME_VERSION: boolean;
// Polyfills // Polyfills
declare interface String { declare interface String {

View File

@ -101,7 +101,10 @@ export class ClientAPI {
*/ */
apiTryLogin() { apiTryLogin() {
if (!G_IS_STANDALONE) { if (!G_IS_STANDALONE) {
return Promise.reject("Not possible outside of standalone."); const token = window.prompt(
"Please enter the auth token for the puzzle DLC (If you have none, you can't login):"
);
return Promise.resolve({ token });
} }
const renderer = getIPCRenderer(); const renderer = getIPCRenderer();

View File

@ -53,6 +53,10 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
initialize() { initialize() {
this.syncKey = null; this.syncKey = null;
if (G_WEGAME_VERSION) {
return;
}
setInterval(() => this.sendTimePoints(), 60 * 1000); setInterval(() => this.sendTimePoints(), 60 * 1000);
// Retrieve sync key from player // Retrieve sync key from player
@ -136,6 +140,10 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
* @param {string} value * @param {string} value
*/ */
sendGameEvent(category, value) { sendGameEvent(category, value) {
if (G_WEGAME_VERSION) {
return;
}
if (!this.syncKey) { if (!this.syncKey) {
logger.warn("Can not send event due to missing sync key"); logger.warn("Can not send event due to missing sync key");
return; return;

View File

@ -2,6 +2,7 @@ import { TextualGameState } from "../core/textual_game_state";
import { T } from "../translations"; import { T } from "../translations";
import { THIRDPARTY_URLS } from "../core/config"; import { THIRDPARTY_URLS } from "../core/config";
import { cachebust } from "../core/cachebust"; import { cachebust } from "../core/cachebust";
import { getLogoSprite } from "../core/background_resources_loader";
export class AboutState extends TextualGameState { export class AboutState extends TextualGameState {
constructor() { constructor() {
@ -15,9 +16,7 @@ export class AboutState extends TextualGameState {
getMainContentHTML() { getMainContentHTML() {
return ` return `
<div class="head"> <div class="head">
<img src="${cachebust( <img src="${cachebust("res/" + getLogoSprite())}" alt="shapez.io Logo">
G_CHINA_VERSION ? "res/logo_cn.png" : "res/logo.png"
)}" alt="shapez.io Logo">
</div> </div>
<div class="text"> <div class="text">
${T.about.body ${T.about.body

View File

@ -1,3 +1,4 @@
import { getLogoSprite } from "../core/background_resources_loader";
import { cachebust } from "../core/cachebust"; import { cachebust } from "../core/cachebust";
import { A_B_TESTING_LINK_TYPE, globalConfig, THIRDPARTY_URLS } from "../core/config"; import { A_B_TESTING_LINK_TYPE, globalConfig, THIRDPARTY_URLS } from "../core/config";
import { GameState } from "../core/game_state"; import { GameState } from "../core/game_state";
@ -49,7 +50,7 @@ export class MainMenuState extends GameState {
return ` return `
<div class="topButtons"> <div class="topButtons">
${ ${
G_CHINA_VERSION G_CHINA_VERSION || G_WEGAME_VERSION
? "" ? ""
: `<button class="languageChoose" data-languageicon="${this.app.settings.getLanguage()}"></button>` : `<button class="languageChoose" data-languageicon="${this.app.settings.getLanguage()}"></button>`
} }
@ -69,10 +70,12 @@ export class MainMenuState extends GameState {
</video> </video>
<div class="logo"> <div class="logo">
<img src="${cachebust( <img src="${cachebust("res/" + getLogoSprite())}" alt="shapez.io Logo">
G_CHINA_VERSION ? "res/logo_cn.png" : "res/logo.png" ${
)}" alt="shapez.io Logo"> G_WEGAME_VERSION
<span class="updateLabel">v${G_BUILD_VERSION} - Puzzle DLC!</span> ? ""
: `<span class="updateLabel">v${G_BUILD_VERSION} - Puzzle DLC!</span>`
}
</div> </div>
<div class="mainWrapper ${showDemoBadges ? "demo" : "noDemo"}" data-columns="${ <div class="mainWrapper ${showDemoBadges ? "demo" : "noDemo"}" data-columns="${
@ -92,7 +95,7 @@ export class MainMenuState extends GameState {
</div> </div>
${ ${
(G_IS_STANDALONE && puzzleDlc) || G_IS_DEV !G_WEGAME_VERSION && ((G_IS_STANDALONE && puzzleDlc) || G_IS_DEV)
? ` ? `
<div class="puzzleContainer"> <div class="puzzleContainer">
<img class="dlcLogo" src="${cachebust( <img class="dlcLogo" src="${cachebust(
@ -104,7 +107,7 @@ export class MainMenuState extends GameState {
} }
${ ${
G_IS_STANDALONE && !puzzleDlc !G_WEGAME_VERSION && G_IS_STANDALONE && !puzzleDlc
? ` ? `
<div class="puzzleContainer notOwned"> <div class="puzzleContainer notOwned">
<img class="dlcLogo" src="${cachebust( <img class="dlcLogo" src="${cachebust(
@ -119,7 +122,11 @@ export class MainMenuState extends GameState {
} }
</div> </div>
<div class="footer ${G_CHINA_VERSION ? "china" : ""}"> ${
G_WEGAME_VERSION
? "<div class='footer wegame'></div>"
: `
<div class="footer ${G_CHINA_VERSION ? "china" : ""} ">
${ ${
G_CHINA_VERSION G_CHINA_VERSION
@ -150,6 +157,8 @@ export class MainMenuState extends GameState {
'<a class="producerLink" target="_blank">Tobias Springer</a>' '<a class="producerLink" target="_blank">Tobias Springer</a>'
)}</div> )}</div>
</div> </div>
`
}
`; `;
} }
@ -263,7 +272,7 @@ export class MainMenuState extends GameState {
this.trackClicks(qs(".settingsButton"), this.onSettingsButtonClicked); this.trackClicks(qs(".settingsButton"), this.onSettingsButtonClicked);
if (!G_CHINA_VERSION) { if (!G_CHINA_VERSION && !G_WEGAME_VERSION) {
this.trackClicks(qs(".languageChoose"), this.onLanguageChooseClicked); this.trackClicks(qs(".languageChoose"), this.onLanguageChooseClicked);
this.trackClicks(qs(".redditLink"), this.onRedditClicked); this.trackClicks(qs(".redditLink"), this.onRedditClicked);
this.trackClicks(qs(".changelog"), this.onChangelogClicked); this.trackClicks(qs(".changelog"), this.onChangelogClicked);
@ -283,14 +292,16 @@ export class MainMenuState extends GameState {
} }
const discordLink = this.htmlElement.querySelector(".discordLink"); const discordLink = this.htmlElement.querySelector(".discordLink");
this.trackClicks( if (discordLink) {
discordLink, this.trackClicks(
() => { discordLink,
this.app.analytics.trackUiClick("main_menu_link_discord"); () => {
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.discord); this.app.analytics.trackUiClick("main_menu_link_discord");
}, this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.discord);
{ preventClick: true } },
); { preventClick: true }
);
}
const githubLink = this.htmlElement.querySelector(".githubLink"); const githubLink = this.htmlElement.querySelector(".githubLink");
if (githubLink) { if (githubLink) {
@ -305,9 +316,15 @@ export class MainMenuState extends GameState {
} }
const producerLink = this.htmlElement.querySelector(".producerLink"); const producerLink = this.htmlElement.querySelector(".producerLink");
this.trackClicks(producerLink, () => this.app.platformWrapper.openExternalLink("https://tobspr.io"), { if (producerLink) {
preventClick: true, this.trackClicks(
}); producerLink,
() => this.app.platformWrapper.openExternalLink("https://tobspr.io"),
{
preventClick: true,
}
);
}
const puzzleModeButton = qs(".puzzleDlcPlayButton"); const puzzleModeButton = qs(".puzzleDlcPlayButton");
if (puzzleModeButton) { if (puzzleModeButton) {

View File

@ -1,6 +1,7 @@
import { GameState } from "../core/game_state"; import { GameState } from "../core/game_state";
import { cachebust } from "../core/cachebust"; import { cachebust } from "../core/cachebust";
import { THIRDPARTY_URLS } from "../core/config"; import { THIRDPARTY_URLS } from "../core/config";
import { getLogoSprite } from "../core/background_resources_loader";
export class MobileWarningState extends GameState { export class MobileWarningState extends GameState {
constructor() { constructor() {
@ -10,9 +11,7 @@ export class MobileWarningState extends GameState {
getInnerHTML() { getInnerHTML() {
return ` return `
<img class="logo" src="${cachebust( <img class="logo" src="${cachebust("res/" + getLogoSprite())}" alt="shapez.io Logo">
G_CHINA_VERSION ? "res/logo_cn.png" : "res/logo.png"
)}" alt="shapez.io Logo">
<p> <p>
I'm sorry, but shapez.io is not available on mobile devices yet! I'm sorry, but shapez.io is not available on mobile devices yet!

View File

@ -1,4 +1,5 @@
import { CHANGELOG } from "../changelog"; import { CHANGELOG } from "../changelog";
import { getLogoSprite } from "../core/background_resources_loader";
import { cachebust } from "../core/cachebust"; import { cachebust } from "../core/cachebust";
import { globalConfig } from "../core/config"; import { globalConfig } from "../core/config";
import { GameState } from "../core/game_state"; import { GameState } from "../core/game_state";
@ -19,7 +20,7 @@ export class PreloadState extends GameState {
return ` return `
<div class="loadingImage"></div> <div class="loadingImage"></div>
<div class="loadingStatus"> <div class="loadingStatus">
<span class="desc">${G_CHINA_VERSION ? "加载中" : "Booting"}</span> <span class="desc">${G_CHINA_VERSION || G_WEGAME_VERSION ? "加载中" : "Booting"}</span>
</div> </div>
</div> </div>
<span class="prefab_GameHint"></span> <span class="prefab_GameHint"></span>
@ -112,7 +113,7 @@ export class PreloadState extends GameState {
.then(() => this.setStatus("Initializing language")) .then(() => this.setStatus("Initializing language"))
.then(() => { .then(() => {
if (G_CHINA_VERSION) { if (G_CHINA_VERSION || G_WEGAME_VERSION) {
return this.app.settings.updateLanguage("zh-CN"); return this.app.settings.updateLanguage("zh-CN");
} }
@ -164,7 +165,7 @@ export class PreloadState extends GameState {
return; return;
} }
if (G_CHINA_VERSION) { if (G_CHINA_VERSION || G_WEGAME_VERSION) {
return; return;
} }
@ -227,7 +228,7 @@ export class PreloadState extends GameState {
} }
update() { update() {
if (G_CHINA_VERSION) { if (G_CHINA_VERSION || G_WEGAME_VERSION) {
return; return;
} }
const now = performance.now(); const now = performance.now();
@ -260,7 +261,7 @@ export class PreloadState extends GameState {
*/ */
setStatus(text) { setStatus(text) {
logger.log("✅ " + text); logger.log("✅ " + text);
if (G_CHINA_VERSION) { if (G_CHINA_VERSION || G_WEGAME_VERSION) {
return Promise.resolve(); return Promise.resolve();
} }
this.currentStatus = text; this.currentStatus = text;
@ -278,9 +279,7 @@ export class PreloadState extends GameState {
subElement.innerHTML = ` subElement.innerHTML = `
<div class="logo"> <div class="logo">
<img src="${cachebust( <img src="${cachebust("res/" + getLogoSprite())}" alt="Shapez.io Logo">
G_CHINA_VERSION ? "res/logo_cn.png" : "res/logo.png"
)}" alt="Shapez.io Logo">
</div> </div>
<div class="failureInner"> <div class="failureInner">
<div class="errorHeader"> <div class="errorHeader">

View File

@ -30,7 +30,7 @@ export class SettingsState extends TextualGameState {
<div class="other"> <div class="other">
${ ${
G_CHINA_VERSION G_CHINA_VERSION || G_WEGAME_VERSION
? "" ? ""
: ` : `
<button class="styledButton about">${T.about.title}</button> <button class="styledButton about">${T.about.title}</button>
@ -74,7 +74,7 @@ export class SettingsState extends TextualGameState {
for (let i = 0; i < allApplicationSettings.length; ++i) { for (let i = 0; i < allApplicationSettings.length; ++i) {
const setting = allApplicationSettings[i]; const setting = allApplicationSettings[i];
if (G_CHINA_VERSION && setting.id === "language") { if ((G_CHINA_VERSION || G_WEGAME_VERSION) && setting.id === "language") {
continue; continue;
} }
@ -105,7 +105,7 @@ export class SettingsState extends TextualGameState {
onEnter(payload) { onEnter(payload) {
this.renderBuildText(); this.renderBuildText();
if (!G_CHINA_VERSION) { if (!G_CHINA_VERSION && !G_WEGAME_VERSION) {
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, { this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
preventDefault: false, preventDefault: false,
}); });
@ -144,7 +144,7 @@ export class SettingsState extends TextualGameState {
initSettings() { initSettings() {
allApplicationSettings.forEach(setting => { allApplicationSettings.forEach(setting => {
if (G_CHINA_VERSION && setting.id === "language") { if ((G_CHINA_VERSION || G_WEGAME_VERSION) && setting.id === "language") {
return; return;
} }

View File

@ -68,11 +68,10 @@ mainMenu:
madeBy: 作者:<author-link> madeBy: 作者:<author-link>
subreddit: Reddit subreddit: Reddit
savegameUnnamed: 存档未命名 savegameUnnamed: 存档未命名
puzzleMode: Puzzle Mode puzzleMode: 谜题模式
back: Back back: 返回
puzzleDlcText: Do you enjoy compacting and optimizing factories? Get the Puzzle puzzleDlcText: 持续优化追求极致效率。在限定空间内使用有限的设施来创造图形《异形工厂》Shapez.io的首个DLC“谜题挑战者”将会给大家带来更烧脑、更自由的全新挑战
DLC now on Steam for even more fun! puzzleDlcWishlist: 添加愿望单!
puzzleDlcWishlist: Wishlist now!
dialogs: dialogs:
buttons: buttons:
ok: 确认 ok: 确认
@ -86,9 +85,9 @@ dialogs:
viewUpdate: 查看更新 viewUpdate: 查看更新
showUpgrades: 显示设施升级 showUpgrades: 显示设施升级
showKeybindings: 显示按键设置 showKeybindings: 显示按键设置
retry: Retry retry: 重试
continue: Continue continue: 继续
playOffline: Play Offline playOffline: 离线游戏
importSavegameError: importSavegameError:
title: 读取错误 title: 读取错误
text: 未能读取您的存档: text: 未能读取您的存档:
@ -136,13 +135,15 @@ dialogs:
desc: 您还没有解锁蓝图功能通过第12关的挑战后可解锁蓝图。 desc: 您还没有解锁蓝图功能通过第12关的挑战后可解锁蓝图。
keybindingsIntroduction: keybindingsIntroduction:
title: 实用快捷键 title: 实用快捷键
desc: "这个游戏有很多有用的快捷键设定。 以下是其中的一些介绍,记得在<strong>按键设置</strong>中查看其他按键设定!<br><br> desc:
"这个游戏有很多有用的快捷键设定。 以下是其中的一些介绍,记得在<strong>按键设置</strong>中查看其他按键设定!<br><br>
<code class='keybinding'>CTRL键</code> + 拖动:选择区域以复制或删除。<br> <code <code class='keybinding'>CTRL键</code> + 拖动:选择区域以复制或删除。<br> <code
class='keybinding'>SHIFT键</code>: 按住以放置多个同一种设施。<br> <code class='keybinding'>SHIFT键</code>: 按住以放置多个同一种设施。<br> <code
class='keybinding'>ALT键</code>: 反向放置传送带。<br>" class='keybinding'>ALT键</code>: 反向放置传送带。<br>"
createMarker: createMarker:
title: 创建地图标记 title: 创建地图标记
desc: 填写一个有意义的名称, 还可以同时包含一个形状的 <strong>短代码</strong> (您可以 <link>点击这里</link> desc:
填写一个有意义的名称, 还可以同时包含一个形状的 <strong>短代码</strong> (您可以 <link>点击这里</link>
生成短代码) 生成短代码)
titleEdit: 编辑地图标记 titleEdit: 编辑地图标记
markerDemoLimit: markerDemoLimit:
@ -170,66 +171,59 @@ dialogs:
title: 教程 title: 教程
desc: 这个关卡有英语版本的视频攻略! 您想查看这个视频攻略吗?? desc: 这个关卡有英语版本的视频攻略! 您想查看这个视频攻略吗??
editConstantProducer: editConstantProducer:
title: Set Item title: 设置项目
puzzleLoadFailed: puzzleLoadFailed:
title: Puzzles failed to load title: 谜题载入失败
desc: "Unfortunately the puzzles could not be loaded:" desc: "很遗憾,谜题未能载入:"
submitPuzzle: submitPuzzle:
title: Submit Puzzle title: 提交谜题
descName: "Give your puzzle a name:" descName: "给您的谜题设定名称:"
descIcon: "Please enter a unique short key, which will be shown as the icon of descIcon:
your puzzle (You can generate them <link>here</link>, or choose one "请输入唯一的短代码,它将显示为标志您的谜题的图标( <link>在此</link>生成,或者从以下随机推荐的图形中选择一个):
of the randomly suggested shapes below):" "
placeholderName: Puzzle Title placeholderName: 谜题标题
puzzleResizeBadBuildings: puzzleResizeBadBuildings:
title: Resize not possible title: 无法调整大小
desc: You can't make the zone any smaller, because then some buildings would be desc: 您无法使这块区域变得更小,否则有些设施将会超出区域范围。
outside the zone.
puzzleLoadError: puzzleLoadError:
title: Bad Puzzle title: 谜题出错
desc: "The puzzle failed to load:" desc: "谜题载入失败:"
offlineMode: offlineMode:
title: Offline Mode title: 离线模式
desc: We couldn't reach the servers, so the game has to run in offline mode. desc: 访问服务器失败,游戏只能在离线模式下进行。请确认您的网络连接正常。
Please make sure you have an active internect connection.
puzzleDownloadError: puzzleDownloadError:
title: Download Error title: 下载出错
desc: "Failed to download the puzzle:" desc: "无法下载谜题:"
puzzleSubmitError: puzzleSubmitError:
title: Submission Error title: 提交出错
desc: "Failed to submit your puzzle:" desc: "无法提交您的谜题:"
puzzleSubmitOk: puzzleSubmitOk:
title: Puzzle Published title: 谜题已发布
desc: Congratulations! Your puzzle has been published and can now be played by desc: 恭喜!您所创造的谜题已成功发布,别的玩家已经可以对您的谜题发起挑战!您可以在"我的谜题"部分找到您发布的谜题。
others. You can now find it in the "My puzzles" section.
puzzleCreateOffline: puzzleCreateOffline:
title: Offline Mode title: 离线模式
desc: Since you are offline, you will not be able to save and/or publish your desc: 由于您现在没有连接互联网,所以您将无法保存或发布您的谜题。是否仍要继续?
puzzle. Would you still like to continue?
puzzlePlayRegularRecommendation: puzzlePlayRegularRecommendation:
title: Recommendation title: 游戏建议
desc: I <strong>strongly</strong> recommend playing the normal game to level 12 desc: <strong>强烈</strong>建议您在至少完成本体第12关后再尝试体验“谜题挑战者”DLC否则您可能在游戏过程中遇到困难您是否仍要继续
before attempting the puzzle DLC, otherwise you may encounter
mechanics not yet introduced. Do you still want to continue?
puzzleShare: puzzleShare:
title: Short Key Copied title: 短代码已复制
desc: The short key of the puzzle (<key>) has been copied to your clipboard! It desc: 此谜题的短代码(<key>)已经复制到了您的剪贴板!您可以在谜题菜单中输入短代码以快速访问对应谜题。
can be entered in the puzzle menu to access the puzzle.
puzzleReport: puzzleReport:
title: Report Puzzle title: 上报谜题
options: options:
profane: Profane profane: 污言秽语
unsolvable: Not solvable unsolvable: 无法完成
trolling: Trolling trolling: Trolling
puzzleReportComplete: puzzleReportComplete:
title: Thank you for your feedback! title: 感谢您的反馈!
desc: The puzzle has been flagged. desc: 此谜题已标记!
puzzleReportError: puzzleReportError:
title: Failed to report title: 上报失败
desc: "Your report could not get processed:" desc: "无法处理您的上报:"
puzzleLoadShortKey: puzzleLoadShortKey:
title: Enter short key title: 输入短代码
desc: Enter the short key of the puzzle to load it. desc: 输入此谜题的短代码以载入。
ingame: ingame:
keybindingsOverlay: keybindingsOverlay:
moveMap: 移动地图 moveMap: 移动地图
@ -251,7 +245,7 @@ ingame:
clearSelection: 取消选择 clearSelection: 取消选择
pipette: 吸取器 pipette: 吸取器
switchLayers: 切换层 switchLayers: 切换层
clearBelts: Clear belts clearBelts: 清除传送带
buildingPlacement: buildingPlacement:
cycleBuildingVariants: 按 <key> 键以选择设施的变型体。 cycleBuildingVariants: 按 <key> 键以选择设施的变型体。
hotkeyLabel: "快捷键: <key>" hotkeyLabel: "快捷键: <key>"
@ -315,15 +309,18 @@ ingame:
hints: hints:
1_1_extractor: 在<strong>圆形</strong>上放置一个<strong>开采器</strong>来获取圆形!<br><br>提示:<strong>按下鼠标左键</strong>选中<strong>开采器</strong> 1_1_extractor: 在<strong>圆形</strong>上放置一个<strong>开采器</strong>来获取圆形!<br><br>提示:<strong>按下鼠标左键</strong>选中<strong>开采器</strong>
1_2_conveyor: 用<strong>传送带</strong>将您的开采器连接到中心基地上!<br><br>提示:选中<strong>传送带</strong>后<strong>按下鼠标左键可拖动</strong>布置传送带! 1_2_conveyor: 用<strong>传送带</strong>将您的开采器连接到中心基地上!<br><br>提示:选中<strong>传送带</strong>后<strong>按下鼠标左键可拖动</strong>布置传送带!
1_3_expand: 您可以放置更多的<strong>开采器</strong>和<strong>传送带</strong>来更有效率地完成关卡目标。<br><br> 1_3_expand:
您可以放置更多的<strong>开采器</strong>和<strong>传送带</strong>来更有效率地完成关卡目标。<br><br>
提示:按住 <strong>SHIFT</strong> 提示:按住 <strong>SHIFT</strong>
键可放置多个<strong>开采器</strong>,注意用<strong>R</strong> 键可放置多个<strong>开采器</strong>,注意用<strong>R</strong>
键可旋转<strong>开采器</strong>的出口方向,确保开采的图形可以顺利传送。 键可旋转<strong>开采器</strong>的出口方向,确保开采的图形可以顺利传送。
2_1_place_cutter: 现在放置一个<strong>切割器</strong>,这个设施可把<strong>圆形</strong>切成两半!<br><br>注意:无论如何放置,切割机总是<strong>从上到下</strong>切割。 2_1_place_cutter: 现在放置一个<strong>切割器</strong>,这个设施可把<strong>圆形</strong>切成两半!<br><br>注意:无论如何放置,切割机总是<strong>从上到下</strong>切割。
2_2_place_trash: 使用切割机后产生的废弃图形会导致<strong>堵塞</strong>。<br><br>注意使用<strong>垃圾桶</strong>清除当前 2_2_place_trash:
使用切割机后产生的废弃图形会导致<strong>堵塞</strong>。<br><br>注意使用<strong>垃圾桶</strong>清除当前
(!) 不需要的废物。 (!) 不需要的废物。
2_3_more_cutters: 干的好!现在放置<strong>2个以上的切割机</strong>来加快当前缓慢的过程!<br><br>提示:用<strong>快捷键0-9</strong>可以快速选择各项设施! 2_3_more_cutters: 干的好!现在放置<strong>2个以上的切割机</strong>来加快当前缓慢的过程!<br><br>提示:用<strong>快捷键0-9</strong>可以快速选择各项设施!
3_1_rectangles: 现在让我们开采一些矩形!找到<strong>矩形地带</strong>并<strong>放置4个开采器</strong>并将它们用<strong>传送带</strong>连接到中心基地。<br><br> 3_1_rectangles:
现在让我们开采一些矩形!找到<strong>矩形地带</strong>并<strong>放置4个开采器</strong>并将它们用<strong>传送带</strong>连接到中心基地。<br><br>
提示:选中<strong>传送带</strong>后按住<strong>SHIFT键</strong>可快速准确地规划<strong>传送带路线!</strong> 提示:选中<strong>传送带</strong>后按住<strong>SHIFT键</strong>可快速准确地规划<strong>传送带路线!</strong>
21_1_place_quad_painter: 放置<strong>四口上色器</strong>并且获取一些<strong>圆形</strong><strong>白色</strong>和<strong>红色</strong> 21_1_place_quad_painter: 放置<strong>四口上色器</strong>并且获取一些<strong>圆形</strong><strong>白色</strong>和<strong>红色</strong>
21_2_switch_to_wires: 按 <strong>E</strong> 键选择<strong>电线层</strong><br><br> 21_2_switch_to_wires: 按 <strong>E</strong> 键选择<strong>电线层</strong><br><br>
@ -381,43 +378,35 @@ ingame:
title: 成就 title: 成就
desc: 挑战全成就解锁! desc: 挑战全成就解锁!
puzzleEditorSettings: puzzleEditorSettings:
zoneTitle: Zone zoneTitle: 区域
zoneWidth: Width zoneWidth: 宽度
zoneHeight: Height zoneHeight: 高度
trimZone: Trim trimZone: 整理
clearItems: Clear Items clearItems: 清除项目
share: Share share: 共享
report: Report report: 上报
puzzleEditorControls: puzzleEditorControls:
title: Puzzle Creator title: 谜题编辑器
instructions: instructions:
- 1. Place <strong>Constant Producers</strong> to provide shapes and - 1.放置<strong>常量生成器</strong>,为玩家提供此谜题的初始图形和颜色。
colors to the player - 2.建造您希望玩家稍后建造的一个或多个图形,并将其交付给一个或多个<strong>目标接收器</strong>。
- 2. Build one or more shapes you want the player to build later and - 3.当一个目标接收器接收到一个图形一段时间后,会<strong>将其保存为此玩家稍后必须建造的目标</strong>(由<strong>绿色充能条</strong>表示)。
deliver it to one or more <strong>Goal Acceptors</strong> - 4.单击设施上的<strong>锁定按钮</strong>即可将其禁用。
- 3. Once a Goal Acceptor receives a shape for a certain amount of - 5.单击审阅后,您的谜题将通过验证,您可以正式发布它。
time, it <strong>saves it as a goal</strong> that the player must - 6.谜题发布后,<strong>所有设施都将被拆除</strong>,除了<strong>常量生成器</strong>和<strong>目标接收器</strong>。然后,等着其他玩家对您创造的谜题发起挑战吧!
produce later (Indicated by the <strong>green badge</strong>).
- 4. Click the <strong>lock button</strong> on a building to disable
it.
- 5. Once you click review, your puzzle will be validated and you
can publish it.
- 6. Upon release, <strong>all buildings will be removed</strong>
except for the Producers and Goal Acceptors - That's the part that
the player is supposed to figure out for themselves, after all :)
puzzleCompletion: puzzleCompletion:
title: Puzzle Completed! title: 谜题挑战成功!
titleLike: "Click the heart if you liked the puzzle:" titleLike: "喜欢此谜题的话,请为它点赞:"
titleRating: How difficult did you find the puzzle? titleRating: 您觉得此谜题难度如何?
titleRatingDesc: Your rating will help me to make you better suggestions in the future titleRatingDesc: 您的评分将帮助作者在未来创作出更好的谜题!
continueBtn: Keep Playing continueBtn: 继续游戏
menuBtn: Menu menuBtn: 菜单
puzzleMetadata: puzzleMetadata:
author: Author author: 作者
shortKey: Short Key shortKey: 短代码
rating: Difficulty score rating: 难度评分
averageDuration: Avg. Duration averageDuration: 平均挑战时间
completionRate: Completion rate completionRate: 挑战完成率
shopUpgrades: shopUpgrades:
belt: belt:
name: 传送、分发、隧道 name: 传送、分发、隧道
@ -495,7 +484,7 @@ buildings:
hub: hub:
deliver: 交付 deliver: 交付
toUnlock: 解锁 toUnlock: 解锁
levelShortcut: LVL levelShortcut: 关卡
endOfDemo: 试玩版结束 endOfDemo: 试玩版结束
wire: wire:
default: default:
@ -601,16 +590,16 @@ buildings:
description: 仅在沙盒模式下可用,在常规层上输出<strong>电线层</strong>给定的<strong>信号</strong>。 description: 仅在沙盒模式下可用,在常规层上输出<strong>电线层</strong>给定的<strong>信号</strong>。
constant_producer: constant_producer:
default: default:
name: Constant Producer name: 常量生成器
description: Constantly outputs a specified shape or color. description: 不断输出指定的图形或颜色。
goal_acceptor: goal_acceptor:
default: default:
name: Goal Acceptor name: 目标接收器
description: Deliver shapes to the goal acceptor to set them as a goal. description: 将图状传递给目标接收器,以将它们设置为谜题挑战目标。
block: block:
default: default:
name: Block name: 方块
description: Allows you to block a tile. description: 放置了方块的格子将无法再进行其他放置。
storyRewards: storyRewards:
reward_cutter_and_trash: reward_cutter_and_trash:
title: 切割图形 title: 切割图形
@ -622,7 +611,8 @@ storyRewards:
desc: 恭喜!您解锁了<strong>旋转机</strong>。它会顺时针将输入的<strong>图形旋转90度</strong>。 desc: 恭喜!您解锁了<strong>旋转机</strong>。它会顺时针将输入的<strong>图形旋转90度</strong>。
reward_painter: reward_painter:
title: 上色 title: 上色
desc: 恭喜!您解锁了<strong>上色器</strong>。开采一些颜色 (就像您开采图形一样),将其在上色器中与图形结合来将图形上色! desc:
恭喜!您解锁了<strong>上色器</strong>。开采一些颜色 (就像您开采图形一样),将其在上色器中与图形结合来将图形上色!
<br>注意:如果您不幸患有色盲,可以在设置中启用<strong>色盲模式</strong> <br>注意:如果您不幸患有色盲,可以在设置中启用<strong>色盲模式</strong>
reward_mixer: reward_mixer:
title: 混合颜色 title: 混合颜色
@ -639,11 +629,13 @@ storyRewards:
desc: 恭喜!您解锁了<strong>隧道</strong>。它可放置在<strong>传送带</strong>或<strong>设施</strong>下方以运送物品。 desc: 恭喜!您解锁了<strong>隧道</strong>。它可放置在<strong>传送带</strong>或<strong>设施</strong>下方以运送物品。
reward_rotater_ccw: reward_rotater_ccw:
title: 逆时针旋转 title: 逆时针旋转
desc: 恭喜!您解锁了<strong>旋转机</strong>的<strong>逆时针</strong>变体。它可以逆时针旋转<strong>图形</strong>。 desc:
恭喜!您解锁了<strong>旋转机</strong>的<strong>逆时针</strong>变体。它可以逆时针旋转<strong>图形</strong>。
<br>选择<strong>旋转机</strong>然后按"T"键来选取这个变体。 <br>选择<strong>旋转机</strong>然后按"T"键来选取这个变体。
reward_miner_chainable: reward_miner_chainable:
title: 链式开采器 title: 链式开采器
desc: 您已经解锁了<strong>链式开采器</strong>!它能<strong>转发资源</strong>给其他的开采器,这样您就能更有效率的开采各类资源了!<br><br> desc:
您已经解锁了<strong>链式开采器</strong>!它能<strong>转发资源</strong>给其他的开采器,这样您就能更有效率的开采各类资源了!<br><br>
注意:新的开采器已替换了工具栏里旧的开采器! 注意:新的开采器已替换了工具栏里旧的开采器!
reward_underground_belt_tier_2: reward_underground_belt_tier_2:
title: 二级隧道 title: 二级隧道
@ -660,12 +652,14 @@ storyRewards:
<br>它<strong>优先从左边</strong>输出,这样您就可以用它做一个<strong>溢流门</strong>了! <br>它<strong>优先从左边</strong>输出,这样您就可以用它做一个<strong>溢流门</strong>了!
reward_freeplay: reward_freeplay:
title: 自由模式 title: 自由模式
desc: 成功了!您解锁了<strong>自由模式</strong>!挑战升级!这意味着现在将<strong>随机</strong>生成图形! desc:
成功了!您解锁了<strong>自由模式</strong>!挑战升级!这意味着现在将<strong>随机</strong>生成图形!
从现在起,中心基地最为需要的是<strong>产量</strong>,我强烈建议您去制造一台能够自动交付所需图形的机器!<br><br> 从现在起,中心基地最为需要的是<strong>产量</strong>,我强烈建议您去制造一台能够自动交付所需图形的机器!<br><br>
基地会在<strong>电线层</strong>输出需要的图形,您需要去分析图形并在此基础上自动配置您的工厂。 基地会在<strong>电线层</strong>输出需要的图形,您需要去分析图形并在此基础上自动配置您的工厂。
reward_blueprints: reward_blueprints:
title: 蓝图 title: 蓝图
desc: 您现在可以<strong>复制粘贴</strong>您的工厂的一部分了!按住 CTRL键并拖动鼠标来选择一块区域然后按C键复制。 desc:
您现在可以<strong>复制粘贴</strong>您的工厂的一部分了!按住 CTRL键并拖动鼠标来选择一块区域然后按C键复制。
<br><br>粘贴并<strong>不是免费的</strong>,您需要制造<strong>蓝图图形</strong>来负担。蓝图图形是您刚刚交付的图形。 <br><br>粘贴并<strong>不是免费的</strong>,您需要制造<strong>蓝图图形</strong>来负担。蓝图图形是您刚刚交付的图形。
no_reward: no_reward:
title: 下一关 title: 下一关
@ -693,7 +687,8 @@ storyRewards:
<br>注意:您注意到<strong>传送读取器</strong>和<strong>存储器</strong>输出的他们最后读取的物品了吗?试着在显示屏上展示一下!" <br>注意:您注意到<strong>传送读取器</strong>和<strong>存储器</strong>输出的他们最后读取的物品了吗?试着在显示屏上展示一下!"
reward_constant_signal: reward_constant_signal:
title: 恒定信号 title: 恒定信号
desc: 恭喜!您解锁了生成于电线层之上的<strong>恒定信号</strong>,把它连接到<strong>过滤器</strong>时非常有用。 desc:
恭喜!您解锁了生成于电线层之上的<strong>恒定信号</strong>,把它连接到<strong>过滤器</strong>时非常有用。
<br>比如它能发出图形、颜色、开关值1 / 0的固定信号。 <br>比如它能发出图形、颜色、开关值1 / 0的固定信号。
reward_logic_gates: reward_logic_gates:
title: 逻辑门 title: 逻辑门
@ -712,7 +707,8 @@ storyRewards:
<strong>提示</strong>:可在设置中打开电线层教程!" <strong>提示</strong>:可在设置中打开电线层教程!"
reward_filter: reward_filter:
title: 物品过滤器 title: 物品过滤器
desc: 恭喜!您解锁了<strong>物品过滤器</strong>!它会根据在电线层上输入的信号决定是从上面还是右边输出物品。<br><br> desc:
恭喜!您解锁了<strong>物品过滤器</strong>!它会根据在电线层上输入的信号决定是从上面还是右边输出物品。<br><br>
您也可以输入开关值1 / 0信号来激活或者禁用它。 您也可以输入开关值1 / 0信号来激活或者禁用它。
reward_demo_end: reward_demo_end:
title: 试玩结束 title: 试玩结束
@ -927,10 +923,10 @@ keybindings:
rotateToDown: 向下旋转 rotateToDown: 向下旋转
rotateToRight: 向右旋转 rotateToRight: 向右旋转
rotateToLeft: 向左旋转 rotateToLeft: 向左旋转
constant_producer: Constant Producer constant_producer: 常量生成器
goal_acceptor: Goal Acceptor goal_acceptor: 目标接收器
block: Block block: 方块
massSelectClear: Clear belts massSelectClear: 清除传送带
about: about:
title: 关于游戏 title: 关于游戏
body: >- body: >-
@ -1010,58 +1006,51 @@ tips:
- 按F4显示FPS。 - 按F4显示FPS。
- 按两次F4显示您鼠标和镜头所在的块。 - 按两次F4显示您鼠标和镜头所在的块。
- 您可以点击被固定在屏幕左侧的图形来解除固定。 - 您可以点击被固定在屏幕左侧的图形来解除固定。
- You can click a pinned shape on the left side to unpin it. - 您可以单击左侧的固定形状将其取消固定。
puzzleMenu: puzzleMenu:
play: Play play: 游戏
edit: Edit edit: 编辑
title: Puzzle Mode title: 谜题模式
createPuzzle: Create Puzzle createPuzzle: 创建谜题
loadPuzzle: Load loadPuzzle: 载入
reviewPuzzle: Review & Publish reviewPuzzle: 审阅 & 发布
validatingPuzzle: Validating Puzzle validatingPuzzle: 验证谜题
submittingPuzzle: Submitting Puzzle submittingPuzzle: 提交谜题
noPuzzles: There are currently no puzzles in this section. noPuzzles: 暂无满足此部分条件的谜题。
categories: categories:
levels: Levels levels: 关卡
new: New new: 最新
top-rated: Top Rated top-rated: 最受好评
mine: My Puzzles mine: 我的谜题
short: Short short: 速通
easy: Easy easy: 简单
hard: Hard hard: 困难
completed: Completed completed: 完成
validation: validation:
title: Invalid Puzzle title: 无效谜题
noProducers: Please place a Constant Producer! noProducers: 请放置<strong>常量生成器</strong>
noGoalAcceptors: Please place a Goal Acceptor! noGoalAcceptors: 请放置<strong>目标接收器</strong>
goalAcceptorNoItem: One or more Goal Acceptors have not yet assigned an item. goalAcceptorNoItem: 一个或多个目标接收器尚未被分配图形目标。请向它们传递图形以设置目标。
Deliver a shape to them to set a goal. goalAcceptorRateNotMet: 一个或多个目标接收器没有获得足够数量的图形。请确保所有接收器的充能条指示器均为绿色。
goalAcceptorRateNotMet: One or more Goal Acceptors are not getting enough items. buildingOutOfBounds: 一个或多个设施位于可建造区域之外。请增加区域面积,或将超出区域的设施移除。
Make sure that the indicators are green for all acceptors. autoComplete: 请确保您的常量生成器不会直接向目标接收器传递目标图形。否则您的谜题会自动完成。
buildingOutOfBounds: One or more buildings are outside of the buildable area.
Either increase the area or remove them.
autoComplete: Your puzzle autocompletes itself! Please make sure your constant
producers are not directly delivering to your goal acceptors.
backendErrors: backendErrors:
ratelimit: You are performing your actions too frequent. Please wait a bit. ratelimit: 你的操作太频繁了。请稍等。
invalid-api-key: Failed to communicate with the backend, please try to invalid-api-key: 与后台通信失败,请尝试更新或重新启动游戏(无效的Api密钥)。
update/restart the game (Invalid Api Key). unauthorized: 与后台通信失败,请尝试更新或重新启动游戏(未经授权)。
unauthorized: Failed to communicate with the backend, please try to bad-token: 与后台通信失败,请尝试更新或重新启动游戏(令牌错误)。
update/restart the game (Unauthorized). bad-id: 谜题标识符无效。
bad-token: Failed to communicate with the backend, please try to update/restart not-found: 找不到给定的谜题。
the game (Bad Token). bad-category: 找不到给定的类别。
bad-id: Invalid puzzle identifier. bad-short-key: 给定的短代码错误。
not-found: The given puzzle could not be found. profane-title: 您的谜题标题包含污言秽语。
bad-category: The given category could not be found. bad-title-too-many-spaces: 您的谜题标题过短。
bad-short-key: The given short key is invalid. bad-shape-key-in-emitter: 常量生成器包含无效项目。
profane-title: Your puzzle title contains profane words. bad-shape-key-in-goal: 目标接收器包含无效项目。
bad-title-too-many-spaces: Your puzzle title is too short. no-emitters: 您的谜题没有任何常量生成器。
bad-shape-key-in-emitter: A constant producer has an invalid item. no-goals: 您的谜题没有任何目标接收器。
bad-shape-key-in-goal: A goal acceptor has an invalid item. short-key-already-taken: 此短代码已被使用,请使用其他短代码。
no-emitters: Your puzzle does not contain any constant producers. can-not-report-your-own-puzzle: 您无法上报您自己的谜题问题。
no-goals: Your puzzle does not contain any goal acceptors. bad-payload: 此请求包含无效数据。
short-key-already-taken: This short key is already taken, please use another one. bad-building-placement: 您的谜题包含放置错误的设施。
can-not-report-your-own-puzzle: You can not report your own puzzle. timeout: 请求超时。
bad-payload: The request contains invalid data.
bad-building-placement: Your puzzle contains invalid placed buildings.
timeout: The request timed out.