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

Merge branch 'master' into right-click-doesnt-clear-cursor.

This commit is contained in:
hexagonhexagon 2020-06-08 00:56:40 -04:00
commit b367f7bb1f
64 changed files with 1409 additions and 831 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 906 KiB

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
artwork/itch.io/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:de805473208e0901f1185485164a35fde59e4baf3000f30102d0f332842410a5
size 184895

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 KiB

Binary file not shown.

View File

@ -189,7 +189,7 @@ function serve({ standalone }) {
gulp.watch("../res_built/atlas/*.json", ["imgres.atlas"]);
// Watch the build folder and reload when anything changed
const extensions = ["html", "js", "png", "jpg", "svg", "mp3", "ico", "woff2", "json"];
const extensions = ["html", "js", "png", "gif", "jpg", "svg", "mp3", "ico", "woff2", "json"];
gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", function (e) {
return gulp.src(e.path).pipe(browserSync.reload({ stream: true }));
});
@ -275,11 +275,7 @@ gulp.task(
$.sequence("sounds.fullbuild", "translations.fullBuild", "js.standalone-beta")
);
gulp.task("step.standalone-beta.mainbuild", cb =>
$.multiProcess(
["utils.copyAdditionalBuildFiles", "step.baseResources", "step.standalone-beta.code"],
cb,
false
)
$.multiProcess(["step.baseResources", "step.standalone-beta.code"], cb, false)
);
gulp.task(
"step.standalone-beta.all",
@ -293,11 +289,7 @@ gulp.task(
$.sequence("sounds.fullbuild", "translations.fullBuild", "js.standalone-prod")
);
gulp.task("step.standalone-prod.mainbuild", cb =>
$.multiProcess(
["utils.copyAdditionalBuildFiles", "step.baseResources", "step.standalone-prod.code"],
cb,
false
)
$.multiProcess(["step.baseResources", "step.standalone-prod.code"], cb, false)
);
gulp.task(
"step.standalone-prod.all",

View File

@ -96,12 +96,20 @@ function gulptasksHTML($, gulp, buildFolder, browserSync) {
const initScript = document.createElement("script");
initScript.textContent = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-165342524-1', { anonymize_ip: true });
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-165342524-1', { anonymize_ip: true });
`;
document.head.appendChild(initScript);
const abTestingScript = document.createElement("script");
abTestingScript.setAttribute(
"src",
"https://www.googleoptimize.com/optimize.js?id=OPT-M5NHCV7"
);
abTestingScript.setAttribute("async", "");
document.head.appendChild(abTestingScript);
}
// Do not need to preload in app or standalone

View File

@ -5,7 +5,7 @@ const path = require("path");
const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
// Globs for ui resources
const imageResourcesGlobs = ["../res/**/*.png", "../res/**/*.svg", "../res/**/*.jpg"];
const imageResourcesGlobs = ["../res/**/*.png", "../res/**/*.svg", "../res/**/*.jpg", "../res/**/*.gif"];
function gulptasksImageResources($, gulp, buildFolder) {
// Lossless options
@ -17,6 +17,10 @@ function gulptasksImageResources($, gulp, buildFolder) {
$.imagemin.optipng({
optimizationLevel: 3,
}),
$.imageminGifsicle({
optimizationLevel: 3,
colors: 128,
}),
];
// Lossy options
@ -36,6 +40,10 @@ function gulptasksImageResources($, gulp, buildFolder) {
$.imagemin.optipng({
optimizationLevel: 3,
}),
$.imageminGifsicle({
optimizationLevel: 3,
colors: 128,
}),
];
// Where the resources folder are
@ -124,6 +132,7 @@ function gulptasksImageResources($, gulp, buildFolder) {
path.join(buildFolder, "res", "ui", "**", "*.png"),
path.join(buildFolder, "res", "ui", "**", "*.jpg"),
path.join(buildFolder, "res", "ui", "**", "*.svg"),
path.join(buildFolder, "res", "ui", "**", "*.gif"),
],
{ read: false }
)

View File

@ -70,6 +70,7 @@
"css-mqpacker": "^7.0.0",
"cssnano": "^4.1.10",
"electron-packager": "^14.0.6",
"imagemin-gifsicle": "^7.0.0",
"faster.js": "^1.1.0",
"glob": "^7.1.3",
"gulp": "^3.9.1",

View File

@ -237,7 +237,7 @@ module.exports = ({
pattern: /globalConfig\.beltSpeedItemsPerSecond/g,
replacement: () => "2.0",
},
{ pattern: /globalConfig\.itemSpacingOnBelts/g, replacement: () => "0.8" },
{ pattern: /globalConfig\.itemSpacingOnBelts/g, replacement: () => "0.63" },
{ pattern: /globalConfig\.debug/g, replacement: () => "''" },
],
}),

View File

@ -3412,6 +3412,15 @@ cross-spawn@^5.0.1:
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^7.0.0:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
cross-zip@^2.1.5:
version "2.1.6"
resolved "https://registry.yarnpkg.com/cross-zip/-/cross-zip-2.1.6.tgz#344d3ba9488609942987d815bb84860cff3d9491"
@ -4875,6 +4884,21 @@ execa@^1.0.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.2.tgz#ad87fb7b2d9d564f70d2b62d511bee41d5cbb240"
integrity sha512-QI2zLa6CjGWdiQsmSkZoGtDx2N+cQIGb3yNolGTdjSQzydzLgYYf8LRuagp7S7fPimjcrzUDSUFd/MgzELMi4Q==
dependencies:
cross-spawn "^7.0.0"
get-stream "^5.0.0"
human-signals "^1.1.1"
is-stream "^2.0.0"
merge-stream "^2.0.0"
npm-run-path "^4.0.0"
onetime "^5.1.0"
signal-exit "^3.0.2"
strip-final-newline "^2.0.0"
executable@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/executable/-/executable-1.1.0.tgz#877980e9112f3391066da37265de7ad8434ab4d9"
@ -5738,7 +5762,7 @@ get-stream@^4.0.0, get-stream@^4.1.0:
dependencies:
pump "^3.0.0"
get-stream@^5.1.0:
get-stream@^5.0.0, get-stream@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
@ -5767,6 +5791,16 @@ gifsicle@^4.0.0:
execa "^1.0.0"
logalot "^2.0.0"
gifsicle@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/gifsicle/-/gifsicle-5.1.0.tgz#08f878e9048c70adf046185115a6350516a1fdc0"
integrity sha512-hQsOH7yjC7fMokntysN6f2QuxrnX+zmKKKVy0sC3Vhtnk8WrOxLdfH/Z2PNn7lVVx+1+drzIeAe8ufcmdSC/8g==
dependencies:
bin-build "^3.0.0"
bin-wrapper "^4.0.0"
execa "^4.0.0"
logalot "^2.0.0"
glob-all@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.1.0.tgz#8913ddfb5ee1ac7812656241b03d5217c64b02ab"
@ -6859,6 +6893,11 @@ https-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
human-signals@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@ -6912,6 +6951,15 @@ imagemin-gifsicle@^6.0.1:
gifsicle "^4.0.0"
is-gif "^3.0.0"
imagemin-gifsicle@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/imagemin-gifsicle/-/imagemin-gifsicle-7.0.0.tgz#1a7ab136a144c4678657ba3b6c412f80805d26b0"
integrity sha512-LaP38xhxAwS3W8PFh4y5iQ6feoTSF+dTAXFRUEYQWYst6Xd+9L/iPk34QGgK/VO/objmIlmq9TStGfVY2IcHIA==
dependencies:
execa "^1.0.0"
gifsicle "^5.0.0"
is-gif "^3.0.0"
imagemin-jpegtran@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/imagemin-jpegtran/-/imagemin-jpegtran-6.0.0.tgz#c8d3bcfb6ec9c561c20a987142854be70d90b04f"
@ -8700,6 +8748,11 @@ merge-stream@^1.0.0:
dependencies:
readable-stream "^2.0.1"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
merge2@^1.2.3:
version "1.3.0"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
@ -8810,7 +8863,7 @@ mimic-fn@^1.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
mimic-fn@^2.0.0:
mimic-fn@^2.0.0, mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
@ -9312,6 +9365,13 @@ npm-run-path@^2.0.0:
dependencies:
path-key "^2.0.0"
npm-run-path@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
dependencies:
path-key "^3.0.0"
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@ -9533,6 +9593,13 @@ onetime@^2.0.0:
dependencies:
mimic-fn "^1.0.0"
onetime@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5"
integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==
dependencies:
mimic-fn "^2.1.0"
open@^0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc"
@ -9997,6 +10064,11 @@ path-key@^2.0.0, path-key@^2.0.1:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
@ -12038,11 +12110,23 @@ shebang-command@^1.2.0:
dependencies:
shebang-regex "^1.0.0"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shelljs@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8"
@ -12680,6 +12764,11 @@ strip-eof@^1.0.0:
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
strip-final-newline@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
strip-indent@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
@ -13973,6 +14062,13 @@ which@1, which@^1.1.1, which@^1.2.14, which@^1.2.9, which@^1.3.1:
dependencies:
isexe "^2.0.0"
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
wide-align@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"

View File

@ -12,7 +12,8 @@
"lint": "npx eslint src/js",
"prettier-all": "prettier --write src/**/*.* && prettier --write gulp/**/*.*",
"publishOnItchWindows": "butler push tmp_standalone_files/shapez.io-standalone-win32-x64 tobspr/shapezio:windows --userversion-file version",
"publishOnItchLinux": "butler push tmp_standalone_files/shapez.io-standalone-linux-x64 tobspr/shapezio:linux-experimental --userversion-file version",
"publishOnItchLinux": "butler push tmp_standalone_files/shapez.io-standalone-linux-x64 tobspr/shapezio:linux --userversion-file version",
"publishOnItch": "yarn publishOnItchWindows && yarn publishOnItchLinux",
"publishOnSteam": "cd gulp/steampipe && ./upload.bat",
"publishStandalone": "yarn publishOnItch && yarn publishOnSteam",
"publishWeb": "cd gulp && yarn main.deploy.prod",
@ -41,6 +42,7 @@
"howler": "^2.1.2",
"html-loader": "^0.5.5",
"ignore-loader": "^0.1.2",
"logrocket": "^1.0.7",
"lz-string": "^1.4.4",
"markdown-loader": "^4.0.0",
"obfuscator-loader": "^1.1.2",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 KiB

View File

@ -5,7 +5,7 @@
transform: translateX(-50%);
color: #333;
z-index: 9999;
background: rgba(0, 10, 20, 0.5);
background: $ingameHudBg;
@include S(padding, 5px);
display: flex;
flex-direction: column;

View File

@ -10,7 +10,7 @@
@include S(width, 240px);
@include S(grid-column-gap, 5px);
background: rgba(#333438, 0.8);
background: $ingameHudBg;
grid-template-columns: 1fr auto;
grid-template-rows: auto 1fr;
@ -108,7 +108,8 @@
.variant {
grid-row: 2 / 3;
@include S(border-radius, $globalBorderRadius);
background: rgba(0, 10, 20, 0.2);
background: rgba($ingameHudBg, 0.3);
opacity: 0.5;
display: inline-flex;
vertical-align: top;
position: relative;
@ -117,7 +118,8 @@
@include S(grid-gap, 10px);
&.active {
background-color: rgba(74, 163, 223, 0.6);
opacity: 1;
background-color: rgba($colorBlueBright, 0.8);
}
$iconSize: 25px;

View File

@ -41,8 +41,8 @@
background: center center / 70% no-repeat;
&:not(.unlocked) {
@include S(width, 30px);
opacity: 0.8;
@include S(width, 20px);
opacity: 0.15;
background-image: none !important;
&::before {

View File

@ -1,8 +1,9 @@
#ingame_HUD_DebugInfo {
position: absolute;
@include S(bottom, 5px);
@include S(left, 5px);
@include S(right, 5px);
text-align: right;
font-size: 15px;
display: flex;
line-height: 15px;

View File

@ -118,7 +118,7 @@
pointer-events: all;
@include S(width, 350px);
> strong {
strong {
font-weight: bold;
}
@ -139,6 +139,14 @@
background-color: rgb(250, 206, 206);
}
}
ul.bucketList {
padding-left: 30px;
li {
display: list-item;
}
}
}
> .buttons {

View File

@ -76,7 +76,7 @@
}
}
> button {
.buttonContainer button {
@include PlainText;
color: #fff;
border-color: rgba(0, 0, 0, 0.1);
@ -86,7 +86,7 @@
@include S(margin-right, 3px);
@include IncreasedClickArea(0px);
@include ButtonText;
@include S(min-height, 30px);
@include S(min-height, 40px);
transition: all 0.12s ease-in-out;
transition-property: opacity, transform;
display: inline-flex;

View File

@ -0,0 +1,50 @@
#ingame_HUD_InteractiveTutorial {
position: absolute;
@include S(left, 10px);
@include S(bottom, 10px);
@include StyleBelowWidth(1430px) {
@include S(bottom, 10px + 40px);
}
@include S(width, 150px);
background: $ingameHudBg;
@include S(padding, 4px);
color: #eee;
display: flex;
flex-direction: column;
@include MakeAnimationWrappedEvenOdd(0.5s ease-in-out) {
0% {
}
50% {
transform: translateX(-100%);
}
100% {
}
}
.title {
color: #fff;
opacity: 0.5;
@include SuperSmallText;
text-transform: uppercase;
}
.desc {
@include SuperSmallText;
strong {
color: $colorBlueBright;
font-weight: bold;
}
}
.helperGif {
@include S(margin-top, 5px);
@include S(height, 150px);
background: center center / contain no-repeat;
}
}

View File

@ -3,8 +3,7 @@
@include S(top, 50px);
left: 50%;
transform: translateX(-50%);
background: rgba(lighten(#f77, 5), 0.95);
@include S(border-radius, $globalBorderRadius);
background: $ingameHudBg;
@include S(padding, 6px, 10px);
@include SuperSmallText;
color: #fff;

View File

@ -1,7 +1,12 @@
#ingame_HUD_TutorialHints {
position: absolute;
@include S(left, 10px);
@include S(bottom, 50px);
@include S(bottom, 10px);
@include StyleBelowWidth(1430px) {
@include S(bottom, 50px);
}
display: flex;
flex-direction: column;
background: rgba(50, 60, 70, 0);
@ -50,6 +55,7 @@
button.toggleHint {
@include PlainText;
@include IncreasedClickArea(0px);
}
}
@ -60,7 +66,7 @@
}
&.enlarged {
background: rgba(50, 60, 70, 0.9);
background: $ingameHudBg;
left: 50%;
bottom: 50%;
transform: translate(-50%, 50%);
@ -75,7 +81,7 @@
bottom: -1000px;
z-index: 0;
background: rgba(50, 60, 70, 0.3);
background: rgba($ingameHudBg, 0.3);
}
.header {

View File

@ -1,6 +1,6 @@
#ingame_HUD_Watermark {
position: absolute;
background: uiResource("get_on_itch_io.svg") center center / contain no-repeat;
background: uiResource("get_on_steam.png") center center / contain no-repeat;
@include S(width, 110px);
@include S(height, 40px);
@include S(top, 10px);

View File

@ -1,7 +1,7 @@
#ingame_HUD_Waypoints_Hint {
position: absolute;
@include S(right, 10px);
@include S(bottom, 100px);
@include S(bottom, 10px);
display: flex;
flex-direction: column;

View File

@ -49,6 +49,7 @@
@import "ingame_hud/watermark";
@import "ingame_hud/blueprint_placer";
@import "ingame_hud/waypoints";
@import "ingame_hud/interactive_tutorial";
// prettier-ignore
$elements:
@ -69,6 +70,7 @@ ingame_HUD_Notifications,
ingame_HUD_MassSelector,
ingame_HUD_DebugInfo,
ingame_HUD_EntityDebugger,
ingame_HUD_InteractiveTutorial,
ingame_HUD_TutorialHints,
ingame_HUD_buildings_toolbar,
ingame_HUD_BlueprintPlacer,
@ -79,9 +81,9 @@ ingame_HUD_Watermark,
ingame_HUD_BetaOverlay,
// Dialogs
ingame_HUD_UnlockNotification,
ingame_HUD_Shop,
ingame_HUD_Statistics,
ingame_HUD_UnlockNotification,
ingame_HUD_SettingsMenu,
ingame_HUD_ModalDialogs;

View File

@ -60,28 +60,17 @@
.mainWrapper {
@include S(padding, 0, 10px);
align-items: center;
align-items: start;
justify-items: center;
&.noDemo {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
&.demo {
@include S(grid-column-gap, 10px);
display: grid;
grid-template-columns: 1fr 1fr;
}
@include S(grid-column-gap, 10px);
display: grid;
grid-template-columns: 1fr 1fr;
.standaloneBanner {
background: rgb(255, 234, 245);
@include S(border-radius, $globalBorderRadius);
height: 100%;
box-sizing: border-box;
@include S(width, 300px);
@include S(padding, 15px);
display: flex;
@ -114,9 +103,9 @@
.steamLink {
width: 100%;
@include S(height, 50px);
@include S(height, 40px);
background: uiResource("get_on_itch_io.svg") center center / contain no-repeat;
background: uiResource("get_on_steam.png") center center / contain no-repeat;
overflow: hidden;
display: block;
text-indent: -999em;
@ -165,6 +154,44 @@
border: #{D(2px)} solid rgba(0, 10, 20, 0.1);
}
.sideContainer {
display: flex;
flex-direction: column;
@include S(width, 300px);
.standaloneBanner {
flex-grow: 1;
@include S(margin-bottom, 10px);
}
.contest {
flex-grow: 1;
background: rgb(32, 187, 166);
@include S(padding, 15px);
h3 {
@include Heading;
color: #fff;
font-weight: bold;
text-transform: uppercase;
@include S(margin-bottom, 5px);
}
p {
color: #fff;
@include Text;
strong {
font-weight: bold;
}
@include S(margin-bottom, 5px);
}
button {
background: #fff;
color: #333538;
}
}
}
.mainContainer {
display: flex;
align-items: center;

View File

@ -30,7 +30,7 @@
width: 200px;
height: 80px;
min-height: 40px;
background: uiResource("get_on_itch_io.svg") center center / contain no-repeat;
background: uiResource("get_on_steam.png") center center / contain no-repeat;
overflow: hidden;
display: block;
text-indent: -999em;

View File

@ -34,8 +34,7 @@ $colorGreenBright: #66bb6a;
$colorBlueBright: rgb(74, 163, 223);
$colorRedBright: #ef5072;
$themeColor: #393747;
$ingameHudBg: rgba($accentColorBright, 0.1);
$ingameHudBorder: #{D(1.5px)} solid $accentColorDark;
$ingameHudBg: rgba(#333438, 0.9);
$text3dColor: #f4ffff;

View File

@ -40,9 +40,6 @@
<meta http-equiv="Expires" content="0" />
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<link rel="canonical" href="https://shapez.io" />
<!-- a/b testing -->
<script src="https://www.googleoptimize.com/optimize.js?id=OPT-M5NHCV7"></script>
</head>
<body oncontextmenu="return false" style="background: #393747;"></body>

View File

@ -121,29 +121,18 @@ export class Application {
* Initializes all platform instances
*/
initPlatformDependentInstances() {
logger.log("Creating platform dependent instances");
// Start with empty ad provider
this.adProvider = new NoAdProvider(this);
if (G_IS_STANDALONE) {
this.storage = new StorageImplElectron(this);
} else {
if (window.indexedDB) {
this.storage = new StorageImplBrowserIndexedDB(this);
} else {
this.storage = new StorageImplBrowser(this);
}
}
this.sound = new SoundImplBrowser(this);
logger.log("Creating platform dependent instances (standalone=", G_IS_STANDALONE, ")");
if (G_IS_STANDALONE) {
this.platformWrapper = new PlatformWrapperImplElectron(this);
} else {
this.platformWrapper = new PlatformWrapperImplBrowser(this);
}
this.analytics = new GoogleAnalyticsImpl(this);
// Start with empty ad provider
this.adProvider = new NoAdProvider(this);
this.sound = new SoundImplBrowser(this);
this.analytics = new GoogleAnalyticsImpl(this);
this.gameAnalytics = new ShapezGameAnalytics(this);
}
@ -267,11 +256,15 @@ export class Application {
onAppRenderableStateChanged(renderable) {
logger.log("Application renderable:", renderable);
window.focus();
const currentState = this.stateMgr.getCurrentState();
if (!renderable) {
this.stateMgr.getCurrentState().onAppPause();
if (currentState) {
currentState.onAppPause();
}
} else {
// Got resume
this.stateMgr.getCurrentState().onAppResume();
if (currentState) {
currentState.onAppResume();
}
this.checkResize();
}
@ -285,7 +278,10 @@ export class Application {
if (!this.unloaded) {
logSection("UNLOAD HANDLER", "#f77");
this.unloaded = true;
this.stateMgr.getCurrentState().onBeforeExit();
const currentState = this.stateMgr.getCurrentState();
if (currentState) {
currentState.onBeforeExit();
}
this.deinitialize();
}
}
@ -295,8 +291,9 @@ export class Application {
*/
onBeforeUnload(event) {
logSection("BEFORE UNLOAD HANDLER", "#f77");
const currentState = this.stateMgr.getCurrentState();
if (!G_IS_DEV && this.stateMgr.getCurrentState().getHasUnloadConfirmation()) {
if (!G_IS_DEV && currentState && currentState.getHasUnloadConfirmation()) {
if (!G_IS_STANDALONE) {
// Need to show a "Are you sure you want to exit"
event.preventDefault();
@ -346,7 +343,10 @@ export class Application {
return;
}
this.stateMgr.getCurrentState().onBackgroundTick(dt);
const currentState = this.stateMgr.getCurrentState();
if (currentState) {
currentState.onBackgroundTick(dt);
}
}
/**
@ -366,7 +366,10 @@ export class Application {
this.lastResizeCheck = time;
}
this.stateMgr.getCurrentState().onRender(dt);
const currentState = this.stateMgr.getCurrentState();
if (currentState) {
currentState.onRender(dt);
}
}
/**
@ -379,7 +382,10 @@ export class Application {
if (this.screenWidth !== w || this.screenHeight !== h || forceUpdate) {
this.screenWidth = w;
this.screenHeight = h;
this.stateMgr.getCurrentState().onResized(this.screenWidth, this.screenHeight);
const currentState = this.stateMgr.getCurrentState();
if (currentState) {
currentState.onResized(this.screenWidth, this.screenHeight);
}
const scale = this.getEffectiveUiScale();
waitNextFrame().then(() => document.documentElement.style.setProperty("--ui-scale", scale));

View File

@ -1,4 +1,39 @@
export const CHANGELOG = [
{
version: "1.1.8",
date: "07.06.2020",
entries: [
"You can now purchase the standalone on steam! <a href='https://steam.shapez.io' target='blank'>View steam page</a>",
"Added ability to create markers in the demo, but only two.",
"Contest #01 has ended! I'll now work through the entries, select the 5 I like most and present them to the community to vote for!",
],
},
{
version: "1.1.7",
date: "04.06.2020",
entries: ["HOTFIX: Fix savegames not showing up on the standalone version"],
},
{
version: "1.1.6",
date: "04.06.2020",
entries: [
"The steam release will happen on the <strong>7th of June</strong> - Be sure to add it to your wishlist! <a href='https://steam.shapez.io' target='blank'>View on steam</a>",
"Fixed level complete dialog being blurred when the shop was opened before",
"Standalone: Increased icon visibility for windows builds",
"Web version: Fixed firefox not loading the game when browsing in private mode",
],
},
{
version: "1.1.5",
date: "03.06.2020",
entries: ["Added weekly contests!"],
},
{
version: "1.1.4",
date: "01.06.2020",
entries: ["Add 'interactive' tutorial for the first level to improve onboarding experience"],
},
{
version: "1.1.3",
date: "01.06.2020",

View File

@ -10,7 +10,10 @@ import { AtlasDefinition, atlasFiles } from "./atlas_definitions";
const logger = createLogger("background_loader");
const essentialMainMenuSprites = ["logo.png", ...G_ALL_UI_IMAGES.filter(src => src.startsWith("ui/"))];
const essentialMainMenuSprites = [
"logo.png",
...G_ALL_UI_IMAGES.filter(src => src.startsWith("ui/") && src.indexOf(".gif") < 0),
];
const essentialMainMenuSounds = [
SOUNDS.uiClick,
SOUNDS.uiError,
@ -21,7 +24,7 @@ const essentialMainMenuSounds = [
];
const essentialBareGameAtlases = atlasFiles;
const essentialBareGameSprites = G_ALL_UI_IMAGES;
const essentialBareGameSprites = G_ALL_UI_IMAGES.filter(src => src.indexOf(".gif") < 0);
const essentialBareGameSounds = [MUSIC.theme];
const additionalGameSprites = [];

View File

@ -9,7 +9,7 @@ import { GLOBAL_APP } from "./globals";
const logger = createLogger("click_detector");
export const MAX_MOVE_DISTANCE_PX = IS_MOBILE ? 20 : 40;
export const MAX_MOVE_DISTANCE_PX = IS_MOBILE ? 20 : 80;
// For debugging
const registerClickDetectors = G_IS_DEV && true;
@ -404,11 +404,11 @@ export class ClickDetector {
if (this.clickDownPosition) {
const pos = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event);
const distance = pos.distance(this.clickDownPosition);
if (distance <= this.maxDistance) {
if (!IS_MOBILE || distance <= this.maxDistance) {
dispatchClick = true;
dispatchClickPos = pos;
} else {
// console.warn("[ClickDetector] Touch does not count as click: ms=", timeSinceStart, "-> tolerance:", tolerance, "(was", distance, ")");
console.warn("[ClickDetector] Touch does not count as click:", "(was", distance, ")");
}
}

View File

@ -15,8 +15,7 @@ export const THIRDPARTY_URLS = {
discord: "https://discord.gg/HN7EVzV",
github: "https://github.com/tobspr/shapez.io",
// standaloneStorePage: "https://steam.shapez.io",
standaloneStorePage: "https://tobspr.itch.io/shapez.io",
standaloneStorePage: "https://store.steampowered.com/app/1318690/shapezio/",
};
export const globalConfig = {
@ -46,7 +45,7 @@ export const globalConfig = {
// Belt speeds
// NOTICE: Update webpack.production.config too!
beltSpeedItemsPerSecond: 2,
itemSpacingOnBelts: 0.63,
itemSpacingOnBelts: 0.8,
minerSpeedItemsPerSecond: 0, // COMPUTED
undergroundBeltMaxTilesByTier: [5, 8],
@ -83,7 +82,7 @@ export const globalConfig = {
debug: {
/* dev:start */
// fastGameEnter: true,
fastGameEnter: true,
// noArtificialDelays: true,
// disableSavegameWrite: true,
// showEntityBounds: true,
@ -95,7 +94,7 @@ export const globalConfig = {
// rewardsInstant: true,
allBuildingsUnlocked: true,
blueprintsNoCost: true,
// upgradesNoCost: true,
upgradesNoCost: true,
// disableUnlockDialog: true,
// disableLogicTicks: true,
// testClipping: true,
@ -104,11 +103,12 @@ export const globalConfig = {
// enableEntityInspector: true,
// testAds: true,
// disableMapOverview: true,
disableTutorialHints: true,
// disableTutorialHints: true,
disableUpgradeNotification: true,
// instantBelts: true,
// instantProcessors: true,
// instantMiners: true,
// resumeGameOnFastEnter: false,
// renderForTrailer: true,
/* dev:end */

View File

@ -94,14 +94,15 @@ export class HubGoals extends BasicSerializableObject {
this.createNextGoal();
// Allow quickly switching goals in dev mode with key "C"
// Allow quickly switching goals in dev mode
if (G_IS_DEV) {
this.root.gameState.inputReciever.keydown.add(key => {
if (key.keyCode === 66) {
// Key: b
this.onGoalCompleted();
}
});
if (G_IS_DEV) {
window.addEventListener("keydown", ev => {
if (ev.key === "b") {
this.onGoalCompleted();
}
});
}
}
}

View File

@ -28,6 +28,7 @@ import { HUDWatermark } from "./parts/watermark";
import { HUDModalDialogs } from "./parts/modal_dialogs";
import { HUDPartTutorialHints } from "./parts/tutorial_hints";
import { HUDWaypoints } from "./parts/waypoints";
import { HUDInteractiveTutorial } from "./parts/interactive_tutorial";
/* dev:start */
import { TrailerMaker } from "./trailer_maker";
@ -87,6 +88,7 @@ export class GameHUD {
}
if (this.root.app.settings.getAllSettings().offerHints) {
this.parts.tutorialHints = new HUDPartTutorialHints(this.root);
this.parts.interactiveTutorial = new HUDInteractiveTutorial(this.root);
}
const frag = document.createDocumentFragment();

View File

@ -5,9 +5,9 @@ import { enumNotificationType } from "./notifications";
import { T } from "../../../translations";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { IS_DEMO } from "../../../core/config";
import { DynamicDomAttach } from "../dynamic_dom_attach";
export class HUDGameMenu extends BaseHUDPart {
initialize() {}
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_GameMenu");
@ -22,12 +22,16 @@ export class HUDGameMenu extends BaseHUDPart {
T.ingame.notifications.newUpgrade,
enumNotificationType.upgrade,
]),
visible: () =>
!this.root.app.settings.getAllSettings().offerHints || this.root.hubGoals.level >= 3,
},
{
id: "stats",
label: "Stats",
handler: () => this.root.hud.parts.statistics.show(),
keybinding: KEYMAPPINGS.ingame.menuOpenStats,
visible: () =>
!this.root.app.settings.getAllSettings().offerHints || this.root.hubGoals.level >= 3,
},
];
@ -36,14 +40,24 @@ export class HUDGameMenu extends BaseHUDPart {
* button: HTMLElement,
* badgeElement: HTMLElement,
* lastRenderAmount: number,
* condition?: function,
* notification: [string, enumNotificationType]
* }>} */
this.badgesToUpdate = [];
buttons.forEach(({ id, label, handler, keybinding, badge, notification }) => {
/** @type {Array<{
* button: HTMLElement,
* condition: function,
* domAttach: DynamicDomAttach
* }>} */
this.visibilityToUpdate = [];
this.buttonsElement = makeDiv(this.element, null, ["buttonContainer"]);
buttons.forEach(({ id, label, handler, keybinding, badge, notification, visible }) => {
const button = document.createElement("button");
button.setAttribute("data-button-id", id);
this.element.appendChild(button);
this.buttonsElement.appendChild(button);
this.trackClicks(button, handler);
if (keybinding) {
@ -52,6 +66,14 @@ export class HUDGameMenu extends BaseHUDPart {
binding.appendLabelToElement(button);
}
if (visible) {
this.visibilityToUpdate.push({
button,
condition: visible,
domAttach: new DynamicDomAttach(this.root, button),
});
}
if (badge) {
const badgeElement = makeDiv(button, null, ["badge"]);
this.badgesToUpdate.push({
@ -60,6 +82,7 @@ export class HUDGameMenu extends BaseHUDPart {
button,
badgeElement,
notification,
condition: visible,
});
}
});
@ -78,27 +101,52 @@ export class HUDGameMenu extends BaseHUDPart {
this.musicButton.classList.toggle("muted", this.root.app.settings.getAllSettings().musicMuted);
this.sfxButton.classList.toggle("muted", this.root.app.settings.getAllSettings().soundsMuted);
}
initialize() {
this.root.signals.gameSaved.add(this.onGameSaved, this);
}
update() {
let playSound = false;
let notifications = new Set();
// Update visibility of buttons
for (let i = 0; i < this.visibilityToUpdate.length; ++i) {
const { button, condition, domAttach } = this.visibilityToUpdate[i];
domAttach.update(condition());
}
// Check for notifications and badges
for (let i = 0; i < this.badgesToUpdate.length; ++i) {
const { badge, button, badgeElement, lastRenderAmount, notification } = this.badgesToUpdate[i];
const {
badge,
button,
badgeElement,
lastRenderAmount,
notification,
condition,
} = this.badgesToUpdate[i];
if (condition && !condition()) {
// Do not show notifications for invisible buttons
continue;
}
// Check if the amount shown differs from the one shown last frame
const amount = badge();
if (lastRenderAmount !== amount) {
if (amount > 0) {
badgeElement.innerText = amount;
}
// Check if the badge increased
// Check if the badge increased, if so play a notification
if (amount > lastRenderAmount) {
playSound = true;
if (notification) {
notifications.add(notification);
}
}
// Rerender notifications
this.badgesToUpdate[i].lastRenderAmount = amount;
button.classList.toggle("hasBadge", amount > 0);
}
@ -107,6 +155,7 @@ export class HUDGameMenu extends BaseHUDPart {
if (playSound) {
this.root.soundProxy.playUi(SOUNDS.badgeNotification);
}
notifications.forEach(([notification, type]) => {
this.root.hud.signals.notification.dispatch(notification, type);
});
@ -118,13 +167,6 @@ export class HUDGameMenu extends BaseHUDPart {
}
startSave() {
// if (IS_DEMO) {
// this.root.hud.parts.dialogs.showFeatureRestrictionInfo(
// null,
// T.dialogs.saveNotPossibleInDemo.desc
// );
// }
this.root.gameState.doSave();
}

View File

@ -0,0 +1,81 @@
import { BaseHUDPart } from "../base_hud_part";
import { makeDiv } from "../../../core/utils";
import { GameRoot } from "../../root";
import { MinerComponent } from "../../components/miner";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { TrackedState } from "../../../core/tracked_state";
import { cachebust } from "../../../core/cachebust";
import { T } from "../../../translations";
const tutorialsByLevel = [
// Level 1
[
// 1.1. place an extractor
{
id: "1_1_extractor",
condition: /** @param {GameRoot} root */ root => {
return root.entityMgr.getAllWithComponent(MinerComponent).length === 0;
},
},
// 1.2. connect to hub
{
id: "1_2_conveyor",
condition: /** @param {GameRoot} root */ root => {
return root.hubGoals.getCurrentGoalDelivered() === 0;
},
},
// 1.3 wait for completion
{
id: "1_3_expand",
condition: () => true,
},
],
];
export class HUDInteractiveTutorial extends BaseHUDPart {
createElements(parent) {
this.element = makeDiv(
parent,
"ingame_HUD_InteractiveTutorial",
["animEven"],
`
<strong class="title">Tutorial</strong>
`
);
this.elementDescription = makeDiv(this.element, null, ["desc"]);
this.elementGif = makeDiv(this.element, null, ["helperGif"]);
}
initialize() {
this.domAttach = new DynamicDomAttach(this.root, this.element);
this.currentHintId = new TrackedState(this.onHintChanged, this);
}
onHintChanged(hintId) {
this.elementDescription.innerHTML = T.ingame.interactiveTutorial.hints[hintId];
this.elementGif.style.backgroundImage =
"url('" + cachebust("res/ui/interactive_tutorial.noinline/" + hintId + ".gif") + "')";
this.element.classList.toggle("animEven");
this.element.classList.toggle("animOdd");
}
update() {
// Compute current hint
const thisLevelHints = tutorialsByLevel[this.root.hubGoals.level - 1];
let targetHintId = null;
if (thisLevelHints) {
for (let i = 0; i < thisLevelHints.length; ++i) {
const hint = thisLevelHints[i];
if (hint.condition(this.root)) {
targetHintId = hint.id;
break;
}
}
}
this.currentHintId.set(targetHintId);
this.domAttach.update(!!targetHintId);
}
}

View File

@ -23,10 +23,6 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
"ingame_HUD_KeybindingOverlay",
[],
`
<div class="binding">
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.createMarker)}</code>
<label>${T.ingame.keybindingsOverlay.createMarker}</label>
</div>
<div class="binding">
<code class="keybinding leftMouse noPlacementOnly"></code><i class="noPlacementOnly"></i>
@ -35,8 +31,15 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveDown)}</code>
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveRight)}</code>
<label>${T.ingame.keybindingsOverlay.moveMap}</label>
</div>
</div>
<div class="binding noPlacementOnly">
<code class="keybinding rightMouse"></code>
<label>${T.ingame.keybindingsOverlay.delete}</label>
</div>
<div class="binding noPlacementOnly">
<code class="keybinding builtinKey">${getKeycode(
KEYMAPPINGS.massSelect.massSelectStart

View File

@ -1,4 +1,3 @@
import { cachebust } from "../../../core/cachebust";
import { InputReceiver } from "../../../core/input_receiver";
import { TrackedState } from "../../../core/tracked_state";
import { makeDiv } from "../../../core/utils";
@ -6,9 +5,8 @@ import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { T } from "../../../translations";
import { globalConfig } from "../../../core/config";
const tutorialVideos = [1, 2, 3, 4, 5, 6, 7, 9, 10, 11];
const tutorialVideos = [2, 3, 4, 5, 6, 7, 9, 10, 11];
export class HUDPartTutorialHints extends BaseHUDPart {
createElements(parent) {
@ -55,15 +53,6 @@ export class HUDPartTutorialHints extends BaseHUDPart {
this.domAttach = new DynamicDomAttach(this.root, this.element);
this.currentShownLevel = new TrackedState(this.updateVideoUrl, this);
this.root.signals.postLoadHook.add(() => {
if (this.root.hubGoals.level === 1 && !(G_IS_DEV && globalConfig.debug.disableTutorialHints)) {
this.root.hud.parts.dialogs.showInfo(
T.dialogs.hintDescription.title,
T.dialogs.hintDescription.desc
);
}
});
}
updateVideoUrl(level) {

View File

@ -28,7 +28,7 @@ export class HUDUnlockNotification extends BaseHUDPart {
createElements(parent) {
this.inputReciever = new InputReceiver("unlock-notification");
this.element = makeDiv(parent, "ingame_HUD_UnlockNotification", []);
this.element = makeDiv(parent, "ingame_HUD_UnlockNotification", ["noBlur"]);
const dialog = makeDiv(this.element, null, ["dialog"]);

View File

@ -13,7 +13,7 @@ export class HUDWatermark extends BaseHUDPart {
}
onWatermarkClick() {
this.root.app.analytics.trackUiClick("watermark_click");
this.root.app.analytics.trackUiClick("watermark_click_2");
this.root.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage);
}

View File

@ -133,11 +133,6 @@ export class HUDWaypoints extends BaseHUDPart {
* @param {Vector=} worldPos Override the world pos, otherwise it is the camera position
*/
requestCreateMarker(worldPos = null) {
if (IS_DEMO) {
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(T.demo.features.creatingMarkers);
return;
}
const markerNameInput = new FormElementInput({
id: "markerName",
label: null,
@ -157,6 +152,11 @@ export class HUDWaypoints extends BaseHUDPart {
const center = worldPos || this.root.camera.center;
dialog.buttonSignals.ok.add(() => {
if (IS_DEMO && this.waypoints.length > 2) {
this.root.hud.parts.dialogs.showFeatureRestrictionInfo("", T.dialogs.markerDemoLimit.desc);
return;
}
this.waypoints.push({
label: markerNameInput.getValue(),
center: { x: center.x, y: center.y },

View File

@ -35,7 +35,7 @@ export const tutorialGoals = [
// Circle
{
shape: "CuCuCuCu", // belts t1
required: 20,
required: 40,
reward: enumHubGoalRewards.reward_cutter_and_trash,
},

View File

@ -18,6 +18,36 @@ if (window.coreThreadLoadedCb) {
window.coreThreadLoadedCb();
}
if (!G_IS_DEV && !G_IS_STANDALONE) {
const monthlyUsers = 300; // thousand
const logrocketLimit = 10; // thousand
const percentageOfUsers = logrocketLimit / monthlyUsers;
if (Math.random() <= percentageOfUsers) {
logger.log("Analyzing this session with logrocket");
const logrocket = require("logrocket");
logrocket.init("p1x9zh/shapezio");
try {
logrocket.getSessionURL(function (sessionURL) {
logger.log("Connected lockrocket to GA");
// @ts-ignore
try {
window.ga("send", {
hitType: "event",
eventCategory: "LogRocket",
eventAction: sessionURL,
});
} catch (ex) {
logger.warn("Logrocket connection to analytics failed:", ex);
}
});
} catch (ex) {
logger.warn("Logrocket connection to analytics failed:", ex);
}
}
}
console.log(
`%cshapez.io %c\n© 2020 Tobias Springer IT Solutions\nCommit %c${G_BUILD_COMMIT_HASH}%c on %c${new Date(
G_BUILD_TIME

View File

@ -1,11 +1,13 @@
import { Math_min } from "../../core/builtins";
import { globalConfig, IS_MOBILE, IS_DEBUG, IS_DEMO } from "../../core/config";
import { globalConfig, IS_DEMO, IS_MOBILE } from "../../core/config";
import { createLogger } from "../../core/logging";
import { queryParamOptions } from "../../core/query_parameters";
import { clamp } from "../../core/utils";
import { GamedistributionAdProvider } from "../ad_providers/gamedistribution";
import { NoAdProvider } from "../ad_providers/no_ad_provider";
import { PlatformWrapperInterface } from "../wrapper";
import { GamedistributionAdProvider } from "../ad_providers/gamedistribution";
import { StorageImplBrowser } from "./storage";
import { StorageImplBrowserIndexedDB } from "./storage_indexed_db";
const logger = createLogger("platform/browser");
@ -72,7 +74,43 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
logger.log("Embed provider:", this.embedProvider.id);
return super.initialize().then(() => this.initializeAdProvider());
return this.detectStorageImplementation()
.then(() => this.initializeAdProvider())
.then(() => super.initialize());
}
detectStorageImplementation() {
return new Promise(resolve => {
logger.log("Detecting storage");
if (!window.indexedDB) {
logger.log("Indexed DB not supported");
this.app.storage = new StorageImplBrowser(this.app);
resolve();
return;
}
// Try accessing the indexedb
let request;
try {
request = window.indexedDB.open("indexeddb_feature_detection", 1);
} catch (ex) {
logger.warn("Error while opening indexed db:", ex);
resolve();
return;
}
request.onerror = err => {
logger.log("Indexed DB can *not* be accessed: ", err);
logger.log("Using fallback to local storage");
this.app.storage = new StorageImplBrowser(this.app);
resolve();
};
request.onsuccess = () => {
logger.log("Indexed DB *can* be accessed");
this.app.storage = new StorageImplBrowserIndexedDB(this.app);
resolve();
};
});
}
getHasUnlimitedSavegames() {
@ -83,71 +121,6 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
return this.embedProvider.showDemoBadge;
}
onSentryLoaded() {
logger.log("Initializing sentry");
window.Sentry.init({
dsn: "TODO SENTRY DSN",
release: G_APP_ENVIRONMENT + "-" + G_BUILD_VERSION + "@" + G_BUILD_COMMIT_HASH,
// Will cause a deprecation warning, but the demise of `ignoreErrors` is still under discussion.
// See: https://github.com/getsentry/raven-js/issues/73
ignoreErrors: [
// Random plugins/extensions
"top.GLOBALS",
// See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html
"originalCreateNotification",
"canvas.contentDocument",
"MyApp_RemoveAllHighlights",
"http://tt.epicplay.com",
"Can't find variable: ZiteReader",
"jigsaw is not defined",
"ComboSearch is not defined",
"http://loading.retry.widdit.com/",
"atomicFindClose",
// Facebook borked
"fb_xd_fragment",
// ISP "optimizing" proxy - `Cache-Control: no-transform` seems to reduce this. (thanks @acdha)
// See http://stackoverflow.com/questions/4113268/how-to-stop-javascript-injection-from-vodafone-proxy
"bmi_SafeAddOnload",
"EBCallBackMessageReceived",
// See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
"conduitPage",
// Generic error code from errors outside the security sandbox
// You can delete this if using raven.js > 1.0, which ignores these automatically.
"Script error.",
// Errors from ads
"Cannot read property 'postMessage' of null",
// Firefox only
"AbortError: The operation was aborted.",
"<unknown>",
],
ignoreUrls: [
// Facebook flakiness
/graph\.facebook\.com/i,
// Facebook blocked
/connect\.facebook\.net\/en_US\/all\.js/i,
// Woopra flakiness
/eatdifferent\.com\.woopra-ns\.com/i,
/static\.woopra\.com\/js\/woopra\.js/i,
// Chrome extensions
/extensions\//i,
/^chrome:\/\//i,
// Other plugins
/127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb
/webappstoolbarba\.texthelp\.com\//i,
/metrics\.itunes\.apple\.com\.edgesuite\.net\//i,
],
beforeSend(event, hint) {
if (window.anyModLoaded) {
return null;
}
return event;
},
});
}
getId() {
return "browser@" + this.embedProvider.id;
}

View File

@ -1,10 +1,17 @@
import { PlatformWrapperImplBrowser } from "../browser/wrapper";
import { getIPCRenderer } from "../../core/utils";
import { createLogger } from "../../core/logging";
import { StorageImplElectron } from "./storage";
import { PlatformWrapperInterface } from "../wrapper";
const logger = createLogger("electron-wrapper");
export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
initialize() {
this.app.storage = new StorageImplElectron(this);
return PlatformWrapperInterface.prototype.initialize.call(this);
}
getId() {
return "electron";
}
@ -22,6 +29,14 @@ export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
return false;
}
getHasUnlimitedSavegames() {
return true;
}
getShowDemoBadges() {
return false;
}
performRestart() {
logger.log(this, "Performing restart");
window.location.reload(true);

View File

@ -24,14 +24,11 @@ export class MainMenuState extends GameState {
<p>${T.demoBanners.intro}</p>
<ul>
${T.demoBanners.advantages.map(advantage => `<li>${advantage}</li>`).join("")}
</ul>
<a href="#" class="steamLink" target="_blank">Get the shapez.io standalone!</a>
`;
return `
return (
`
<button class="settingsButton"></button>
@ -54,18 +51,29 @@ export class MainMenuState extends GameState {
<div class="logo">
<img src="${cachebust("res/logo.png")}" alt="shapez.io Logo">
${
IS_DEMO && this.app.platformWrapper.getShowDemoBadges()
? `<div class="demoBadge"></div>`
: ""
}
</div>
<div class="mainWrapper ${IS_DEMO ? "demo" : "noDemo"}">
${IS_DEMO ? `<div class="standaloneBanner">${bannerHtml}</div>` : ""}
<div class="sideContainer">
${IS_DEMO ? `<div class="standaloneBanner">${bannerHtml}</div>` : ""}
<div class="contest">
<h3>${T.mainMenu.contests.contest_01_03062020.title}</h3>
` +
/*<p>${T.mainMenu.contests.contest_01_03062020.desc}</p>
<button class="styledButton participateContest">${
T.mainMenu.contests.showInfo
}</button>*/
`
<p>${T.mainMenu.contests.contestOver}</p>
</div>
</div>
<div class="mainContainer">
${
isSupportedBrowser()
@ -104,7 +112,8 @@ export class MainMenuState extends GameState {
<div class="author">Made by <a class="producerLink" target="_blank">Tobias Springer</a></div>
</div>
`;
`
);
}
requestImportSavegame() {
@ -199,7 +208,7 @@ export class MainMenuState extends GameState {
if (G_IS_DEV && globalConfig.debug.fastGameEnter) {
const games = this.app.savegameMgr.getSavegamesMetaData();
if (games.length > 0) {
if (games.length > 0 && globalConfig.debug.resumeGameOnFastEnter) {
this.resumeGame(games[0]);
} else {
this.onPlayButtonClicked();
@ -220,6 +229,11 @@ export class MainMenuState extends GameState {
this.trackClicks(qs(".settingsButton"), this.onSettingsButtonClicked);
this.trackClicks(qs(".changelog"), this.onChangelogClicked);
const contestButton = qs(".participateContest");
if (contestButton) {
this.trackClicks(contestButton, this.onContestClicked);
}
if (G_IS_STANDALONE) {
this.trackClicks(qs(".exitAppButton"), this.onExitAppButtonClicked);
}
@ -254,7 +268,7 @@ export class MainMenuState extends GameState {
}
onSteamLinkClicked() {
this.app.analytics.trackUiClick("main_menu_steam_link");
this.app.analytics.trackUiClick("main_menu_steam_link_2");
this.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage);
return false;
}
@ -267,6 +281,15 @@ export class MainMenuState extends GameState {
this.moveToState("ChangelogState");
}
onContestClicked() {
this.app.analytics.trackUiClick("contest_click");
this.dialogs.showInfo(
T.mainMenu.contests.contest_01_03062020.title,
T.mainMenu.contests.contest_01_03062020.longDesc
);
}
renderSavegames() {
const oldContainer = this.htmlElement.querySelector(".mainContainer .savegames");
if (oldContainer) {
@ -375,19 +398,6 @@ export class MainMenuState extends GameState {
this.moveToState("SettingsState");
}
doStartNewGame() {
this.app.analytics.trackUiClick("startgame");
this.app.adProvider.showVideoAd().then(() => {
const savegame = this.app.savegameMgr.createNewSavegame();
this.moveToState("InGameState", {
savegame,
});
this.app.analytics.trackUiClick("startgame_adcomplete");
});
}
onPlayButtonClicked() {
if (
IS_DEMO &&
@ -399,17 +409,15 @@ export class MainMenuState extends GameState {
return;
}
if (IS_DEMO) {
this.app.analytics.trackUiClick("startgame_pre_show");
const { ok } = this.dialogs.showWarning(
T.dialogs.demoExplanation.title,
T.dialogs.demoExplanation.desc
);
ok.add(() => this.doStartNewGame());
return;
}
this.app.analytics.trackUiClick("startgame");
this.app.adProvider.showVideoAd().then(() => {
const savegame = this.app.savegameMgr.createNewSavegame();
this.doStartNewGame();
this.moveToState("InGameState", {
savegame,
});
this.app.analytics.trackUiClick("startgame_adcomplete");
});
}
onLeave() {

View File

@ -13,11 +13,11 @@ export class MobileWarningState extends GameState {
<img class="logo" src="${cachebust("res/logo.png")}" alt="shapez.io Logo">
<p>
I'm sorry, but shapez.io is not yet available on mobile devices!
(There is also no estimate when this will change, but feel to make a contribution! It's
&nbsp;<a href="https://github.com/tobspr/shapez.io" target="_blank">open source</a>!)</p>
I'm sorry, but shapez.io is not available on mobile devices yet!
There is also no estimate when this will change, but feel to make a contribution! It's
&nbsp;<a href="https://github.com/tobspr/shapez.io" target="_blank">open source</a>!</p>
<p>If you want to play on your computer, you can also get the standalone on itch.io:</p>
<p>If you want to play on your computer, you can also get the standalone on steam:</p>
<a href="${

View File

@ -82,18 +82,14 @@ export class PreloadState extends GameState {
.then(res => res.json())
.then(({ latest }) => {
if (latest !== G_BUILD_VERSION) {
const { ok, viewUpdate } = this.dialogs.showInfo(
const { ok } = this.dialogs.showInfo(
T.dialogs.newUpdate.title,
T.dialogs.newUpdate.desc,
["ok:good", "viewUpdate:good"]
["ok:good"]
);
return new Promise(resolve => {
ok.add(resolve);
viewUpdate.add(() => {
window.open("https://tobspr.itch.io/shapezio", "_blank");
resolve();
});
});
}
})

View File

@ -1,81 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>
shapez.io shape generator
</title>
<script async src="index.js"></script>
<style>
html,
body {
width: 100%;
height: 100%;
padding: 0;
}
body {
font-family: "Source Sans Pro", "Roboto", sans-serif;
background: #fafafa;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#resultWrapper {
border: 1px solid #ccc;
margin-top: 10px;
background: #fff;
padding: 40px;
}
#resultWrapper #result {
}
#code {
width: 600px;
font-family: monospace;
padding: 30px;
border: 1px solid #ccc;
background: #fff;
font-size: 17px;
}
#code:focus {
outline: none;
border-color: #39f;
}
#error {
height: 40px;
color: #f77;
margin-top: 10px;
display: flex;
text-align: left;
align-items: center;
}
#error:not(.hasError) {
color: rgb(71, 179, 71);
}
</style>
</head>
<body>
<h2>Shape generator</h2>
<input
value="CuCuCuCu"
id="code"
placeholder="shape code"
onkeypress="debounce(generate)"
onkeydown="debounce(generate)"
onkeyup="debounce(generate)"
onchange="debounce(generate)"
/>
<div id="error">Error</div>
<br />
<div id="resultWrapper">
<canvas id="result" width="256" height="256"></canvas>
</div>
</body>
</html>

View File

@ -1,301 +0,0 @@
/*
* Lots of code here is copied 1:1 from actual game files
*
*/
/** @enum {string} */
const enumSubShape = {
rect: "rect",
circle: "circle",
star: "star",
windmill: "windmill",
};
/** @enum {string} */
const enumSubShapeToShortcode = {
[enumSubShape.rect]: "R",
[enumSubShape.circle]: "C",
[enumSubShape.star]: "S",
[enumSubShape.windmill]: "W",
};
/** @enum {enumSubShape} */
const enumShortcodeToSubShape = {};
for (const key in enumSubShapeToShortcode) {
enumShortcodeToSubShape[enumSubShapeToShortcode[key]] = key;
}
const arrayQuadrantIndexToOffset = [
{ x: 1, y: -1 }, // tr
{ x: 1, y: 1 }, // br
{ x: -1, y: 1 }, // bl
{ x: -1, y: -1 }, // tl
];
// From colors.js
/** @enum {string} */
const enumColors = {
red: "red",
green: "green",
blue: "blue",
yellow: "yellow",
purple: "purple",
cyan: "cyan",
white: "white",
uncolored: "uncolored",
};
/** @enum {string} */
const enumColorToShortcode = {
[enumColors.red]: "r",
[enumColors.green]: "g",
[enumColors.blue]: "b",
[enumColors.yellow]: "y",
[enumColors.purple]: "p",
[enumColors.cyan]: "c",
[enumColors.white]: "w",
[enumColors.uncolored]: "u",
};
/** @enum {string} */
const enumColorsToHexCode = {
[enumColors.red]: "#ff666a",
[enumColors.green]: "#78ff66",
[enumColors.blue]: "#66a7ff",
// red + green
[enumColors.yellow]: "#fcf52a",
// red + blue
[enumColors.purple]: "#dd66ff",
// blue + green
[enumColors.cyan]: "#87fff5",
// blue + green + red
[enumColors.white]: "#ffffff",
[enumColors.uncolored]: "#aaaaaa",
};
/** @enum {enumColors} */
const enumShortcodeToColor = {};
for (const key in enumColorToShortcode) {
enumShortcodeToColor[enumColorToShortcode[key]] = key;
}
CanvasRenderingContext2D.prototype.beginCircle = function (x, y, r) {
if (r < 0.05) {
this.beginPath();
this.rect(x, y, 1, 1);
return;
}
this.beginPath();
this.arc(x, y, r, 0, 2.0 * Math.PI);
};
/////////////////////////////////////////////////////
function radians(degrees) {
return (degrees * Math.PI) / 180.0;
}
/**
* Generates the definition from the given short key
*/
function fromShortKey(key) {
const sourceLayers = key.split(":");
let layers = [];
for (let i = 0; i < sourceLayers.length; ++i) {
const text = sourceLayers[i];
if (text.length !== 8) {
throw new Error("Invalid layer: '" + text + "' -> must be 8 characters");
}
const quads = [null, null, null, null];
for (let quad = 0; quad < 4; ++quad) {
const shapeText = text[quad * 2 + 0];
const subShape = enumShortcodeToSubShape[shapeText];
const color = enumShortcodeToColor[text[quad * 2 + 1]];
if (subShape) {
if (!color) {
throw new Error("Invalid shape color key: " + key);
}
quads[quad] = {
subShape,
color,
};
} else if (shapeText !== "-") {
throw new Error("Invalid shape key: " + shapeText);
}
}
layers.push(quads);
}
return layers;
}
function renderShape(layers) {
const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById("result"));
const context = canvas.getContext("2d");
context.save();
context.fillStyle = "#fff";
context.fillRect(0, 0, 1000, 1000);
const w = 256;
const h = 256;
const dpi = 1;
context.translate((w * dpi) / 2, (h * dpi) / 2);
context.scale((dpi * w) / 23, (dpi * h) / 23);
context.fillStyle = "#e9ecf7";
const quadrantSize = 10;
const quadrantHalfSize = quadrantSize / 2;
context.fillStyle = "rgba(40, 50, 65, 0.1)";
context.beginCircle(0, 0, quadrantSize * 1.15);
context.fill();
for (let layerIndex = 0; layerIndex < layers.length; ++layerIndex) {
const quadrants = layers[layerIndex];
const layerScale = Math.max(0.1, 0.9 - layerIndex * 0.22);
for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) {
if (!quadrants[quadrantIndex]) {
continue;
}
const { subShape, color } = quadrants[quadrantIndex];
const quadrantPos = arrayQuadrantIndexToOffset[quadrantIndex];
const centerQuadrantX = quadrantPos.x * quadrantHalfSize;
const centerQuadrantY = quadrantPos.y * quadrantHalfSize;
const rotation = radians(quadrantIndex * 90);
context.translate(centerQuadrantX, centerQuadrantY);
context.rotate(rotation);
context.fillStyle = enumColorsToHexCode[color];
context.strokeStyle = "#555";
context.lineWidth = 1;
const insetPadding = 0.0;
switch (subShape) {
case enumSubShape.rect: {
context.beginPath();
const dims = quadrantSize * layerScale;
context.rect(
insetPadding + -quadrantHalfSize,
-insetPadding + quadrantHalfSize - dims,
dims,
dims
);
break;
}
case enumSubShape.star: {
context.beginPath();
const dims = quadrantSize * layerScale;
let originX = insetPadding - quadrantHalfSize;
let originY = -insetPadding + quadrantHalfSize - dims;
const moveInwards = dims * 0.4;
context.moveTo(originX, originY + moveInwards);
context.lineTo(originX + dims, originY);
context.lineTo(originX + dims - moveInwards, originY + dims);
context.lineTo(originX, originY + dims);
context.closePath();
break;
}
case enumSubShape.windmill: {
context.beginPath();
const dims = quadrantSize * layerScale;
let originX = insetPadding - quadrantHalfSize;
let originY = -insetPadding + quadrantHalfSize - dims;
const moveInwards = dims * 0.4;
context.moveTo(originX, originY + moveInwards);
context.lineTo(originX + dims, originY);
context.lineTo(originX + dims, originY + dims);
context.lineTo(originX, originY + dims);
context.closePath();
break;
}
case enumSubShape.circle: {
context.beginPath();
context.moveTo(insetPadding + -quadrantHalfSize, -insetPadding + quadrantHalfSize);
context.arc(
insetPadding + -quadrantHalfSize,
-insetPadding + quadrantHalfSize,
quadrantSize * layerScale,
-Math.PI * 0.5,
0
);
context.closePath();
break;
}
default: {
assertAlways(false, "Unkown sub shape: " + subShape);
}
}
context.fill();
context.stroke();
context.rotate(-rotation);
context.translate(-centerQuadrantX, -centerQuadrantY);
}
}
context.restore();
}
/////////////////////////////////////////////////////
function showError(msg) {
const errorDiv = document.getElementById("error");
errorDiv.classList.toggle("hasError", !!msg);
if (msg) {
errorDiv.innerText = msg;
} else {
errorDiv.innerText = "Shape generated";
}
}
// @ts-ignore
window.generate = () => {
showError(null);
// @ts-ignore
const code = document.getElementById("code").value.trim();
let parsed = null;
try {
parsed = fromShortKey(code);
} catch (ex) {
showError(ex);
return;
}
renderShape(parsed);
};
// @ts-ignore
window.debounce = fn => {
setTimeout(fn, 0);
};
// @ts-ignore
window.addEventListener("load", window.generate);

View File

@ -1,13 +0,0 @@
{
"name": "shape_generator",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"devDependencies": {
"http-server": "^0.12.3"
},
"scripts": {
"serve": "http-server . -p 9000 -g --cors -o -c-1"
}
}

View File

@ -1,152 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
async@^2.6.2:
version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
dependencies:
lodash "^4.17.14"
basic-auth@^1.0.3:
version "1.1.0"
resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884"
integrity sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=
colors@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
corser@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87"
integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=
debug@^3.0.0, debug@^3.1.1:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
dependencies:
ms "^2.1.1"
ecstatic@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48"
integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==
dependencies:
he "^1.1.1"
mime "^1.6.0"
minimist "^1.1.0"
url-join "^2.0.5"
eventemitter3@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
follow-redirects@^1.0.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb"
integrity sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==
dependencies:
debug "^3.0.0"
he@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
http-proxy@^1.18.0:
version "1.18.0"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
dependencies:
eventemitter3 "^4.0.0"
follow-redirects "^1.0.0"
requires-port "^1.0.0"
http-server@^0.12.3:
version "0.12.3"
resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.12.3.tgz#ba0471d0ecc425886616cb35c4faf279140a0d37"
integrity sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==
dependencies:
basic-auth "^1.0.3"
colors "^1.4.0"
corser "^2.0.1"
ecstatic "^3.3.2"
http-proxy "^1.18.0"
minimist "^1.2.5"
opener "^1.5.1"
portfinder "^1.0.25"
secure-compare "3.0.1"
union "~0.5.0"
lodash@^4.17.14:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
mime@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
minimist@^1.1.0, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
mkdirp@^0.5.1:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
dependencies:
minimist "^1.2.5"
ms@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
opener@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
portfinder@^1.0.25:
version "1.0.26"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70"
integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==
dependencies:
async "^2.6.2"
debug "^3.1.1"
mkdirp "^0.5.1"
qs@^6.4.0:
version "6.9.4"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
requires-port@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
secure-compare@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3"
integrity sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=
union@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/union/-/union-0.5.0.tgz#b2c11be84f60538537b846edb9ba266ba0090075"
integrity sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==
dependencies:
qs "^6.4.0"
url-join@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728"
integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=

View File

@ -64,15 +64,9 @@ global:
demoBanners:
# This is the "advertisement" shown in the main menu and other various places
title: Hey!
title: Demo Version
intro: >-
If you enjoy this game, please consider buying the full version!
advantages:
- Unlimited savegames
- Waypoints
- Dark mode & more
- >-
Allow me to further develop shapez.io ❤️
Get the standalone to unlock all features!
mainMenu:
play: Play
@ -88,6 +82,29 @@ mainMenu:
savegameLevel: Level <x>
savegameLevelUnknown: Unknown Level
contests:
contest_01_03062020:
title: "Contest #01"
desc: Win <strong>$25</strong> for the coolest base!
longDesc: >-
To give something back to you, I thought it would be cool to make weekly contests!
<br><br>
<strong>This weeks topic:</strong> Build the coolest base!
<br><br>
Here's the deal:<br>
<ul class="bucketList">
<li>Submit a screenshot of your base to <strong>contest@shapez.io</strong></li>
<li>Bonus points if you share it on social media!</li>
<li>I will choose 5 screenshots and propose it to the <strong>discord</strong> community to vote.</li>
<li>The winner gets <strong>$25</strong> (Paypal, Amazon Gift Card, whatever you prefer)</li>
<li>Deadline: 07.06.2020 12:00 AM CEST</li>
</ul>
<br>
I'm looking forward to seeing your awesome creations!
showInfo: View
contestOver: This contest has ended - Join the discord to get noticed about new contests!
dialogs:
buttons:
ok: OK
@ -153,15 +170,11 @@ dialogs:
leaveNotPossibleInDemo:
title: Demo version
desc: Your game was saved but you will not be able to restore it in the demo. Restoring your savegames is only possible in the full version. Are you sure?
desc: Your game has been saved, but you will not be able to restore it in the demo. Restoring your savegames is only possible in the full version. Are you sure?
newUpdate:
title: Update available
desc: There is an update for this game available!
demoExplanation:
title: Notice from the Developer
desc: I am developing this game in my free time, and I hope you enjoy it! If you do, please consider to buy the standalone version!
desc: There is an update for this game available, be sure to download it!
oneSavegameLimit:
title: Limited savegames
@ -206,6 +219,9 @@ dialogs:
title: New Marker
desc: Give it a meaningful name
markerDemoLimit:
desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers!
ingame:
# This is shown in the top left corner and displays useful keybindings in
# every situation
@ -220,6 +236,7 @@ ingame:
toggleHud: Toggle HUD
placeBuilding: Place building
createMarker: Create Marker
delete: Destroy
# Everything related to placing buildings (I.e. as soon as you selected a building
# from the toolbar)
@ -313,12 +330,24 @@ ingame:
blueprintPlacer:
cost: Cost
# Map markers
waypoints:
waypoints: Markers
hub: HUB
description: Left-click a marker to jump to it, right-click to delete it.<br><br>Press <keybinding> to create a marker from the current view, or <strong>right-click</strong> to create a marker at the selected location.
creationSuccessNotification: Marker has been created.
# Interactive tutorial
interactiveTutorial:
title: Tutorial
hints:
1_1_extractor: Place an <strong>extractor</strong> on top of a <strong>circle shape</strong> to extract it!
1_2_conveyor: >-
Connect the extractor with a <strong>conveyor belt</strong> to your hub!<br><br>Tip: <strong>Click and drag</strong> the belt with your mouse!
1_3_expand: >-
This is <strong>NOT</strong> an idle game! Build more extractors and belts to finish the goal quicker.<br><br>Tip: Hold <strong>SHIFT</strong> to place multiple extractors, and use <strong>R</strong> to rotate them.
# All shop upgrades
shopUpgrades:
belt:
@ -574,7 +603,7 @@ settings:
offerHints:
title: Hints & Tutorials
description: >-
Whether to offer hints and tutorials while playing.
Whether to offer hints and tutorials while playing. Also hides certain UI elements onto a given level to make it easier to get into the game.
keybindings:
title: Keybindings
@ -649,6 +678,5 @@ demo:
importingGames: Importing savegames
oneGameLimit: Limited to one savegame
customizeKeybindings: Customizing Keybindings
creatingMarkers: Create custom markers
settingNotAvailable: Not available in the demo.

View File

@ -26,6 +26,13 @@ global:
# How big numbers are rendered, e.g. "10,000"
thousandsDivider: "."
# The suffix for large numbers, e.g. 1.3k, 400.2M, etc. cf wikipedia système international d'unité
suffix:
thousands: k
millions: M
billions: T
trillions: E
# Shown for infinitely big numbers
infinite: inf
@ -152,10 +159,6 @@ dialogs:
title: Mise-à-jour disponible
desc: Une mise-à-jour est disponible pour ce jeu!
demoExplanation:
title: Note du développeur
desc: Je développe ce jeu pendant mon temps libre, et j'espère que vous l'appréciez! Si c'est le cas, merci de considérez l'achat de la version complète!
oneSavegameLimit:
title: Sauvegardes limitées
desc: Vous ne pouvez avoir qu'une seule sauvegarde en même temps dans la version démo. Merci de soit effacer l'actuelle ou de vous procurer la version complète!
@ -213,6 +216,7 @@ ingame:
toggleHud: Basculet l'ATH
placeBuilding: Placer un bâtiment
createMarker: Créer une balise
delete: Supprimer
# Everything related to placing buildings (I.e. as soon as you selected a building
# from the toolbar)
@ -278,7 +282,7 @@ ingame:
description: Affiche tous les formes que votre usine entière produit, en incluant les formes intermédiaires.
delivered:
title: Délivré
description: Affiche les formes qui ont étés délivrées dans votres bâtiment central.
description: Affiche les formes qui ont été livrées dans votre noyau.
noShapesProduced: Aucune forme n'a été produite jusqu'à présent.
# Displays the shapes per minute, e.g. '523 / m'
@ -306,12 +310,21 @@ ingame:
blueprintPlacer:
cost: Coût
# Map markers
waypoints:
waypoints: Balise
hub: Noyau
description: Cliquez une balise pour vous y rendre, clic-droit pour l'effacer.<br><br>Appuyez sur <keybinding> pour créer une balise sur la vue actuelle, ou <strong>clic-droit</strong> pour en créer une sur l'endroit pointé.
creationSuccessNotification: La bailse a été créée.
# Interactive tutorial
interactiveTutorial:
title: Tutoriel
hints:
1_1_extractor: Placez un <strong>extracteur</strong> sur une <strong>forme en cercle</strong> pour l'extraire!
1_2_conveyor: Connectez l'extracteur avec un <strong>convoyeur</strong> vers votre noyau!
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 votre votre but.
# All shop upgrades
shopUpgrades:
belt:
@ -440,7 +453,7 @@ storyRewards:
reward_tunnel:
title: Tunnel
desc: Le <strong>tunnel</strong> a été débloqué - Vous pouvez maintenant faire passer des formes vous les convoyeurs et les bâtimentts avec ça!
desc: Le <strong>tunnel</strong> a été débloqué - Vous pouvez maintenant faire passer des formes sous les convoyeurs et les bâtiments avec ça!
reward_rotater_ccw:
title: Pivoteur inversé
@ -448,7 +461,7 @@ storyRewards:
reward_miner_chainable:
title: Extracteur en série
desc: Vous avez débloqué <strong>l'extracteur en série</strong>! Il permet <strong>de transférer ses resources</strong> à d'autres extracteurs pour extraire les ressources plus efficacement!
desc: Vous avez débloqué <strong>l'extracteur en série</strong>! Il permet <strong>de transférer ses resources</strong> à d'autres extracteurs pour les extraire plus efficacement!
reward_underground_belt_tier_2:
title: Tunnel échelon II
@ -481,7 +494,7 @@ storyRewards:
reward_blueprints:
title: Patrons
desc: Vous pouvez maintenant <strong>copier et coller</strong> des perties de votre usines! Sélectionnez une zone (Appuyez sur CTRL, et sélectionnez avec votre souris), et appuyez sur 'C' pour la copier.<br><br>Coller n'est <strong>pas gratuit</strong>, vous devez produire <strong>des formes de patrons</strong> pour vous le payer! (Ceux qu'ont vient de vous donner).
desc: Vous pouvez maintenant <strong>copier et coller</strong> des parties de votre usines! Sélectionnez une zone (Appuyez sur CTRL, et sélectionnez avec votre souris), et appuyez sur 'C' pour la copier.<br><br>Coller n'est <strong>pas gratuit</strong>, vous devez produire <strong>des formes de patrons</strong> pour vous le payer! (Ceux que vous venez de livrer).
# Special reward, which is shown when there is no reward actually
no_reward:
@ -511,6 +524,23 @@ settings:
title: Taille de l'interface
description: >-
Change la taille de l'interface utilisateur. Cette interface se redimensionnera suivant la résolution de votre appareil, mais cette option contrôle le facteur de résolution.
scales:
super_small: Très petite
small: Petite
regular: Normale
large: Largr
huge: Très large
scrollWheelSensitivity:
title: Sensibilité du zoom
description: >-
Change la sensibilité du zoom (AUssi bien de la roulette de la souris que du trackpad).
sensitivity:
super_slow: Super lent
slow: Lent
regular: Normal
fast: Rapide
super_fast: Super rapide
fullscreen:
title: Plein écran
@ -557,6 +587,7 @@ keybindings:
categoryLabels:
general: Application
ingame: Jeu
navigation: Navigation
placement: Placement
massSelect: Suppression de masse
buildings: Raccourcis bâtiment
@ -569,9 +600,11 @@ keybindings:
mapMoveRight: Aller à droite
mapMoveDown: Aller en bas
mapMoveLeft: Aller à gauche
centerMap: Centrer la carte
mapZoomIn: Zoom avant
mapZoomOut: Zoom arrière
createMarker: Créer une balise
menuOpenShop: Améliorations
menuOpenStats: Statistiques
@ -621,5 +654,5 @@ demo:
settingNotAvailable: Indisponible dans la démo.
#
# French translation version v0.2 based on english v1.1.1 by Didier WEERTS 'The Corsaire'
# French translation version v0.3 based on english v1.1.4 by Didier WEERTS 'The Corsaire'
#

View File

@ -0,0 +1,673 @@
#
# GAME TRANSLATIONS
#
# Contributing:
#
# If you want to contribute, please make a pull request on this respository
# and I will have a look.
#
# Placeholders:
#
# Do *not* replace placeholders! Placeholders have a special syntax like
# `Hotkey: <key>`. They are encapsulated within angle brackets. The correct
# translation for this one in German for example would be: `Taste: <key>` (notice
# how the placeholder stayed '<key>' and was not replaced!)
#
# Adding a new language:
#
# If you want to add a new language, ask me in the discord and I will setup
# the basic structure so the game also detects it.
#
global:
loading: Carregando
error: Erro
# How big numbers are rendered, e.g. "10,000"
thousandsDivider: "."
# The suffix for large numbers, e.g. 1.3k, 400.2M, etc.
suffix:
thousands: K
millions: M
billions: B
trillions: T
# Shown for infinitely big numbers
infinite: inf
time:
# Used for formatting past time dates
oneSecondAgo: um segundo atrás
xSecondsAgo: <x> segundos atrás
oneMinuteAgo: um minuto atrás
xMinutesAgo: <x> minutos atrás
oneHourAgo: uma hora atrás
xHoursAgo: <x> horas atrás
oneDayAgo: um dia atrás
xDaysAgo: <x> dias atrás
# Short formats for times, e.g. '5h 23m'
secondsShort: <seconds>s
minutesAndSecondsShort: <minutes>m <seconds>s
hoursAndMinutesShort: <hours>h <minutes>s
xMinutes: <x> minutos
keys:
tab: TAB
control: CTRL
alt: ALT
escape: ESC
shift: SHIFT
space: ESPAÇO
demoBanners:
# This is the "advertisement" shown in the main menu and other various places
title: Versão Demo
intro: >-
Pegue a versão completa para desbloquear todas os recursos
mainMenu:
play: Jogar
changelog: Changelog
importSavegame: Importar
openSourceHint: Esse jogo tem código aberto!
discordLink: Discord oficial
# This is shown when using firefox and other browsers which are not supported.
browserWarning: >-
Desculpe, o jogo fica lento em seu navegador! Compre a versão completa ou baixe o Chrome para obter uma experiência completa.
savegameLevel: Level <x>
savegameLevelUnknown: Level desconhecido
contests:
contest_01_03062020:
title: "Concurso #01"
desc: Ganhe <strong> $ 25 </strong> pela melhor base!
longDesc: >-
Para retribuir, pensei que seria legal fazer concursos semanais!
<br><br>
<strong> Tópico dessa semana:</strong> Cronstua a base mais legal!
<br><br>
Here's the deal:<br>
<ul class="bucketList">
<li>Envie uma captura de tela da sua base para <strong>contest@shapez.io</strong></li>
<li>Pontos bônus se você o compartilhar nas mídias sociais!</li>
<li>Vou escolher 5 capturas de tela e propor à votação a comunidade <strong>discord</strong>.</li>
<li>o vencedor recebe <strong> $ 25 </strong> (Paypal, Amazon Gift Card, o que você preferir)</li>
<li>Até 07.06.2020 12:00 CEST</li>
</ul>
<br>
Estou ansioso para ver suas criações incríveis!
showInfo: Participate
dialogs:
buttons:
ok: OK
delete: Deletar
cancel: Cancelar
later: Voltar
restart: Reiniciar
reset: Reset
getStandalone: Obter versão completa
deleteGame: Eu sei o que eu faço
viewUpdate: Atualizações
showUpgrades: Mostrar atualizações
showKeybindings: Controles
importSavegameError:
title: Erro importante
text: >-
Falha ao carregar seu savegame:
importSavegameSuccess:
title: Sucesso
text: >-
Seu savegame foi importado.
gameLoadFailure:
title: Jogo esta quebrado
text: >-
Falha ao carregar seu savegame
confirmSavegameDelete:
title: Confirmar exclusão
text: >-
Tem certeza que quer excluir esse jogo?
savegameDeletionError:
title: Falha para deletar
text: >-
Falha ao deletar seu savegame:
restartRequired:
title: Reiniciar
text: >-
Voce precisa reiniciar o jogo para aplicar as mudanças.
editKeybinding:
title: Change Keybinding
desc: Press the key you want to assign, or escape to cancel.
resetKeybindingsConfirmation:
title: Resetar controles
desc: Essa opção deixa os controles no modo padrão.
keybindingsResetOk:
title: Resetar controles
desc: Os controles foram resetados para o modo padrão.
featureRestriction:
title: Versão Demo
desc: Você tentou acessar um recurso (<feature>) que não está disponível na demo. Considere obter a versão completa para a proceder!
saveNotPossibleInDemo:
desc: Seu jogo foi salvo, mas a restauração só é possível na versão completa. Considere obter a versão completa!
leaveNotPossibleInDemo:
title: Demo version
desc: Seu jogo foi salvo, mas você não poderá restaurá-lo na demo. Restaurar seus savegames só é possível na versão completa. Você tem certeza?
newUpdate:
title: Atualização disponível
desc: Uma atualização para esse jogo esta disponível!
oneSavegameLimit:
title: Save limitado
desc: Você pode ter apenas um savegame por vez na versão demo. Remova o existente ou obtenha a versão completa!
updateSummary:
title: Nova Atualização!
desc: >-
Aqui estão as alterações desde a última vez que você jogou:
hintDescription:
title: Tutorial
desc: >-
Sempre que precisar de ajuda ou estiver parado, confira o botão 'Mostrar dica' no canto inferior esquerdo e darei o meu melhor para ajudá-lo!
upgradesIntroduction:
title: Desbloquear updates
desc: >-
Todas as formas que você produz podem ser usadas para desbloquear atualizações - <strong> Não destrua suas antigas fábricas!!</strong>
O guia de atualizações pode ser encontrada no canto superior direito da tela.
massDeleteConfirm:
title: Deletar
desc: >-
Voce esta deletando vários itens (<count> para ser exato)! Voce quer continuar?
blueprintsNotUnlocked:
title: Não desbloqueado ainda
desc: >-
Os projetos ainda não foram desbloqueados! Complete mais níveis para desbloqueá-los.
keybindingsIntroduction:
title: Teclas úteis
desc: >-
Este jogo possui muitas combinações de teclas que facilitam a construção de grandes fábricas
Aqui estão alguns mas certifique-se de <strong> verificar as combinações de teclas </strong>!<br><br>
<code class='keybinding'>CTRL</code> + Drag: Selecione a área para copiar / delete.<br>
<code class='keybinding'>SHIFT</code>: Mantenha pressionado para colocar vários.<br>
<code class='keybinding'>ALT</code>: Inverter as posições.<br>
createMarker:
title: Nova Marcação
desc: De um nome
ingame:
# This is shown in the top left corner and displays useful keybindings in
# every situation
keybindingsOverlay:
moveMap: Mover
removeBuildings: Deletar
stopPlacement: Parar
rotateBuilding: Rotação
placeMultiple: Colocar vários
reverseOrientation: reverso
disableAutoOrientation: desligar orientações
toggleHud: Base
placeBuilding: Colocar construção
createMarker: Criar marcador
delete: Destruir
# Everything related to placing buildings (I.e. as soon as you selected a building
# from the toolbar)
buildingPlacement:
# Buildings can have different variants which are unlocked at later levels,
# and this is the hint shown when there are multiple variants available.
cycleBuildingVariants: Aperte <key> para variações.
# Shows the hotkey in the ui, e.g. "Hotkey: Q"
hotkeyLabel: >-
Hotkey: <key>
infoTexts:
speed: velocidade
range: distancia
storage: Estoque
oneItemPerSecond: 1 item / segundo
itemsPerSecond: <x> itens / s
itemsPerSecondDouble: (x2)
tiles: <x> tiles
# The notification when completing a level
levelCompleteNotification:
# <level> is replaced by the actual level, so this gets 'Level 03' for example.
levelTitle: Level <level>
completed: Completado
unlockText: Desbloqueado <reward>!
buttonNextLevel: Próximo Level
# Notifications on the lower right
notifications:
newUpgrade: Nova Atualização disponível!
gameSaved: Seu jogo foi Salvo.
# Mass select information, this is when you hold CTRL and then drag with your mouse
# to select multiple buildings
massSelect:
infoText: Aperte <keyCopy> para copiar, <keyDelete> para excluir e <keyCancel> para cancelar.
# The "Upgrades" window
shop:
title: Atualizações
buttonUnlock: Atualizações
# Gets replaced to e.g. "Tier IX"
tier: Nível <x>
# The roman number for each tier
tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X]
maximumLevel: Level Máximo
# The "Statistics" window
statistics:
title: Estatísticas
dataSources:
stored:
title: Estoque
description: Exibindo a quantidade de formas armazenadas em seu edifício central.
produced:
title: Produção
description: Exibindo todas as formas que toda a sua fábrica produz, incluindo produtos intermediários..
delivered:
title: Entregue
description: Exibindo formas entregues ao seu edifício central..
noShapesProduced: Nenhuma forma foi produzida até o momento.
# Displays the shapes per minute, e.g. '523 / m'
shapesPerMinute: <formas> / m
# Settings menu, when you press "ESC"
settingsMenu:
playtime: Tempo de Jogo
buildingsPlaced: Construções
beltsPlaced: Belts
buttons:
continue: Continue
settings: Definições
menu: Voltar ao menu
# Bottom left tutorial hints
tutorialHints:
title: Precisa de ajuda?
showHint: Mostrar dica
hideHint: Fechar
# When placing a blueprint
blueprintPlacer:
cost: Custo
# Map markers
waypoints:
waypoints: Marcadores
hub: HUB
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.
# Interactive tutorial
interactiveTutorial:
title: Tutorial
hints:
1_1_extractor: Coloque um <strong> extrator </strong> em cima de uma <strong> fonte de círculo </strong> para extraí-lo!
1_2_conveyor: >-
Conecte o extrator com uma <strong> esteira transportadora </strong> até a sua base! <br><br> Dica, <strong>clique e arraste</strong> a esteira com o mouse!
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.
# All shop upgrades
shopUpgrades:
belt:
name: Esteiras, Distribuidores e Túneis
description: Velocidade +<gain>%
miner:
name: Extração
description: Velocidade +<gain>%
processors:
name: Cortar, Rotacionar e Empilhamento
description: Velocidade +<gain>%
painting:
name: Misturador e pintura
description: Velocidade +<gain>%
# Buildings and their name / description
buildings:
belt:
default:
name: &belt Conveyor Belt
description: Transporta itens, mantenha pressionado e arraste para colocar vários.
miner: # Internal name for the Extractor
default:
name: &miner Extractor
description: Coloque sobre uma forma ou cor para extraí-la.
chainable:
name: Extractor (Chain)
description: Coloque sobre uma forma ou cor para extraí-la. Pode ser acorrentado.
underground_belt: # Internal name for the Tunnel
default:
name: &underground_belt Tunnel
description: Permite transportar recursos sob construções.
tier2:
name: Tunnel Tier II
description: Permite transportar recursos sob construções.
splitter: # Internal name for the Balancer
default:
name: &splitter Balancer
description: Multifunctional - Distribui uniformemente todas as entradas em todas as saídas.
compact:
name: Merger (compact)
description: Mescla duas correias transportadoras em uma.
compact-inverse:
name: Merger (compact)
description: Mescla duas correias transportadoras em uma.
cutter:
default:
name: &cutter Cutter
description: Corta as formas de cima para baixo e produz as duas metades. <strong> Se você usar apenas uma parte, não se esqueça de destruir a outra parte, ou ela irá parar a produção! </strong>
quad:
name: Cutter (Quad)
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>
rotater:
default:
name: &rotater Rotate
description: Gira as formas no sentido horário em 90 graus.
ccw:
name: Rotate (CCW)
description: RGira as formas no sentido anti-horário em 90 graus.
stacker:
default:
name: &stacker Stacker
description: Empilha os dois itens. Se eles não puderem ser mesclados, o item certo será colocado acima do item esquerdo.
mixer:
default:
name: &mixer Color Mixer
description: Mistura duas cores usando mistura aditiva.
painter:
default:
name: &painter Painter
description: Colore a forma inteira na entrada esquerda com a cor da entrada direita.
double:
name: Painter (Double)
description: Colore as duas formas na entrada esquerda com a cor da entrada direita.
quad:
name: Painter (Quad)
description: Permite colorir cada quadrante da forma com uma cor diferente.
trash:
default:
name: &trash Lixo
description: Aceita qualquer item e os destrói. PARA SEMPRE
storage:
name: Estoque
description: Armazena itens em excesso, até uma determinada capacidade. Pode ser usado como uma porta de transbordamento.
storyRewards:
# Those are the rewards gained from completing the store
reward_cutter_and_trash:
title: Formas de corte
desc: Voce desbloqueou <strong>cutter</strong> - corte de formas pela metade de <strong>cima para baixo </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 lixo, que destrói tudo o que você coloca nele
reward_rotater:
title: Rodando
desc: O <strong> rotator </strong> foi desbloqueado! Gira as formas no sentido horário em 90 graus
reward_painter:
title: Pintando
desc: >-
O <strong> pintor </strong> foi desbloqueado - Extraia algumas veias coloridas (como você faz com formas) e combine-as com uma forma no pintor para colori-las! <br> <br> PS: Se você é daltônico , Já estou trabalhando em uma solução!
reward_mixer:
title: Mistura de cores
desc: O <strong> misturador </strong> foi desbloqueado - combine duas cores usando <strong> mistura aditiva </strong> com esta construção!
reward_stacker:
title: Combinador
desc: Agora você pode combinar formas com o <strong> combinador </strong>! Ambas as entradas são combinadas e, se puderem ser colocadas próximas uma da outra, serão <strong> fundidas </strong>. Caso contrário, a entrada direita é <strong> empilhada em cima </strong> da entrada esquerda!
reward_splitter:
title: Divisor/fusão
desc: O balanceador multifuncional <strong> </strong> foi desbloqueado - ele pode ser usado para construir fábricas maiores dividindo e mesclando itens </strong>! <br> <br>
reward_tunnel:
title: Túnel
desc: O <strong> túnel </strong> foi desbloqueado - Agora você pode canalizar itens através de construções!
reward_rotater_ccw:
title: CCW Rotação
desc: Você desbloqueou uma variante do <strong> rotater </strong> - permite girar no sentido anti-horário! Para construí-lo, selecione o rotador e <strong> pressione 'T' para alternar suas variantes </strong>!
reward_miner_chainable:
title: Extrator de encadeamento
desc: Você desbloqueou o <strong> extrator de correntes </strong>! Ele pode <strong> encaminhar seus recursos </strong> para outros extratores, para que você possa extrair recursos com mais eficiência!
reward_underground_belt_tier_2:
title: Túnel Tier II
desc: Você desbloqueou uma nova variante do <strong> túnel </strong> - ele tem um <strong> maior alcance </strong>, e também pode misturar e combinar esses túneis agora!
reward_splitter_compact:
title: Balanceador compacto
desc: >-
Você desbloqueou uma variante compacta do <strong> balanceador </strong> - ele aceita duas entradas e as mescla em uma!
reward_cutter_quad:
title: Cortador quádruplo
desc: Você desbloqueou uma variante do <strong> cortador </strong> - permite cortar formas em <strong> quatro partes </strong> em vez de apenas duas!
reward_painter_double:
title: Pintura dupla
desc: Você desbloqueou uma variante do <strong> pintor </strong> - funciona como o pintor regular, mas processa <strong> duas formas ao mesmo tempo </strong>, consumindo apenas uma cor em vez de duas!
reward_painter_quad:
title: Pintura quádupla
desc: Você desbloqueou uma variante do <strong> pintor </strong> - permite pintar cada parte da forma individualmente!
reward_storage:
title: buffer de armazenamento
desc: Você desbloqueou uma variante do <strong> lixo </strong> - Permite armazenar itens até uma determinada capacidade!
reward_freeplay:
title: Modo Livre
desc: Você fez isso! Você desbloqueou o <strong> modo de jogo livre </strong>! Isso significa que as formas agora são geradas aleatoriamente! (Não se preocupe, mais conteúdo está planejado para o jogo completo!)
reward_blueprints:
title: Projetos
desc: Agora você pode <strong> copiar e colar </strong> partes de sua fábrica! Selecione uma área (mantenha pressionada a tecla CTRL e arraste com o mouse) e pressione 'C' para copiá-la. <br> <br> Colar <strong> não é de graça </strong>, é necessário produzir <strong> projetos e formas </strong> para pagar! (Aqueles que você acabou de entregar).
# Special reward, which is shown when there is no reward actually
no_reward:
title: Próximo level
desc: >-
Este nível não lhe deu nenhuma recompensa, mas em breve?! <br> <br> PS: Melhor não destruir sua fábrica existente - Você precisa de <strong> todas </strong> todas essas formas posteriormente mais tarde para <strong> desbloquear atualizações </strong>!
no_reward_freeplay:
title: Next level
desc: >-
Parabens, não se esqueça existe muita coisa planejada para essa versão.
settings:
title: opções
categories:
game: Jogo
app: Aplicação
versionBadges:
dev: Desenvolvedor
staging: Staging
prod: Produção
buildDate: Built <at-date>
labels:
uiScale:
title: Fonte
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 quantidade de escala.
scales:
super_small: Super pequeno
small: Pequeno
regular: Normal
large: Grande
huge: Gigante
scrollWheelSensitivity:
title: Sensibilidade do zoom
description: >-
Altera a sensibilidade do zoom (scrol do mouse ou touchpad).
sensitivity:
super_slow: Super lento
slow: Lento
regular: Normal
fast: Rápido
super_fast: Super Rápido
fullscreen:
title: Tecla Cheia
description: >-
É recomendável jogar o jogo em tela cheia para obter a melhor experiência. Disponível apenas na versão completa.
soundsMuted:
title: Som
description: >-
Se ligado o jogo fica Mudo.
musicMuted:
title: Musica
description: >-
Se ligado a musica é desligada.
theme:
title: Tema
description: >-
Escolha o tema entre (Branco / Preto).
refreshRate:
title: Frequencia
description: >-
Se você possui um monitor de 144 hz, altere a taxa de atualização aqui para que o jogo seja simulado corretamente com taxas de atualização mais altas. Isso pode realmente diminuir o FPS se o computador estiver muito lento.
alwaysMultiplace:
title: Multiplicidade
description: >-
Se ativado, todos os edifícios permanecerão selecionados após o posicionamento até que você o cancele. Isso é equivalente a manter SHIFT permanentemente.
offerHints:
title: Dicas e tutoriais
description: >-
Se deve oferecer dicas e tutoriais enquanto estiver jogando.v.
keybindings:
title: Comandos
hint: >-
Tip: Certifique-se de usar CTRL, SHIFT e ALT! Eles permitem diferentes opções de veiculação.
resetKeybindings: Reset Keyinbindings
categoryLabels:
general: Geral
ingame: Jogo
navigation: Navegação
placement: Posicionamento
massSelect: Seleção
buildings: Construções
placementModifiers: Modificações
mappings:
confirm: Confirmar
back: Voltar
mapMoveUp: Mover para cima
mapMoveRight: Mover para direita
mapMoveDown: Mover para baixo
mapMoveLeft: Mover para a esquerda
centerMap: Centralizar
mapZoomIn: Aproximar
mapZoomOut: Distanciar
createMarker: Criar marcação
menuOpenShop: Atualizações
menuOpenStats: Estatísticas
toggleHud: Ocultar Menu
toggleFPSInfo: Mostar FPS
belt: *belt
splitter: *splitter
underground_belt: *underground_belt
miner: *miner
cutter: *cutter
rotater: *rotater
stacker: *stacker
mixer: *mixer
painter: *painter
trash: *trash
abortBuildingPlacement: Cancelar
rotateWhilePlacing: Rotacionar
rotateInverseModifier: >-
Modifier: Rotação instantanea
cycleBuildingVariants: Variações
confirmMassDelete: Confirmar exclusão em massa
cycleBuildings: Trocar de construção
massSelectStart: Segure e arraste para começar
massSelectSelectMultiple: Selecionar área
massSelectCopy: Copiar área
placementDisableAutoOrientation: Desligar orientações automaticas
placeMultiple: Permanecer no modo de produção
placeInverse: Inverter orientação de esteira
about:
title: Sobre o jogo
changelog:
title: Changelog
demo:
features:
restoringGames: Restaurando jogos salvos
importingGames: Carregando jogos salvos
oneGameLimit: Limitado para um savegamne
customizeKeybindings: Modificando Teclas
creatingMarkers: Criando marcações
settingNotAvailable: Não disponível na versão demo.

View File

@ -1 +1 @@
1.1.3
1.1.8

View File

@ -5604,6 +5604,11 @@ logalot@^2.0.0, logalot@^2.1.0:
figures "^1.3.5"
squeak "^1.0.0"
logrocket@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/logrocket/-/logrocket-1.0.7.tgz#fe17dbdfc861481cd274fbda533d552de7800a3a"
integrity sha512-v6HWEQIsyG+3FkldB7vIAgHh7/qpsiz2Br4bLK5SHBvjqRrHs/Fp+Jr8oiA2GYq0UurAtCu51U8SWft5+OCKtg==
longest@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"