diff --git a/.travis.yml b/.travis.yml index c7003323..85abbc20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -111,7 +111,7 @@ jobs: env: YARN_GPG=no before_install: - choco install git-lfs -y -f || echo "0" # choco fails but git-lfs is still installed - - choco install ffmpeg + - choco install ffmpeg --version=4.2.3 - export PATH=/C/ProgramData/chocolatey/lib/ffmpeg/tools/ffmpeg/bin:$PATH - wget https://github.com/moiamond/docker-ffmpeg-base-windowsservercore/raw/master/System32/avicap32.dll -P /C/Windows/System32/ - wget https://github.com/moiamond/docker-ffmpeg-base-windowsservercore/raw/master/System32/msvfw32.dll -P /C/Windows/System32/ @@ -129,7 +129,7 @@ jobs: env: YARN_GPG=no before_install: - choco install git-lfs -y -f || echo "0" # choco fails but git-lfs is still installed - - choco install ffmpeg + - choco install ffmpeg --version=4.2.3 - choco install wget - export PATH=/C/ProgramData/chocolatey/lib/ffmpeg/tools/ffmpeg/bin:$PATH - wget https://github.com/moiamond/docker-ffmpeg-base-windowsservercore/raw/master/System32/avicap32.dll -P /C/Windows/System32/ diff --git a/README.md b/README.md index 97087812..5a5847aa 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,9 @@ Your goal is to produce shapes by cutting, rotating, merging and painting parts - Run `git lfs pull` to download sound assets - Make sure `ffmpeg` is on your path - Install Node.js and Yarn -- Run `yarn` in the root folder, then run `yarn` in the `gulp/` folder -- Cd into `gulp` and run `yarn gulp` - it should now open in your browser +- Run `yarn` in the root folder +- Cd into `gulp` folder +- Run `yarn` and then `yarn gulp` - it should now open in your browser **Notice**: This will produce a debug build with several debugging flags enabled. If you want to disable them, modify `config.js`. diff --git a/artwork/.gitignore b/artwork/.gitignore deleted file mode 100644 index fc14a67a..00000000 --- a/artwork/.gitignore +++ /dev/null @@ -1 +0,0 @@ -trailer/ \ No newline at end of file diff --git a/artwork/README.md b/artwork/README.md new file mode 100644 index 00000000..dab59a98 --- /dev/null +++ b/artwork/README.md @@ -0,0 +1,3 @@ +The artwork can be found here: + +https://github.com/tobspr/shapez.io-artwork diff --git a/artwork/buildings/RGB_Icon.psd b/artwork/buildings/RGB_Icon.psd deleted file mode 100644 index ded296c4..00000000 --- a/artwork/buildings/RGB_Icon.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5c424731dff98885b13a360f42933bc0f43635e9b69b62950c4befbfbd21663e -size 230312 diff --git a/artwork/buildings/belt.psd b/artwork/buildings/belt.psd deleted file mode 100644 index 980c52d9..00000000 --- a/artwork/buildings/belt.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:377f61c6947953c3df4f944397e51c87d318f80bb91ba4913de4a1da7f94a7cc -size 379425 diff --git a/artwork/buildings/belt_minimap_shapes.psd b/artwork/buildings/belt_minimap_shapes.psd deleted file mode 100644 index 6da7cd72..00000000 --- a/artwork/buildings/belt_minimap_shapes.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:98d30b113681fcf248ec6c81b53d89fb8006e414ec68862b452a23c216ebfe85 -size 22652 diff --git a/artwork/buildings/buildings_1x1.psd b/artwork/buildings/buildings_1x1.psd deleted file mode 100644 index c4b1abc3..00000000 --- a/artwork/buildings/buildings_1x1.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a83f85517a44fa590a7a5e72b90736ba52065712e537f9eaa0d53aefd6a42457 -size 765795 diff --git a/artwork/buildings/buildings_2x1.psd b/artwork/buildings/buildings_2x1.psd deleted file mode 100644 index 117507a9..00000000 --- a/artwork/buildings/buildings_2x1.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7d05e340acb18f7b6b6f05fa7536f14179cda54a9ead0923fbb8e39c68da148c -size 703229 diff --git a/artwork/buildings/buildings_2x2.psd b/artwork/buildings/buildings_2x2.psd deleted file mode 100644 index 00f31093..00000000 --- a/artwork/buildings/buildings_2x2.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9d8a4254944d83882513a062e77406419d94c3058a7ad657a5a318d45cc5443f -size 902131 diff --git a/artwork/buildings/buildings_3x3.psd b/artwork/buildings/buildings_3x3.psd deleted file mode 100644 index 73ad2e91..00000000 --- a/artwork/buildings/buildings_3x3.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:573954846ee7adff355373ed22ce4cef90c5a1d4b7af928944c2110f6b5120f5 -size 595603 diff --git a/artwork/buildings/buildings_4x1.psd b/artwork/buildings/buildings_4x1.psd deleted file mode 100644 index ffd3decb..00000000 --- a/artwork/buildings/buildings_4x1.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc99dc14248306295ce17761c0cadf369a713ed65e864554e374d20ea9d571af -size 778507 diff --git a/artwork/buildings/extractor.psd b/artwork/buildings/extractor.psd deleted file mode 100644 index c0dfd420..00000000 --- a/artwork/buildings/extractor.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4a4dd431e7ff12f72eb54545c10ba1d5e6dd16119fe1430864a4e449391adebb -size 216421 diff --git a/artwork/buildings/hub.psd b/artwork/buildings/hub.psd deleted file mode 100644 index d025b0c4..00000000 --- a/artwork/buildings/hub.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:95a342ce958586280b9ebc69a41d5cc950915b787de83ddaf101dbb852bdaf86 -size 1179560 diff --git a/artwork/gamedistribution/1280x550.jpg b/artwork/gamedistribution/1280x550.jpg deleted file mode 100644 index 9f5c0f44..00000000 Binary files a/artwork/gamedistribution/1280x550.jpg and /dev/null differ diff --git a/artwork/gamedistribution/1280x550.png b/artwork/gamedistribution/1280x550.png deleted file mode 100644 index 5086af18..00000000 Binary files a/artwork/gamedistribution/1280x550.png and /dev/null differ diff --git a/artwork/gamedistribution/1280x720.jpg b/artwork/gamedistribution/1280x720.jpg deleted file mode 100644 index ea2bb545..00000000 Binary files a/artwork/gamedistribution/1280x720.jpg and /dev/null differ diff --git a/artwork/gamedistribution/1280x720.png b/artwork/gamedistribution/1280x720.png deleted file mode 100644 index 191fe91a..00000000 Binary files a/artwork/gamedistribution/1280x720.png and /dev/null differ diff --git a/artwork/gamedistribution/1280x720.psd b/artwork/gamedistribution/1280x720.psd deleted file mode 100644 index f6bae3e1..00000000 --- a/artwork/gamedistribution/1280x720.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ccae5926d00eee9dd0686b1d415f30e302c53e25d8ca1c9d5517347510cea2b5 -size 11758220 diff --git a/artwork/gamedistribution/512x340.jpg b/artwork/gamedistribution/512x340.jpg deleted file mode 100644 index d34f34af..00000000 Binary files a/artwork/gamedistribution/512x340.jpg and /dev/null differ diff --git a/artwork/gamedistribution/512x340.png b/artwork/gamedistribution/512x340.png deleted file mode 100644 index 33eb371c..00000000 Binary files a/artwork/gamedistribution/512x340.png and /dev/null differ diff --git a/artwork/gamedistribution/512x384.jpg b/artwork/gamedistribution/512x384.jpg deleted file mode 100644 index 77d3b3ad..00000000 Binary files a/artwork/gamedistribution/512x384.jpg and /dev/null differ diff --git a/artwork/gamedistribution/512x384.png b/artwork/gamedistribution/512x384.png deleted file mode 100644 index 65fd95c4..00000000 Binary files a/artwork/gamedistribution/512x384.png and /dev/null differ diff --git a/artwork/gamedistribution/512x384.psd b/artwork/gamedistribution/512x384.psd deleted file mode 100644 index 4c4429de..00000000 --- a/artwork/gamedistribution/512x384.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ac7dc426f618215bf8e62526dfe38d8076c439849ef341f5545561c551625d4 -size 10266632 diff --git a/artwork/gamedistribution/512x512.jpg b/artwork/gamedistribution/512x512.jpg deleted file mode 100644 index db293db4..00000000 Binary files a/artwork/gamedistribution/512x512.jpg and /dev/null differ diff --git a/artwork/gamedistribution/512x512.png b/artwork/gamedistribution/512x512.png deleted file mode 100644 index 81c8b737..00000000 Binary files a/artwork/gamedistribution/512x512.png and /dev/null differ diff --git a/artwork/gamedistribution/iframe/index.html b/artwork/gamedistribution/iframe/index.html deleted file mode 100644 index ac308b68..00000000 --- a/artwork/gamedistribution/iframe/index.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - shapez.io - - - - - - - - - diff --git a/artwork/gamedistribution/iframe/manifest.json b/artwork/gamedistribution/iframe/manifest.json deleted file mode 100644 index 539af604..00000000 --- a/artwork/gamedistribution/iframe/manifest.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "shapez.io", - "short_name": "shapez.io", - "start_url": "index.html", - "display": "standalone", - "background_color": "#222428", - "description": "shapez.io" -} diff --git a/artwork/icon-standalone.ico b/artwork/icon-standalone.ico deleted file mode 100644 index 54721ebf..00000000 Binary files a/artwork/icon-standalone.ico and /dev/null differ diff --git a/artwork/icon-standalone.png b/artwork/icon-standalone.png deleted file mode 100644 index 44994cc9..00000000 Binary files a/artwork/icon-standalone.png and /dev/null differ diff --git a/artwork/icon-standalone.psd b/artwork/icon-standalone.psd deleted file mode 100644 index a972d472..00000000 --- a/artwork/icon-standalone.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a0062684305ff8ac875812f39e565fe00f27b537212b2ad70d68c27fb2ae6f8 -size 224962 diff --git a/artwork/icon.ico b/artwork/icon.ico deleted file mode 100644 index 4ec3676d..00000000 Binary files a/artwork/icon.ico and /dev/null differ diff --git a/artwork/icon.png b/artwork/icon.png deleted file mode 100644 index 64c36eb8..00000000 Binary files a/artwork/icon.png and /dev/null differ diff --git a/artwork/icon.psd b/artwork/icon.psd deleted file mode 100644 index 1e9a7eae..00000000 --- a/artwork/icon.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:22b15510bbe17ebe46b899952fe7cb260271c103e66759544aef0a7fa963d319 -size 209192 diff --git a/artwork/installer/installer.ifp b/artwork/installer/installer.ifp deleted file mode 100644 index 98c09a1e..00000000 Binary files a/artwork/installer/installer.ifp and /dev/null differ diff --git a/artwork/installer/wizard.bmp b/artwork/installer/wizard.bmp deleted file mode 100644 index ae9c43b6..00000000 Binary files a/artwork/installer/wizard.bmp and /dev/null differ diff --git a/artwork/installer/wizard.psd b/artwork/installer/wizard.psd deleted file mode 100644 index 9e74b727..00000000 --- a/artwork/installer/wizard.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f3fa43e6a02c92ac66717aaedde15c41b6694c390165c52a43e5b794b73bc895 -size 1091078 diff --git a/artwork/intial_concept/README.md b/artwork/intial_concept/README.md deleted file mode 100644 index 012abdee..00000000 --- a/artwork/intial_concept/README.md +++ /dev/null @@ -1 +0,0 @@ -This is the initial concept which I made and was the birth of shapez.io diff --git a/artwork/intial_concept/concept-v2.png b/artwork/intial_concept/concept-v2.png deleted file mode 100644 index 2072fc47..00000000 Binary files a/artwork/intial_concept/concept-v2.png and /dev/null differ diff --git a/artwork/intial_concept/concept.png b/artwork/intial_concept/concept.png deleted file mode 100644 index 3c8468df..00000000 Binary files a/artwork/intial_concept/concept.png and /dev/null differ diff --git a/artwork/intial_concept/concept.psd b/artwork/intial_concept/concept.psd deleted file mode 100644 index b1f2218d..00000000 --- a/artwork/intial_concept/concept.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3c5b380e08ed27a1d7c47f2e7c686963a1837bfebce29cce180a741674eb4800 -size 1533043 diff --git a/artwork/itch.io/background.jpg b/artwork/itch.io/background.jpg deleted file mode 100644 index 524b6358..00000000 Binary files a/artwork/itch.io/background.jpg and /dev/null differ diff --git a/artwork/itch.io/banner.png b/artwork/itch.io/banner.png deleted file mode 100644 index 17488ee2..00000000 Binary files a/artwork/itch.io/banner.png and /dev/null differ diff --git a/artwork/itch.io/banner.psd b/artwork/itch.io/banner.psd deleted file mode 100644 index c4203db4..00000000 --- a/artwork/itch.io/banner.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c334d77dabdc40fef4ece56ccef9eaa59b5b6b9381817c234f9bf07d00e676e5 -size 12721033 diff --git a/artwork/itch.io/bg.png b/artwork/itch.io/bg.png deleted file mode 100644 index 425e94d8..00000000 Binary files a/artwork/itch.io/bg.png and /dev/null differ diff --git a/artwork/itch.io/full-page.psd b/artwork/itch.io/full-page.psd deleted file mode 100644 index e33a1b91..00000000 --- a/artwork/itch.io/full-page.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:965ea97e2390927132f2463118ec7b8dd874b838fc770dc7f0ee76bb48ef0527 -size 21376906 diff --git a/artwork/itch.io/screenshots/1.png b/artwork/itch.io/screenshots/1.png deleted file mode 100644 index 75214ff7..00000000 Binary files a/artwork/itch.io/screenshots/1.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/10.png b/artwork/itch.io/screenshots/10.png deleted file mode 100644 index 87308cee..00000000 Binary files a/artwork/itch.io/screenshots/10.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/11.png b/artwork/itch.io/screenshots/11.png deleted file mode 100644 index d2de5570..00000000 Binary files a/artwork/itch.io/screenshots/11.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/2.png b/artwork/itch.io/screenshots/2.png deleted file mode 100644 index 9dd0fc6f..00000000 Binary files a/artwork/itch.io/screenshots/2.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/3.png b/artwork/itch.io/screenshots/3.png deleted file mode 100644 index af0d0ab3..00000000 Binary files a/artwork/itch.io/screenshots/3.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/4.png b/artwork/itch.io/screenshots/4.png deleted file mode 100644 index f4e34386..00000000 Binary files a/artwork/itch.io/screenshots/4.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/5.png b/artwork/itch.io/screenshots/5.png deleted file mode 100644 index b456d816..00000000 Binary files a/artwork/itch.io/screenshots/5.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/6.png b/artwork/itch.io/screenshots/6.png deleted file mode 100644 index bdbbaccf..00000000 Binary files a/artwork/itch.io/screenshots/6.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/7.png b/artwork/itch.io/screenshots/7.png deleted file mode 100644 index 0df86bcc..00000000 Binary files a/artwork/itch.io/screenshots/7.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/8.png b/artwork/itch.io/screenshots/8.png deleted file mode 100644 index 1b3bbdc2..00000000 Binary files a/artwork/itch.io/screenshots/8.png and /dev/null differ diff --git a/artwork/itch.io/screenshots/9.png b/artwork/itch.io/screenshots/9.png deleted file mode 100644 index d9ada467..00000000 Binary files a/artwork/itch.io/screenshots/9.png and /dev/null differ diff --git a/artwork/logo.png b/artwork/logo.png deleted file mode 100644 index 75dd3a35..00000000 Binary files a/artwork/logo.png and /dev/null differ diff --git a/artwork/logo.psd b/artwork/logo.psd deleted file mode 100644 index 04575aa1..00000000 --- a/artwork/logo.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:16f131c43e555211929bfd90468c554416acf9a54f2172dd377bbe4f02b43227 -size 228133 diff --git a/artwork/promo/yorgio-promo.png b/artwork/promo/yorgio-promo.png deleted file mode 100644 index 60ebd785..00000000 Binary files a/artwork/promo/yorgio-promo.png and /dev/null differ diff --git a/artwork/promo/yorgio-promo.psd b/artwork/promo/yorgio-promo.psd deleted file mode 100644 index 589bdaa4..00000000 --- a/artwork/promo/yorgio-promo.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ab0287f69a54c57e725e239a1a6ef35c79d60f4217184fcde7b27ab4d1c0ef60 -size 8866812 diff --git a/artwork/reddit/banner.png b/artwork/reddit/banner.png deleted file mode 100644 index 3982791f..00000000 Binary files a/artwork/reddit/banner.png and /dev/null differ diff --git a/artwork/steam/184x69.png b/artwork/steam/184x69.png deleted file mode 100644 index 6e0a3c0a..00000000 Binary files a/artwork/steam/184x69.png and /dev/null differ diff --git a/artwork/steam/1920x620.png b/artwork/steam/1920x620.png deleted file mode 100644 index 7f659383..00000000 Binary files a/artwork/steam/1920x620.png and /dev/null differ diff --git a/artwork/steam/1920x620.psd b/artwork/steam/1920x620.psd deleted file mode 100644 index fd66178b..00000000 --- a/artwork/steam/1920x620.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b909ed70673b45c3f651a6325f5d0c27d1bfd982bfbc41f964075135c6fede76 -size 23705912 diff --git a/artwork/steam/231x87.png b/artwork/steam/231x87.png deleted file mode 100644 index 73d17031..00000000 Binary files a/artwork/steam/231x87.png and /dev/null differ diff --git a/artwork/steam/32x32.png b/artwork/steam/32x32.png deleted file mode 100644 index 4c1cca09..00000000 Binary files a/artwork/steam/32x32.png and /dev/null differ diff --git a/artwork/steam/32x32.psd b/artwork/steam/32x32.psd deleted file mode 100644 index 9a3c3914..00000000 --- a/artwork/steam/32x32.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f09b39f525b2d1ed094ceec73b792ce75d593e769254154cf32f4df2a429f2ba -size 52046 diff --git a/artwork/steam/444x208.png b/artwork/steam/444x208.png deleted file mode 100644 index e0e7216d..00000000 Binary files a/artwork/steam/444x208.png and /dev/null differ diff --git a/artwork/steam/460x215.png b/artwork/steam/460x215.png deleted file mode 100644 index 69f58a94..00000000 Binary files a/artwork/steam/460x215.png and /dev/null differ diff --git a/artwork/steam/460x215.psd b/artwork/steam/460x215.psd deleted file mode 100644 index 4833668b..00000000 --- a/artwork/steam/460x215.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:12df556b43bb303aa0318a6adff70ff3acd9ac68693ebabf3fab094efecca810 -size 6757896 diff --git a/artwork/steam/600x900.png b/artwork/steam/600x900.png deleted file mode 100644 index 3064b240..00000000 Binary files a/artwork/steam/600x900.png and /dev/null differ diff --git a/artwork/steam/600x900.psd b/artwork/steam/600x900.psd deleted file mode 100644 index b0bffc9e..00000000 --- a/artwork/steam/600x900.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:42015852b1abec0541c10f71acdde226170b60de7b7737282485b738022d8982 -size 11018053 diff --git a/artwork/steam/616x353.png b/artwork/steam/616x353.png deleted file mode 100644 index 58f9352e..00000000 Binary files a/artwork/steam/616x353.png and /dev/null differ diff --git a/artwork/steam/616x353.psd b/artwork/steam/616x353.psd deleted file mode 100644 index ba232882..00000000 --- a/artwork/steam/616x353.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5a5a83129016b75d11af487f42b4bee3d85a48d2894b681d076724c9512aeb31 -size 10334692 diff --git a/artwork/steam/640x360.png b/artwork/steam/640x360.png deleted file mode 100644 index 5f70fb36..00000000 Binary files a/artwork/steam/640x360.png and /dev/null differ diff --git a/artwork/steam/640x360.psd b/artwork/steam/640x360.psd deleted file mode 100644 index 958e9e03..00000000 --- a/artwork/steam/640x360.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:20ca95838254a46d4c23f4c24b7877eaad60aa1aeed3df087b242f389e428774 -size 156876 diff --git a/artwork/steam/announcement-cover.png b/artwork/steam/announcement-cover.png deleted file mode 100644 index 60af9100..00000000 Binary files a/artwork/steam/announcement-cover.png and /dev/null differ diff --git a/artwork/steam/announcement.png b/artwork/steam/announcement.png deleted file mode 100644 index cc0861db..00000000 Binary files a/artwork/steam/announcement.png and /dev/null differ diff --git a/artwork/steam/announcement.psd b/artwork/steam/announcement.psd deleted file mode 100644 index 518a49ac..00000000 --- a/artwork/steam/announcement.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ae83b8805191eeba13016e40216fc4781ac3958e6886769ce8677ea28370d13e -size 239706 diff --git a/artwork/steam/devlog.png b/artwork/steam/devlog.png deleted file mode 100644 index 9abdefe1..00000000 Binary files a/artwork/steam/devlog.png and /dev/null differ diff --git a/artwork/steam/devlog.psd b/artwork/steam/devlog.psd deleted file mode 100644 index 7cd9b0a7..00000000 --- a/artwork/steam/devlog.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:40d458f800344d819ad4d3f38943f53f399258369ee5c20f6583d1b49847465f -size 188255 diff --git a/artwork/steam/screenshots/1.png b/artwork/steam/screenshots/1.png deleted file mode 100644 index ff85b1dc..00000000 Binary files a/artwork/steam/screenshots/1.png and /dev/null differ diff --git a/artwork/steam/screenshots/10.png b/artwork/steam/screenshots/10.png deleted file mode 100644 index f7afe0a8..00000000 Binary files a/artwork/steam/screenshots/10.png and /dev/null differ diff --git a/artwork/steam/screenshots/11.png b/artwork/steam/screenshots/11.png deleted file mode 100644 index 6ef87b38..00000000 Binary files a/artwork/steam/screenshots/11.png and /dev/null differ diff --git a/artwork/steam/screenshots/2.png b/artwork/steam/screenshots/2.png deleted file mode 100644 index fd3b5d1c..00000000 Binary files a/artwork/steam/screenshots/2.png and /dev/null differ diff --git a/artwork/steam/screenshots/3.png b/artwork/steam/screenshots/3.png deleted file mode 100644 index 4b6e5d6a..00000000 Binary files a/artwork/steam/screenshots/3.png and /dev/null differ diff --git a/artwork/steam/screenshots/4.png b/artwork/steam/screenshots/4.png deleted file mode 100644 index 4ee5bfdc..00000000 Binary files a/artwork/steam/screenshots/4.png and /dev/null differ diff --git a/artwork/steam/screenshots/5.png b/artwork/steam/screenshots/5.png deleted file mode 100644 index cb2fa743..00000000 Binary files a/artwork/steam/screenshots/5.png and /dev/null differ diff --git a/artwork/steam/screenshots/6.png b/artwork/steam/screenshots/6.png deleted file mode 100644 index e0182e70..00000000 Binary files a/artwork/steam/screenshots/6.png and /dev/null differ diff --git a/artwork/steam/screenshots/7.png b/artwork/steam/screenshots/7.png deleted file mode 100644 index 9da8d817..00000000 Binary files a/artwork/steam/screenshots/7.png and /dev/null differ diff --git a/artwork/steam/screenshots/8.png b/artwork/steam/screenshots/8.png deleted file mode 100644 index f09363f7..00000000 Binary files a/artwork/steam/screenshots/8.png and /dev/null differ diff --git a/artwork/steam/screenshots/9.png b/artwork/steam/screenshots/9.png deleted file mode 100644 index 9bf9534f..00000000 Binary files a/artwork/steam/screenshots/9.png and /dev/null differ diff --git a/artwork/steam/store_page_gif.gif b/artwork/steam/store_page_gif.gif deleted file mode 100644 index 1491fb0a..00000000 Binary files a/artwork/steam/store_page_gif.gif and /dev/null differ diff --git a/artwork/thirdparty/armorgames/162x100.png b/artwork/thirdparty/armorgames/162x100.png deleted file mode 100644 index aede09f3..00000000 Binary files a/artwork/thirdparty/armorgames/162x100.png and /dev/null differ diff --git a/artwork/thirdparty/armorgames/162x100.psd b/artwork/thirdparty/armorgames/162x100.psd deleted file mode 100644 index c0c4160f..00000000 --- a/artwork/thirdparty/armorgames/162x100.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f119ae5afd23eb038b9cb55699ea02b5908c8c4d67a0b06e91934ca41eb123fa -size 143528 diff --git a/artwork/thirdparty/armorgames/620x320.png b/artwork/thirdparty/armorgames/620x320.png deleted file mode 100644 index 8f0ff84d..00000000 Binary files a/artwork/thirdparty/armorgames/620x320.png and /dev/null differ diff --git a/artwork/thirdparty/armorgames/620x320.psd b/artwork/thirdparty/armorgames/620x320.psd deleted file mode 100644 index b0e3df6b..00000000 --- a/artwork/thirdparty/armorgames/620x320.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1c1b98562af8362919fe67e90fbf18033ef48ca3b394072f08ab2b3e2711a594 -size 1440735 diff --git a/artwork/thirdparty/armorgames/icon.png b/artwork/thirdparty/armorgames/icon.png deleted file mode 100644 index 4d78ff80..00000000 Binary files a/artwork/thirdparty/armorgames/icon.png and /dev/null differ diff --git a/artwork/thirdparty/armorgames/icon.psd b/artwork/thirdparty/armorgames/icon.psd deleted file mode 100644 index 1cca09a5..00000000 --- a/artwork/thirdparty/armorgames/icon.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1d523d3aff76713cbce90986d86e33d1b937ccefadbd6958e2d90b25cd6ed47b -size 40609 diff --git a/artwork/thirdparty/armorgames/index.html b/artwork/thirdparty/armorgames/index.html deleted file mode 100644 index 2b2da26d..00000000 --- a/artwork/thirdparty/armorgames/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - shapez.io - - - - - - You will be redirected soon - - diff --git a/artwork/thirdparty/armorgames/index.zip b/artwork/thirdparty/armorgames/index.zip deleted file mode 100644 index 02aa81f0..00000000 Binary files a/artwork/thirdparty/armorgames/index.zip and /dev/null differ diff --git a/artwork/thirdparty/iogames.space/thumb.png b/artwork/thirdparty/iogames.space/thumb.png deleted file mode 100644 index 9f36f7b2..00000000 Binary files a/artwork/thirdparty/iogames.space/thumb.png and /dev/null differ diff --git a/artwork/thirdparty/iogames.space/thumb.psd b/artwork/thirdparty/iogames.space/thumb.psd deleted file mode 100644 index 93d392df..00000000 --- a/artwork/thirdparty/iogames.space/thumb.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fb09261c4d8f26cbf3c79f9e283a59d2bf9b54c8f360794a4696644edbcbcaa9 -size 8895432 diff --git a/artwork/thirdparty/kongregate/icon.png b/artwork/thirdparty/kongregate/icon.png deleted file mode 100644 index dc742197..00000000 Binary files a/artwork/thirdparty/kongregate/icon.png and /dev/null differ diff --git a/artwork/thirdparty/kongregate/icon.psd b/artwork/thirdparty/kongregate/icon.psd deleted file mode 100644 index 25835670..00000000 --- a/artwork/thirdparty/kongregate/icon.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:406ddccda44fd026d5a435ff80c418fa007f0252fb5ac13165514d5da9186065 -size 10271381 diff --git a/artwork/thirdparty/kongregate/iframe.html b/artwork/thirdparty/kongregate/iframe.html deleted file mode 100644 index 6b741420..00000000 --- a/artwork/thirdparty/kongregate/iframe.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - Iframe test - - - - - diff --git a/artwork/thirdparty/kongregate/index.html b/artwork/thirdparty/kongregate/index.html deleted file mode 100644 index ce19f275..00000000 --- a/artwork/thirdparty/kongregate/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - Redirecting to shapez.io - - - - - Redirecting you to - shapez.io - - diff --git a/artwork/thirdparty/miniclip/150x110.psd b/artwork/thirdparty/miniclip/150x110.psd deleted file mode 100644 index e4677214..00000000 --- a/artwork/thirdparty/miniclip/150x110.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:525a1f60529723c8e534233adbbbd8ff8c6d5fec25360f35c77f787166fb0526 -size 7666025 diff --git a/artwork/thirdparty/miniclip/216x287.psd b/artwork/thirdparty/miniclip/216x287.psd deleted file mode 100644 index 1e535a14..00000000 --- a/artwork/thirdparty/miniclip/216x287.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:064c6e73648537b2c6225784dd56ed37bdf46c5e3b1106e05278243f1d86cb8d -size 1136861 diff --git a/artwork/thirdparty/miniclip/444x287.psd b/artwork/thirdparty/miniclip/444x287.psd deleted file mode 100644 index ced5937b..00000000 --- a/artwork/thirdparty/miniclip/444x287.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0989c0e5d438247599f37e6c5bda458ff4bd0dcda5b7a0e5c392c2a98ac14c80 -size 9068311 diff --git a/artwork/thirdparty/miniclip/512x512.psd b/artwork/thirdparty/miniclip/512x512.psd deleted file mode 100644 index b4efeec9..00000000 --- a/artwork/thirdparty/miniclip/512x512.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aad36634a8b25092fab68560668c56abeac1ef4f5f0f52e805cc5e2a6c4ca6bb -size 2535755 diff --git a/artwork/thirdparty/miniclip/70x59.psd b/artwork/thirdparty/miniclip/70x59.psd deleted file mode 100644 index fa13ab2d..00000000 --- a/artwork/thirdparty/miniclip/70x59.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:23c3cb1a03dd1986d5dc7385762bbbf000b1b5adc5c1b5f202d79651aaae8fc7 -size 801189 diff --git a/artwork/thirdparty/miniclip/shapezio-miniclip-assets.zip b/artwork/thirdparty/miniclip/shapezio-miniclip-assets.zip deleted file mode 100644 index 53b2b380..00000000 Binary files a/artwork/thirdparty/miniclip/shapezio-miniclip-assets.zip and /dev/null differ diff --git a/artwork/thirdparty/miniclip/shapezio__150x110.png b/artwork/thirdparty/miniclip/shapezio__150x110.png deleted file mode 100644 index c4696af6..00000000 Binary files a/artwork/thirdparty/miniclip/shapezio__150x110.png and /dev/null differ diff --git a/artwork/thirdparty/miniclip/shapezio__216x287.png b/artwork/thirdparty/miniclip/shapezio__216x287.png deleted file mode 100644 index eba64e2c..00000000 Binary files a/artwork/thirdparty/miniclip/shapezio__216x287.png and /dev/null differ diff --git a/artwork/thirdparty/miniclip/shapezio__444x287.png b/artwork/thirdparty/miniclip/shapezio__444x287.png deleted file mode 100644 index 335fd664..00000000 Binary files a/artwork/thirdparty/miniclip/shapezio__444x287.png and /dev/null differ diff --git a/artwork/thirdparty/miniclip/shapezio__512x512.png b/artwork/thirdparty/miniclip/shapezio__512x512.png deleted file mode 100644 index 81c8b737..00000000 Binary files a/artwork/thirdparty/miniclip/shapezio__512x512.png and /dev/null differ diff --git a/artwork/thirdparty/miniclip/shapezio__70x59.png b/artwork/thirdparty/miniclip/shapezio__70x59.png deleted file mode 100644 index a982eaf3..00000000 Binary files a/artwork/thirdparty/miniclip/shapezio__70x59.png and /dev/null differ diff --git a/artwork/tutorial_videos/level_1.webm b/artwork/tutorial_videos/level_1.webm deleted file mode 100644 index c14a3918..00000000 --- a/artwork/tutorial_videos/level_1.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bc60f1f38c775874047967fea3b81350b8b62496fd276e89227ce3b3bd8f593b -size 1038054 diff --git a/artwork/tutorial_videos/level_10.webm b/artwork/tutorial_videos/level_10.webm deleted file mode 100644 index aa1124a3..00000000 --- a/artwork/tutorial_videos/level_10.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:db8026c2a132c9d2f016986dc7a66127254c725c068eaae60909ddff6d50a210 -size 2397175 diff --git a/artwork/tutorial_videos/level_11.webm b/artwork/tutorial_videos/level_11.webm deleted file mode 100644 index 29a782a7..00000000 --- a/artwork/tutorial_videos/level_11.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ce02cec04d080b2114822e9241a9baa073a56f38dd0c52e235373fd8ae2f856d -size 1105340 diff --git a/artwork/tutorial_videos/level_2.webm b/artwork/tutorial_videos/level_2.webm deleted file mode 100644 index 775c8629..00000000 --- a/artwork/tutorial_videos/level_2.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:68e0987d534972b90a40b814180c19eb69100a8661295388c4237cbb3ee3b907 -size 2029655 diff --git a/artwork/tutorial_videos/level_3.webm b/artwork/tutorial_videos/level_3.webm deleted file mode 100644 index c20b650a..00000000 --- a/artwork/tutorial_videos/level_3.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2afc6b142575631260ef546c4e47e444cb47bf20668635d69babe77d7771e71f -size 1651886 diff --git a/artwork/tutorial_videos/level_4.webm b/artwork/tutorial_videos/level_4.webm deleted file mode 100644 index a0fe2602..00000000 --- a/artwork/tutorial_videos/level_4.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0790736c943db421ec09cef70df722dbd7c3ff25dbad8cfd711a68c4b4806dcd -size 1467335 diff --git a/artwork/tutorial_videos/level_5.webm b/artwork/tutorial_videos/level_5.webm deleted file mode 100644 index 60292038..00000000 --- a/artwork/tutorial_videos/level_5.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0c8e8f9ebb7523c50d7a8797ec1830c1669bd4dbe233295274b17c08ba52cdf5 -size 2063527 diff --git a/artwork/tutorial_videos/level_6.webm b/artwork/tutorial_videos/level_6.webm deleted file mode 100644 index 6ba82c0c..00000000 --- a/artwork/tutorial_videos/level_6.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:95a9f337551e9c9a0064f28ac20cf51f6a76f9f44e0163b458db9dacc36feaa4 -size 3892951 diff --git a/artwork/tutorial_videos/level_7.webm b/artwork/tutorial_videos/level_7.webm deleted file mode 100644 index 55b5f70b..00000000 --- a/artwork/tutorial_videos/level_7.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:25d07f2a8facbd7faf8710ed86e882743bfc46dece51d80ee959be239dd0f482 -size 3188174 diff --git a/artwork/tutorial_videos/level_9.webm b/artwork/tutorial_videos/level_9.webm deleted file mode 100644 index 40e240e2..00000000 --- a/artwork/tutorial_videos/level_9.webm +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a996fc3605f4ef180a7985f2a74621510489cc88b2b8a97a9dc1bd19566383b7 -size 1727787 diff --git a/artwork/twitch/box-image.jpg b/artwork/twitch/box-image.jpg deleted file mode 100644 index 90526447..00000000 Binary files a/artwork/twitch/box-image.jpg and /dev/null differ diff --git a/artwork/twitch/box-image.psd b/artwork/twitch/box-image.psd deleted file mode 100644 index ea3443fe..00000000 --- a/artwork/twitch/box-image.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0cd2d82917e470202d38d32277f7519ccfd1821cb21791266539ddf07486d1b -size 7314327 diff --git a/artwork/ui/building_tutorials.psd b/artwork/ui/building_tutorials.psd deleted file mode 100644 index 5d35a9f4..00000000 --- a/artwork/ui/building_tutorials.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e519ee86412cc34446e2315e6c4ffa9aa93aaa034e511dc6d80d92e5bb953d3f -size 14461756 diff --git a/artwork/ui/debug_arrows.psd b/artwork/ui/debug_arrows.psd deleted file mode 100644 index e9421289..00000000 --- a/artwork/ui/debug_arrows.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c5502e112c14310aa90e0137b8153b7acecf91e9c0311191b903d87bb10b99a1 -size 26245 diff --git a/artwork/ui/ejector_arrow.psd b/artwork/ui/ejector_arrow.psd deleted file mode 100644 index c6b201ac..00000000 --- a/artwork/ui/ejector_arrow.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2628ddad3e861d403ceee1d8f736f11d8c79d2ab597ae9e7939fed6f9dc5fc69 -size 65914 diff --git a/artwork/ui/get_on_steam.psd b/artwork/ui/get_on_steam.psd deleted file mode 100644 index 36a11a89..00000000 --- a/artwork/ui/get_on_steam.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:27d142e1f200f474af2cb622774248f42225c45836ce5d0b0badd5c17b78ae86 -size 198569 diff --git a/artwork/ui/storage_overlay.psd b/artwork/ui/storage_overlay.psd deleted file mode 100644 index 78052848..00000000 --- a/artwork/ui/storage_overlay.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c289cd61980aaf502fe4eda8591b2a2684137c85ca37d927598f916449f70de4 -size 38930 diff --git a/artwork/ui/toolbar-icons.psd b/artwork/ui/toolbar-icons.psd deleted file mode 100644 index 9b453e15..00000000 --- a/artwork/ui/toolbar-icons.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:27c8d1eaa48beb7187e37244bd6ef7f43429be84ac88fffa96a4d72eb0e6565b -size 158809 diff --git a/artwork/ui/toolbar_background.psd b/artwork/ui/toolbar_background.psd deleted file mode 100644 index d4dc44b0..00000000 --- a/artwork/ui/toolbar_background.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bcde4f1a9e2a7b1ec77f904fe248a9cabfeed9eec9aea31d25627a46da1f8b7f -size 48317 diff --git a/artwork/ui/vignette.psd b/artwork/ui/vignette.psd deleted file mode 100644 index 6769736c..00000000 --- a/artwork/ui/vignette.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b9b171450a2713faaa0eb41ea052da8ee67d4ded246b01ec92f322a25b989a51 -size 113869 diff --git a/artwork/wires/prefab.png b/artwork/wires/prefab.png deleted file mode 100644 index 99df19b8..00000000 Binary files a/artwork/wires/prefab.png and /dev/null differ diff --git a/artwork/wires/prefab.psd b/artwork/wires/prefab.psd deleted file mode 100644 index 71c38097..00000000 --- a/artwork/wires/prefab.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:498dea7314b8720c40dcd8bdd64b1b4a7a35259b2ffe7e896fc3db22878d6414 -size 1954036 diff --git a/gulp/ftp.js b/gulp/ftp.js index 2d342ac4..d41bccb6 100644 --- a/gulp/ftp.js +++ b/gulp/ftp.js @@ -15,6 +15,11 @@ function gulptasksFTP($, gulp, buildFolder) { ]; const credentials = { + alpha: { + host: process.env.SHAPEZ_CLI_SERVER_HOST, + user: process.env.SHAPEZ_CLI_ALPHA_FTP_USER, + pass: process.env.SHAPEZ_CLI_ALPHA_FTP_PW, + }, staging: { host: process.env.SHAPEZ_CLI_SERVER_HOST, user: process.env.SHAPEZ_CLI_STAGING_FTP_USER, @@ -51,7 +56,7 @@ function gulptasksFTP($, gulp, buildFolder) { path.join(buildFolder, "!**/index.html"), ]; - for (const deployEnv of ["prod", "staging"]) { + for (const deployEnv of ["alpha", "prod", "staging"]) { const deployCredentials = credentials[deployEnv]; gulp.task(`ftp.upload.${deployEnv}.game`, () => { diff --git a/gulp/gulpfile.js b/gulp/gulpfile.js index f2fdd9d4..0db3f729 100644 --- a/gulp/gulpfile.js +++ b/gulp/gulpfile.js @@ -36,12 +36,12 @@ const $ = require("gulp-load-plugins")({ const envVars = [ "SHAPEZ_CLI_SERVER_HOST", // "SHAPEZ_CLI_PHONEGAP_KEY", + "SHAPEZ_CLI_ALPHA_FTP_USER", + "SHAPEZ_CLI_ALPHA_FTP_PW", "SHAPEZ_CLI_STAGING_FTP_USER", "SHAPEZ_CLI_STAGING_FTP_PW", "SHAPEZ_CLI_LIVE_FTP_USER", "SHAPEZ_CLI_LIVE_FTP_PW", - // "SHAPEZ_CLI_TRANSREPORT_FTP_USER", - // "SHAPEZ_CLI_TRANSREPORT_FTP_PW", ]; for (let i = 0; i < envVars.length; ++i) { @@ -104,11 +104,14 @@ gulp.task("utils.requireCleanWorkingTree", cb => { let output = $.trim(execSync("git status -su").toString("ascii")).replace(/\r/gi, "").split("\n"); // Filter files which are OK to be untracked - output = output.filter(x => x.indexOf(".local.js") < 0); + output = output + .map(x => x.replace(/[\r\n]+/gi, "")) + .filter(x => x.indexOf(".local.js") < 0) + .filter(x => x.length > 0); if (output.length > 0) { console.error("\n\nYou have unstaged changes, please commit everything first!"); console.error("Unstaged files:"); - console.error(output.join("\n")); + console.error(output.map(x => "'" + x + "'").join("\n")); process.exit(1); } cb(); @@ -297,6 +300,10 @@ gulp.task( ); // Deploying! +gulp.task( + "main.deploy.alpha", + gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.alpha") +); gulp.task( "main.deploy.staging", gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.staging") diff --git a/gulp/standalone.js b/gulp/standalone.js index f5126780..c4f33417 100644 --- a/gulp/standalone.js +++ b/gulp/standalone.js @@ -158,8 +158,11 @@ function gulptasksStandalone($, gulp, buildFolder) { fs.writeFileSync(path.join(appPath, ".itch.toml"), tomlFile); - if (platform === "linux" || platform === "darwin") { - fs.writeFileSync(path.join(appPath, "play.sh"), "#!/usr/bin/env bash\n./shapezio\n"); + if (platform === "linux") { + fs.writeFileSync( + path.join(appPath, "play.sh"), + '#!/usr/bin/env bash\n./shapezio --no-sandbox "$@"\n' + ); fs.chmodSync(path.join(appPath, "play.sh"), 0o775); } else if (platform === "win32") { // Optional: Create a playable copy. Shouldn't be required @@ -175,6 +178,43 @@ function gulptasksStandalone($, gulp, buildFolder) { // "start shapezio --local --dev --disable-direct-composition --in-process-gpu\r\n" // ); } + + if (platform === "darwin") { + // Clear up framework folders + fs.writeFileSync( + path.join(appPath, "play.sh"), + '#!/usr/bin/env bash\n./shapez.io-standalone.app/Contents/MacOS/shapezio --no-sandbox "$@"\n' + ); + fs.chmodSync(path.join(appPath, "play.sh"), 0o775); + fs.chmodSync( + path.join(appPath, "shapez.io-standalone.app", "Contents", "MacOS", "shapezio"), + 0o775 + ); + + const finalPath = path.join(appPath, "shapez.io-standalone.app"); + + const frameworksDir = path.join(finalPath, "Contents", "Frameworks"); + const frameworkFolders = fs + .readdirSync(frameworksDir) + .filter(fname => fname.endsWith(".framework")); + + for (let i = 0; i < frameworkFolders.length; ++i) { + const folderName = frameworkFolders[i]; + const frameworkFolder = path.join(frameworksDir, folderName); + console.log(" -> ", frameworkFolder); + + const filesToDelete = fs + .readdirSync(frameworkFolder) + .filter(fname => fname.toLowerCase() !== "versions"); + filesToDelete.forEach(fname => { + console.log(" -> Deleting", fname); + fs.unlinkSync(path.join(frameworkFolder, fname)); + }); + + const frameworkSourceDir = path.join(frameworkFolder, "Versions", "A"); + fse.copySync(frameworkSourceDir, frameworkFolder); + } + } }); cb(); diff --git a/gulp/webpack.production.config.js b/gulp/webpack.production.config.js index f80a69d2..1b89283f 100644 --- a/gulp/webpack.production.config.js +++ b/gulp/webpack.production.config.js @@ -105,6 +105,8 @@ module.exports = ({ passes: 2, module: true, pure_funcs: [ + "Math.radians", + "Math.degrees", "Math.round", "Math.ceil", "Math.floor", @@ -119,21 +121,6 @@ module.exports = ({ "Math.sign", "Math.pow", "Math.atan2", - - "Math_round", - "Math_ceil", - "Math_floor", - "Math_sqrt", - "Math_hypot", - "Math_abs", - "Math_max", - "Math_min", - "Math_sin", - "Math_cos", - "Math_tan", - "Math_sign", - "Math_pow", - "Math_atan2", ], toplevel: true, unsafe_math: true, @@ -215,6 +202,13 @@ module.exports = ({ end: "dev:end", }, }, + { + loader: "webpack-strip-block", + options: { + start: "wires:start", + end: "wires:end", + }, + }, ], }, { @@ -238,7 +232,6 @@ module.exports = ({ pattern: /globalConfig\.beltSpeedItemsPerSecond/g, replacement: () => "2.0", }, - { pattern: /globalConfig\.itemSpacingOnBelts/g, replacement: () => "0.63" }, { pattern: /globalConfig\.debug/g, replacement: () => "''" }, ], }), diff --git a/res/ui/building_icons/advanced_processor.png b/res/ui/building_icons/advanced_processor.png new file mode 100644 index 00000000..c1423b09 Binary files /dev/null and b/res/ui/building_icons/advanced_processor.png differ diff --git a/res/ui/building_icons/wire.png b/res/ui/building_icons/wire.png new file mode 100644 index 00000000..e6ccb3a6 Binary files /dev/null and b/res/ui/building_icons/wire.png differ diff --git a/res/ui/building_icons/wire_crossings.png b/res/ui/building_icons/wire_crossings.png new file mode 100644 index 00000000..29ea7123 Binary files /dev/null and b/res/ui/building_icons/wire_crossings.png differ diff --git a/res/ui/languages/zh-TW.svg b/res/ui/languages/zh-TW.svg index f89219a0..c3dab661 100644 --- a/res/ui/languages/zh-TW.svg +++ b/res/ui/languages/zh-TW.svg @@ -1,14 +1,15 @@ - - - - - - - - - + + + + + + diff --git a/res_built/atlas/atlas0_10.json b/res_built/atlas/atlas0_10.json index 342ea730..e20ae7b7 100644 --- a/res_built/atlas/atlas0_10.json +++ b/res_built/atlas/atlas0_10.json @@ -1,158 +1,6 @@ {"frames": { "sprites/belt/forward_0.png": -{ - "frame": {"x":205,"y":110,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_1.png": -{ - "frame": {"x":222,"y":110,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_2.png": -{ - "frame": {"x":311,"y":26,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_3.png": -{ - "frame": {"x":379,"y":26,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_4.png": -{ - "frame": {"x":376,"y":66,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_5.png": -{ - "frame": {"x":396,"y":26,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_6.png": -{ - "frame": {"x":393,"y":66,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_7.png": -{ - "frame": {"x":413,"y":26,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_8.png": -{ - "frame": {"x":410,"y":66,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_9.png": -{ - "frame": {"x":430,"y":26,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_10.png": -{ - "frame": {"x":239,"y":110,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_11.png": -{ - "frame": {"x":206,"y":68,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_12.png": -{ - "frame": {"x":223,"y":68,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_13.png": -{ - "frame": {"x":240,"y":68,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_14.png": -{ - "frame": {"x":243,"y":26,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_15.png": -{ - "frame": {"x":260,"y":26,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_16.png": -{ - "frame": {"x":277,"y":26,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_17.png": -{ - "frame": {"x":257,"y":66,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_18.png": -{ - "frame": {"x":274,"y":66,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_19.png": { "frame": {"x":294,"y":26,"w":13,"h":13}, "rotated": false, @@ -160,7 +8,79 @@ "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, "sourceSize": {"w":13,"h":13} }, -"sprites/belt/forward_20.png": +"sprites/belt/forward_1.png": +{ + "frame": {"x":311,"y":26,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_2.png": +{ + "frame": {"x":487,"y":43,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_3.png": +{ + "frame": {"x":521,"y":40,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_4.png": +{ + "frame": {"x":522,"y":23,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_5.png": +{ + "frame": {"x":527,"y":3,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_6.png": +{ + "frame": {"x":504,"y":94,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_7.png": +{ + "frame": {"x":516,"y":77,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_8.png": +{ + "frame": {"x":504,"y":111,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_9.png": +{ + "frame": {"x":523,"y":57,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_10.png": { "frame": {"x":328,"y":26,"w":13,"h":13}, "rotated": false, @@ -168,31 +88,7 @@ "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, "sourceSize": {"w":13,"h":13} }, -"sprites/belt/forward_21.png": -{ - "frame": {"x":291,"y":66,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_22.png": -{ - "frame": {"x":308,"y":66,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_23.png": -{ - "frame": {"x":325,"y":66,"w":13,"h":13}, - "rotated": false, - "trimmed": false, - "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, - "sourceSize": {"w":13,"h":13} -}, -"sprites/belt/forward_24.png": +"sprites/belt/forward_11.png": { "frame": {"x":345,"y":26,"w":13,"h":13}, "rotated": false, @@ -200,7 +96,7 @@ "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, "sourceSize": {"w":13,"h":13} }, -"sprites/belt/forward_25.png": +"sprites/belt/forward_12.png": { "frame": {"x":362,"y":26,"w":13,"h":13}, "rotated": false, @@ -208,9 +104,113 @@ "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, "sourceSize": {"w":13,"h":13} }, +"sprites/belt/forward_13.png": +{ + "frame": {"x":379,"y":26,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_14.png": +{ + "frame": {"x":396,"y":26,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_15.png": +{ + "frame": {"x":413,"y":49,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_16.png": +{ + "frame": {"x":430,"y":49,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_17.png": +{ + "frame": {"x":436,"y":111,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_18.png": +{ + "frame": {"x":453,"y":111,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_19.png": +{ + "frame": {"x":447,"y":49,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_20.png": +{ + "frame": {"x":470,"y":105,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_21.png": +{ + "frame": {"x":482,"y":84,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_22.png": +{ + "frame": {"x":489,"y":60,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_23.png": +{ + "frame": {"x":504,"y":43,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_24.png": +{ + "frame": {"x":505,"y":23,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/belt/forward_25.png": +{ + "frame": {"x":487,"y":101,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, "sprites/belt/forward_26.png": { - "frame": {"x":342,"y":66,"w":13,"h":13}, + "frame": {"x":499,"y":77,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -218,7 +218,7 @@ }, "sprites/belt/forward_27.png": { - "frame": {"x":359,"y":66,"w":13,"h":13}, + "frame": {"x":506,"y":60,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -226,7 +226,7 @@ }, "sprites/belt/left_0.png": { - "frame": {"x":443,"y":83,"w":13,"h":13}, + "frame": {"x":538,"y":40,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -234,7 +234,7 @@ }, "sprites/belt/left_1.png": { - "frame": {"x":450,"y":63,"w":13,"h":13}, + "frame": {"x":539,"y":20,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -242,7 +242,7 @@ }, "sprites/belt/left_2.png": { - "frame": {"x":484,"y":3,"w":13,"h":13}, + "frame": {"x":557,"y":54,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -250,7 +250,7 @@ }, "sprites/belt/left_3.png": { - "frame": {"x":501,"y":54,"w":13,"h":13}, + "frame": {"x":590,"y":20,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -258,7 +258,7 @@ }, "sprites/belt/left_4.png": { - "frame": {"x":513,"y":37,"w":13,"h":13}, + "frame": {"x":595,"y":3,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -266,7 +266,7 @@ }, "sprites/belt/left_5.png": { - "frame": {"x":515,"y":20,"w":13,"h":13}, + "frame": {"x":555,"y":108,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -274,7 +274,7 @@ }, "sprites/belt/left_6.png": { - "frame": {"x":518,"y":3,"w":13,"h":13}, + "frame": {"x":572,"y":88,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -282,7 +282,7 @@ }, "sprites/belt/left_7.png": { - "frame": {"x":485,"y":105,"w":13,"h":13}, + "frame": {"x":584,"y":71,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -290,7 +290,7 @@ }, "sprites/belt/left_8.png": { - "frame": {"x":497,"y":88,"w":13,"h":13}, + "frame": {"x":591,"y":54,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -298,7 +298,7 @@ }, "sprites/belt/left_9.png": { - "frame": {"x":511,"y":71,"w":13,"h":13}, + "frame": {"x":606,"y":37,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -306,7 +306,7 @@ }, "sprites/belt/left_10.png": { - "frame": {"x":460,"y":80,"w":13,"h":13}, + "frame": {"x":544,"y":3,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -314,7 +314,7 @@ }, "sprites/belt/left_11.png": { - "frame": {"x":433,"y":3,"w":13,"h":13}, + "frame": {"x":521,"y":94,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -322,7 +322,7 @@ }, "sprites/belt/left_12.png": { - "frame": {"x":447,"y":20,"w":13,"h":13}, + "frame": {"x":521,"y":111,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -330,7 +330,7 @@ }, "sprites/belt/left_13.png": { - "frame": {"x":450,"y":3,"w":13,"h":13}, + "frame": {"x":533,"y":74,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -338,7 +338,7 @@ }, "sprites/belt/left_14.png": { - "frame": {"x":462,"y":37,"w":13,"h":13}, + "frame": {"x":540,"y":57,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -346,7 +346,7 @@ }, "sprites/belt/left_15.png": { - "frame": {"x":464,"y":20,"w":13,"h":13}, + "frame": {"x":555,"y":37,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -354,7 +354,7 @@ }, "sprites/belt/left_16.png": { - "frame": {"x":467,"y":3,"w":13,"h":13}, + "frame": {"x":556,"y":20,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -362,7 +362,7 @@ }, "sprites/belt/left_17.png": { - "frame": {"x":467,"y":54,"w":13,"h":13}, + "frame": {"x":561,"y":3,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -370,7 +370,7 @@ }, "sprites/belt/left_18.png": { - "frame": {"x":479,"y":37,"w":13,"h":13}, + "frame": {"x":538,"y":91,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -378,7 +378,7 @@ }, "sprites/belt/left_19.png": { - "frame": {"x":481,"y":20,"w":13,"h":13}, + "frame": {"x":550,"y":74,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -386,7 +386,7 @@ }, "sprites/belt/left_20.png": { - "frame": {"x":463,"y":97,"w":13,"h":13}, + "frame": {"x":572,"y":37,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -394,7 +394,7 @@ }, "sprites/belt/left_21.png": { - "frame": {"x":477,"y":71,"w":13,"h":13}, + "frame": {"x":573,"y":20,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -402,7 +402,7 @@ }, "sprites/belt/left_22.png": { - "frame": {"x":484,"y":54,"w":13,"h":13}, + "frame": {"x":578,"y":3,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -410,7 +410,7 @@ }, "sprites/belt/left_23.png": { - "frame": {"x":496,"y":37,"w":13,"h":13}, + "frame": {"x":538,"y":108,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -418,7 +418,7 @@ }, "sprites/belt/left_24.png": { - "frame": {"x":498,"y":20,"w":13,"h":13}, + "frame": {"x":555,"y":91,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -426,7 +426,7 @@ }, "sprites/belt/left_25.png": { - "frame": {"x":501,"y":3,"w":13,"h":13}, + "frame": {"x":567,"y":71,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -434,7 +434,7 @@ }, "sprites/belt/left_26.png": { - "frame": {"x":480,"y":88,"w":13,"h":13}, + "frame": {"x":574,"y":54,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -442,7 +442,7 @@ }, "sprites/belt/left_27.png": { - "frame": {"x":494,"y":71,"w":13,"h":13}, + "frame": {"x":589,"y":37,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -450,7 +450,7 @@ }, "sprites/belt/right_0.png": { - "frame": {"x":518,"y":54,"w":13,"h":13}, + "frame": {"x":607,"y":20,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -458,7 +458,7 @@ }, "sprites/belt/right_1.png": { - "frame": {"x":530,"y":37,"w":13,"h":13}, + "frame": {"x":612,"y":3,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -466,7 +466,7 @@ }, "sprites/belt/right_2.png": { - "frame": {"x":531,"y":88,"w":13,"h":13}, + "frame": {"x":625,"y":54,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -474,7 +474,7 @@ }, "sprites/belt/right_3.png": { - "frame": {"x":569,"y":54,"w":13,"h":13}, + "frame": {"x":623,"y":88,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -482,7 +482,7 @@ }, "sprites/belt/right_4.png": { - "frame": {"x":581,"y":37,"w":13,"h":13}, + "frame": {"x":635,"y":71,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -490,7 +490,7 @@ }, "sprites/belt/right_5.png": { - "frame": {"x":583,"y":20,"w":13,"h":13}, + "frame": {"x":642,"y":54,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -498,7 +498,7 @@ }, "sprites/belt/right_6.png": { - "frame": {"x":586,"y":3,"w":13,"h":13}, + "frame": {"x":623,"y":105,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -506,7 +506,7 @@ }, "sprites/belt/right_7.png": { - "frame": {"x":553,"y":105,"w":13,"h":13}, + "frame": {"x":659,"y":54,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -514,7 +514,7 @@ }, "sprites/belt/right_8.png": { - "frame": {"x":565,"y":88,"w":13,"h":13}, + "frame": {"x":652,"y":71,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -522,7 +522,7 @@ }, "sprites/belt/right_9.png": { - "frame": {"x":579,"y":71,"w":13,"h":13}, + "frame": {"x":669,"y":71,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -530,7 +530,7 @@ }, "sprites/belt/right_10.png": { - "frame": {"x":532,"y":20,"w":13,"h":13}, + "frame": {"x":572,"y":105,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -538,7 +538,7 @@ }, "sprites/belt/right_11.png": { - "frame": {"x":535,"y":3,"w":13,"h":13}, + "frame": {"x":589,"y":88,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -546,7 +546,7 @@ }, "sprites/belt/right_12.png": { - "frame": {"x":502,"y":105,"w":13,"h":13}, + "frame": {"x":601,"y":71,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -554,7 +554,7 @@ }, "sprites/belt/right_13.png": { - "frame": {"x":514,"y":88,"w":13,"h":13}, + "frame": {"x":608,"y":54,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -562,7 +562,7 @@ }, "sprites/belt/right_14.png": { - "frame": {"x":528,"y":71,"w":13,"h":13}, + "frame": {"x":623,"y":37,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -570,7 +570,7 @@ }, "sprites/belt/right_15.png": { - "frame": {"x":535,"y":54,"w":13,"h":13}, + "frame": {"x":624,"y":20,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -578,7 +578,7 @@ }, "sprites/belt/right_16.png": { - "frame": {"x":547,"y":37,"w":13,"h":13}, + "frame": {"x":629,"y":3,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -586,7 +586,7 @@ }, "sprites/belt/right_17.png": { - "frame": {"x":549,"y":20,"w":13,"h":13}, + "frame": {"x":589,"y":105,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -594,7 +594,7 @@ }, "sprites/belt/right_18.png": { - "frame": {"x":552,"y":3,"w":13,"h":13}, + "frame": {"x":606,"y":88,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -602,7 +602,7 @@ }, "sprites/belt/right_19.png": { - "frame": {"x":519,"y":105,"w":13,"h":13}, + "frame": {"x":618,"y":71,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -610,7 +610,7 @@ }, "sprites/belt/right_20.png": { - "frame": {"x":545,"y":71,"w":13,"h":13}, + "frame": {"x":640,"y":37,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -618,7 +618,7 @@ }, "sprites/belt/right_21.png": { - "frame": {"x":552,"y":54,"w":13,"h":13}, + "frame": {"x":641,"y":20,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -626,7 +626,7 @@ }, "sprites/belt/right_22.png": { - "frame": {"x":564,"y":37,"w":13,"h":13}, + "frame": {"x":646,"y":3,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -634,7 +634,7 @@ }, "sprites/belt/right_23.png": { - "frame": {"x":566,"y":20,"w":13,"h":13}, + "frame": {"x":606,"y":105,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -642,7 +642,7 @@ }, "sprites/belt/right_24.png": { - "frame": {"x":569,"y":3,"w":13,"h":13}, + "frame": {"x":663,"y":3,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -650,7 +650,7 @@ }, "sprites/belt/right_25.png": { - "frame": {"x":536,"y":105,"w":13,"h":13}, + "frame": {"x":658,"y":20,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -658,7 +658,7 @@ }, "sprites/belt/right_26.png": { - "frame": {"x":548,"y":88,"w":13,"h":13}, + "frame": {"x":657,"y":37,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -666,15 +666,23 @@ }, "sprites/belt/right_27.png": { - "frame": {"x":562,"y":71,"w":13,"h":13}, + "frame": {"x":674,"y":37,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, "sourceSize": {"w":13,"h":13} }, +"sprites/blueprints/advanced_processor.png": +{ + "frame": {"x":3,"y":83,"w":38,"h":38}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":38,"h":38}, + "sourceSize": {"w":38,"h":38} +}, "sprites/blueprints/belt_left.png": { - "frame": {"x":586,"y":54,"w":13,"h":13}, + "frame": {"x":640,"y":88,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -682,7 +690,7 @@ }, "sprites/blueprints/belt_right.png": { - "frame": {"x":596,"y":71,"w":13,"h":13}, + "frame": {"x":640,"y":105,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -690,7 +698,7 @@ }, "sprites/blueprints/belt_top.png": { - "frame": {"x":570,"y":105,"w":13,"h":13}, + "frame": {"x":657,"y":88,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -698,7 +706,7 @@ }, "sprites/blueprints/cutter-quad.png": { - "frame": {"x":82,"y":3,"w":76,"h":19}, + "frame": {"x":165,"y":81,"w":76,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":76,"h":19}, @@ -706,7 +714,7 @@ }, "sprites/blueprints/cutter.png": { - "frame": {"x":284,"y":3,"w":36,"h":19}, + "frame": {"x":327,"y":43,"w":36,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":36,"h":19}, @@ -714,15 +722,15 @@ }, "sprites/blueprints/energy_generator.png": { - "frame": {"x":126,"y":79,"w":36,"h":38}, + "frame": {"x":166,"y":3,"w":37,"h":37}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":1,"y":0,"w":36,"h":38}, + "spriteSourceSize": {"x":1,"y":1,"w":37,"h":37}, "sourceSize": {"w":38,"h":38} }, "sprites/blueprints/miner-chainable.png": { - "frame": {"x":364,"y":3,"w":19,"h":19}, + "frame": {"x":328,"y":66,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -730,7 +738,7 @@ }, "sprites/blueprints/miner.png": { - "frame": {"x":302,"y":106,"w":19,"h":19}, + "frame": {"x":351,"y":66,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -738,7 +746,7 @@ }, "sprites/blueprints/mixer.png": { - "frame": {"x":247,"y":85,"w":37,"h":19}, + "frame": {"x":286,"y":44,"w":37,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":37,"h":19}, @@ -746,7 +754,7 @@ }, "sprites/blueprints/painter-double.png": { - "frame": {"x":84,"y":82,"w":38,"h":38}, + "frame": {"x":45,"y":83,"w":38,"h":38}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":38,"h":38}, @@ -754,7 +762,7 @@ }, "sprites/blueprints/painter-mirrored.png": { - "frame": {"x":82,"y":49,"w":38,"h":19}, + "frame": {"x":244,"y":44,"w":38,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":38,"h":19}, @@ -762,7 +770,7 @@ }, "sprites/blueprints/painter-quad.png": { - "frame": {"x":3,"y":83,"w":77,"h":19}, + "frame": {"x":82,"y":45,"w":77,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":77,"h":19}, @@ -770,7 +778,7 @@ }, "sprites/blueprints/painter.png": { - "frame": {"x":124,"y":49,"w":38,"h":19}, + "frame": {"x":248,"y":3,"w":38,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":38,"h":19}, @@ -778,7 +786,7 @@ }, "sprites/blueprints/rotater-ccw.png": { - "frame": {"x":325,"y":106,"w":19,"h":19}, + "frame": {"x":367,"y":43,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -786,7 +794,7 @@ }, "sprites/blueprints/rotater.png": { - "frame": {"x":328,"y":83,"w":19,"h":19}, + "frame": {"x":367,"y":89,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -794,7 +802,7 @@ }, "sprites/blueprints/splitter-compact-inverse.png": { - "frame": {"x":348,"y":106,"w":19,"h":19}, + "frame": {"x":374,"y":66,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -802,7 +810,7 @@ }, "sprites/blueprints/splitter-compact.png": { - "frame": {"x":351,"y":83,"w":19,"h":19}, + "frame": {"x":390,"y":43,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -810,7 +818,7 @@ }, "sprites/blueprints/splitter.png": { - "frame": {"x":324,"y":3,"w":36,"h":19}, + "frame": {"x":332,"y":3,"w":36,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":36,"h":19}, @@ -818,7 +826,7 @@ }, "sprites/blueprints/stacker.png": { - "frame": {"x":243,"y":3,"w":37,"h":19}, + "frame": {"x":245,"y":101,"w":37,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":37,"h":19}, @@ -826,7 +834,7 @@ }, "sprites/blueprints/trash-storage.png": { - "frame": {"x":204,"y":3,"w":35,"h":38}, + "frame": {"x":87,"y":82,"w":35,"h":38}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":35,"h":38}, @@ -834,7 +842,7 @@ }, "sprites/blueprints/trash.png": { - "frame": {"x":371,"y":106,"w":19,"h":19}, + "frame": {"x":412,"y":3,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -842,7 +850,7 @@ }, "sprites/blueprints/underground_belt_entry-tier2.png": { - "frame": {"x":417,"y":106,"w":19,"h":18}, + "frame": {"x":458,"y":3,"w":19,"h":18}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":1,"w":19,"h":18}, @@ -850,7 +858,7 @@ }, "sprites/blueprints/underground_belt_entry.png": { - "frame": {"x":256,"y":108,"w":19,"h":16}, + "frame": {"x":443,"y":66,"w":19,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":3,"w":19,"h":16}, @@ -858,7 +866,7 @@ }, "sprites/blueprints/underground_belt_exit-tier2.png": { - "frame": {"x":279,"y":108,"w":19,"h":16}, + "frame": {"x":459,"y":25,"w":19,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":16}, @@ -866,15 +874,63 @@ }, "sprites/blueprints/underground_belt_exit.png": { - "frame": {"x":440,"y":105,"w":19,"h":16}, + "frame": {"x":464,"y":45,"w":19,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":16}, "sourceSize": {"w":19,"h":19} }, +"sprites/blueprints/wire_crossings-merger.png": +{ + "frame": {"x":459,"y":86,"w":19,"h":15}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":19,"h":15}, + "sourceSize": {"w":19,"h":19} +}, +"sprites/blueprints/wire_crossings.png": +{ + "frame": {"x":248,"y":26,"w":19,"h":14}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":5,"w":19,"h":14}, + "sourceSize": {"w":19,"h":19} +}, +"sprites/blueprints/wire_left.png": +{ + "frame": {"x":154,"y":68,"w":10,"h":9}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":4,"w":10,"h":9}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/blueprints/wire_right.png": +{ + "frame": {"x":168,"y":68,"w":9,"h":9}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":4,"y":4,"w":9,"h":9}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/blueprints/wire_top.png": +{ + "frame": {"x":680,"y":3,"w":6,"h":13}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":4,"y":0,"w":6,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/buildings/advanced_processor.png": +{ + "frame": {"x":82,"y":3,"w":38,"h":38}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":38,"h":38}, + "sourceSize": {"w":38,"h":38} +}, "sprites/buildings/belt_left.png": { - "frame": {"x":582,"y":88,"w":13,"h":13}, + "frame": {"x":674,"y":88,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -882,7 +938,7 @@ }, "sprites/buildings/belt_right.png": { - "frame": {"x":587,"y":105,"w":13,"h":13}, + "frame": {"x":657,"y":105,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -890,7 +946,7 @@ }, "sprites/buildings/belt_top.png": { - "frame": {"x":205,"y":110,"w":13,"h":13}, + "frame": {"x":294,"y":26,"w":13,"h":13}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, @@ -898,7 +954,7 @@ }, "sprites/buildings/cutter-quad.png": { - "frame": {"x":82,"y":26,"w":76,"h":19}, + "frame": {"x":165,"y":104,"w":76,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":76,"h":19}, @@ -906,7 +962,7 @@ }, "sprites/buildings/cutter.png": { - "frame": {"x":288,"y":83,"w":36,"h":19}, + "frame": {"x":372,"y":3,"w":36,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":36,"h":19}, @@ -914,10 +970,10 @@ }, "sprites/buildings/energy_generator.png": { - "frame": {"x":166,"y":45,"w":36,"h":38}, + "frame": {"x":207,"y":3,"w":37,"h":37}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":1,"y":0,"w":36,"h":38}, + "spriteSourceSize": {"x":1,"y":1,"w":37,"h":37}, "sourceSize": {"w":38,"h":38} }, "sprites/buildings/hub.png": @@ -930,7 +986,7 @@ }, "sprites/buildings/miner-chainable.png": { - "frame": {"x":374,"y":83,"w":19,"h":19}, + "frame": {"x":390,"y":89,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -938,7 +994,7 @@ }, "sprites/buildings/miner.png": { - "frame": {"x":394,"y":106,"w":19,"h":19}, + "frame": {"x":397,"y":66,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -946,7 +1002,7 @@ }, "sprites/buildings/mixer.png": { - "frame": {"x":248,"y":43,"w":37,"h":19}, + "frame": {"x":286,"y":101,"w":37,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":37,"h":19}, @@ -954,7 +1010,7 @@ }, "sprites/buildings/painter-double.png": { - "frame": {"x":162,"y":3,"w":38,"h":38}, + "frame": {"x":124,"y":3,"w":38,"h":38}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":38,"h":38}, @@ -962,7 +1018,7 @@ }, "sprites/buildings/painter-mirrored.png": { - "frame": {"x":205,"y":87,"w":38,"h":19}, + "frame": {"x":290,"y":3,"w":38,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":38,"h":19}, @@ -970,7 +1026,7 @@ }, "sprites/buildings/painter-quad.png": { - "frame": {"x":3,"y":106,"w":77,"h":19}, + "frame": {"x":163,"y":45,"w":77,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":77,"h":19}, @@ -978,7 +1034,7 @@ }, "sprites/buildings/painter.png": { - "frame": {"x":206,"y":45,"w":38,"h":19}, + "frame": {"x":245,"y":78,"w":38,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":38,"h":19}, @@ -986,7 +1042,7 @@ }, "sprites/buildings/rotater-ccw.png": { - "frame": {"x":370,"y":43,"w":19,"h":19}, + "frame": {"x":413,"y":89,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -994,7 +1050,7 @@ }, "sprites/buildings/rotater.png": { - "frame": {"x":387,"y":3,"w":19,"h":19}, + "frame": {"x":413,"y":26,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -1002,7 +1058,7 @@ }, "sprites/buildings/splitter-compact-inverse.png": { - "frame": {"x":393,"y":43,"w":19,"h":19}, + "frame": {"x":435,"y":3,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -1010,7 +1066,7 @@ }, "sprites/buildings/splitter-compact.png": { - "frame": {"x":410,"y":3,"w":19,"h":19}, + "frame": {"x":420,"y":66,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -1018,7 +1074,7 @@ }, "sprites/buildings/splitter.png": { - "frame": {"x":330,"y":43,"w":36,"h":19}, + "frame": {"x":327,"y":90,"w":36,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":36,"h":19}, @@ -1026,7 +1082,7 @@ }, "sprites/buildings/stacker.png": { - "frame": {"x":289,"y":43,"w":37,"h":19}, + "frame": {"x":287,"y":67,"w":37,"h":19}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":37,"h":19}, @@ -1034,7 +1090,7 @@ }, "sprites/buildings/trash-storage.png": { - "frame": {"x":166,"y":87,"w":35,"h":38}, + "frame": {"x":126,"y":81,"w":35,"h":38}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":35,"h":38}, @@ -1042,7 +1098,7 @@ }, "sprites/buildings/trash.png": { - "frame": {"x":397,"y":83,"w":19,"h":19}, + "frame": {"x":436,"y":26,"w":19,"h":19}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":19}, @@ -1050,7 +1106,7 @@ }, "sprites/buildings/underground_belt_entry-tier2.png": { - "frame": {"x":420,"y":83,"w":19,"h":18}, + "frame": {"x":436,"y":89,"w":19,"h":18}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":1,"w":19,"h":18}, @@ -1058,7 +1114,7 @@ }, "sprites/buildings/underground_belt_entry.png": { - "frame": {"x":416,"y":43,"w":19,"h":16}, + "frame": {"x":481,"y":3,"w":19,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":3,"w":19,"h":16}, @@ -1066,7 +1122,7 @@ }, "sprites/buildings/underground_belt_exit-tier2.png": { - "frame": {"x":427,"y":63,"w":19,"h":16}, + "frame": {"x":482,"y":23,"w":19,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":16}, @@ -1074,15 +1130,55 @@ }, "sprites/buildings/underground_belt_exit.png": { - "frame": {"x":439,"y":43,"w":19,"h":16}, + "frame": {"x":504,"y":3,"w":19,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":19,"h":16}, "sourceSize": {"w":19,"h":19} }, +"sprites/buildings/wire_crossings-merger.png": +{ + "frame": {"x":466,"y":65,"w":19,"h":15}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":19,"h":15}, + "sourceSize": {"w":19,"h":19} +}, +"sprites/buildings/wire_crossings.png": +{ + "frame": {"x":271,"y":26,"w":19,"h":14}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":5,"w":19,"h":14}, + "sourceSize": {"w":19,"h":19} +}, +"sprites/buildings/wire_left.png": +{ + "frame": {"x":181,"y":68,"w":9,"h":9}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":4,"w":9,"h":9}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/buildings/wire_right.png": +{ + "frame": {"x":194,"y":68,"w":9,"h":9}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":4,"y":4,"w":9,"h":9}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/buildings/wire_top.png": +{ + "frame": {"x":675,"y":20,"w":5,"h":13}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":4,"y":0,"w":5,"h":13}, + "sourceSize": {"w":13,"h":13} +}, "sprites/debug/acceptor_slot.png": { - "frame": {"x":82,"y":72,"w":6,"h":6}, + "frame": {"x":207,"y":68,"w":6,"h":6}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":6,"h":6}, @@ -1090,7 +1186,7 @@ }, "sprites/debug/ejector_slot.png": { - "frame": {"x":92,"y":72,"w":6,"h":6}, + "frame": {"x":217,"y":68,"w":6,"h":6}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":6,"h":6}, @@ -1098,7 +1194,7 @@ }, "sprites/map_overview/belt_forward.png": { - "frame": {"x":111,"y":72,"w":3,"h":3}, + "frame": {"x":306,"y":90,"w":3,"h":3}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":3,"h":3}, @@ -1106,7 +1202,7 @@ }, "sprites/map_overview/belt_left.png": { - "frame": {"x":118,"y":72,"w":3,"h":3}, + "frame": {"x":313,"y":90,"w":3,"h":3}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":3,"h":3}, @@ -1114,7 +1210,7 @@ }, "sprites/map_overview/belt_right.png": { - "frame": {"x":125,"y":72,"w":3,"h":3}, + "frame": {"x":320,"y":90,"w":3,"h":3}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":3,"h":3}, @@ -1122,15 +1218,23 @@ }, "sprites/misc/deletion_marker.png": { - "frame": {"x":598,"y":37,"w":10,"h":10}, + "frame": {"x":82,"y":68,"w":10,"h":10}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":10,"h":10}, "sourceSize": {"w":10,"h":10} }, +"sprites/misc/energy_generator_overlay.png": +{ + "frame": {"x":110,"y":68,"w":18,"h":9}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":17,"y":27,"w":18,"h":9}, + "sourceSize": {"w":38,"h":38} +}, "sprites/misc/hub_direction_indicator.png": { - "frame": {"x":132,"y":72,"w":3,"h":3}, + "frame": {"x":327,"y":113,"w":3,"h":3}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":3,"h":3}, @@ -1138,7 +1242,7 @@ }, "sprites/misc/lock_direction_indicator.png": { - "frame": {"x":102,"y":72,"w":5,"h":5}, + "frame": {"x":297,"y":90,"w":5,"h":5}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":5,"h":5}, @@ -1146,7 +1250,7 @@ }, "sprites/misc/slot_bad_arrow.png": { - "frame": {"x":598,"y":37,"w":10,"h":10}, + "frame": {"x":82,"y":68,"w":10,"h":10}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":10,"h":10}, @@ -1154,7 +1258,7 @@ }, "sprites/misc/slot_good_arrow.png": { - "frame": {"x":599,"y":88,"w":10,"h":10}, + "frame": {"x":96,"y":68,"w":10,"h":10}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":10,"h":10}, @@ -1162,7 +1266,7 @@ }, "sprites/misc/storage_overlay.png": { - "frame": {"x":463,"y":114,"w":18,"h":9}, + "frame": {"x":132,"y":68,"w":18,"h":9}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":18,"h":9}, @@ -1170,19 +1274,115 @@ }, "sprites/misc/waypoint.png": { - "frame": {"x":139,"y":72,"w":3,"h":3}, + "frame": {"x":327,"y":120,"w":3,"h":3}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":3,"h":3}, "sourceSize": {"w":3,"h":3} +}, +"sprites/misc/wires_overlay_tile.png": +{ + "frame": {"x":674,"y":105,"w":13,"h":13}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":13,"h":13}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/wires/battery_empty.png": +{ + "frame": {"x":227,"y":68,"w":6,"h":6}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":6,"h":6}, + "sourceSize": {"w":6,"h":6} +}, +"sprites/wires/battery_full.png": +{ + "frame": {"x":237,"y":68,"w":6,"h":6}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":6,"h":6}, + "sourceSize": {"w":6,"h":6} +}, +"sprites/wires/battery_low.png": +{ + "frame": {"x":247,"y":67,"w":6,"h":6}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":6,"h":6}, + "sourceSize": {"w":6,"h":6} +}, +"sprites/wires/battery_medium.png": +{ + "frame": {"x":257,"y":67,"w":6,"h":6}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":6,"h":6}, + "sourceSize": {"w":6,"h":6} +}, +"sprites/wires/negative_energy.png": +{ + "frame": {"x":267,"y":67,"w":6,"h":6}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":6,"h":6}, + "sourceSize": {"w":6,"h":6} +}, +"sprites/wires/pin_negative_accept.png": +{ + "frame": {"x":367,"y":112,"w":11,"h":12}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":0,"w":11,"h":12}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/wires/pin_negative_eject.png": +{ + "frame": {"x":397,"y":112,"w":9,"h":12}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":0,"w":9,"h":12}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/wires/pin_positive_accept.png": +{ + "frame": {"x":410,"y":112,"w":9,"h":12}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":0,"w":9,"h":12}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/wires/pin_positive_eject.png": +{ + "frame": {"x":382,"y":112,"w":11,"h":12}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":0,"w":11,"h":12}, + "sourceSize": {"w":13,"h":13} +}, +"sprites/wires/positive_energy.png": +{ + "frame": {"x":277,"y":67,"w":6,"h":6}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":6,"h":6}, + "sourceSize": {"w":6,"h":6} +}, +"sprites/wires/waste_piled.png": +{ + "frame": {"x":287,"y":90,"w":6,"h":6}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":6,"h":6}, + "sourceSize": {"w":6,"h":6} }}, "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "1.0", "image": "atlas0_10.png", "format": "RGBA8888", - "size": {"w":612,"h":128}, + "size": {"w":690,"h":127}, "scale": "0.1", - "smartupdate": "$TexturePacker:SmartUpdate:dc34796c028235bbc69e5b8d854254ca:2765d0b8c8bcbb7a4aaaf1104853ad41:8778749683c68f53155587e6d831729a$" + "smartupdate": "$TexturePacker:SmartUpdate:4e5fb3bd7f1e5423e4fcea2215debe11:0c5d091d0b928944c68553dcc592c801:f159918d23e5952766c6d23ab52278c6$" } } diff --git a/res_built/atlas/atlas0_10.png b/res_built/atlas/atlas0_10.png index d774ecac..b75b013b 100644 Binary files a/res_built/atlas/atlas0_10.png and b/res_built/atlas/atlas0_10.png differ diff --git a/res_built/atlas/atlas0_100.json b/res_built/atlas/atlas0_100.json index 05465e84..974d23ec 100644 --- a/res_built/atlas/atlas0_100.json +++ b/res_built/atlas/atlas0_100.json @@ -2,7 +2,7 @@ "sprites/belt/forward_0.png": { - "frame": {"x":1202,"y":1870,"w":100,"h":126}, + "frame": {"x":1115,"y":1688,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -10,7 +10,7 @@ }, "sprites/belt/forward_1.png": { - "frame": {"x":1871,"y":250,"w":100,"h":126}, + "frame": {"x":1115,"y":1818,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -18,7 +18,63 @@ }, "sprites/belt/forward_2.png": { - "frame": {"x":1631,"y":1865,"w":100,"h":126}, + "frame": {"x":1353,"y":2194,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_3.png": +{ + "frame": {"x":1470,"y":2445,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_4.png": +{ + "frame": {"x":1871,"y":199,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_5.png": +{ + "frame": {"x":1263,"y":1163,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_6.png": +{ + "frame": {"x":1484,"y":1222,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_7.png": +{ + "frame": {"x":1372,"y":1347,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_8.png": +{ + "frame": {"x":1476,"y":1352,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_9.png": +{ + "frame": {"x":1531,"y":1748,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -26,7 +82,7 @@ }, "sprites/belt/forward_10.png": { - "frame": {"x":1450,"y":1487,"w":100,"h":126}, + "frame": {"x":1100,"y":2065,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -34,7 +90,7 @@ }, "sprites/belt/forward_11.png": { - "frame": {"x":1423,"y":1849,"w":100,"h":126}, + "frame": {"x":1219,"y":1687,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -42,7 +98,7 @@ }, "sprites/belt/forward_12.png": { - "frame": {"x":1455,"y":1617,"w":100,"h":126}, + "frame": {"x":1219,"y":1817,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -50,7 +106,7 @@ }, "sprites/belt/forward_13.png": { - "frame": {"x":1793,"y":1624,"w":100,"h":126}, + "frame": {"x":1225,"y":1947,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -58,7 +114,7 @@ }, "sprites/belt/forward_14.png": { - "frame": {"x":1897,"y":1624,"w":100,"h":126}, + "frame": {"x":1132,"y":2277,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -66,7 +122,7 @@ }, "sprites/belt/forward_15.png": { - "frame": {"x":1559,"y":1735,"w":100,"h":126}, + "frame": {"x":1132,"y":2407,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -74,7 +130,7 @@ }, "sprites/belt/forward_16.png": { - "frame": {"x":1663,"y":1735,"w":100,"h":126}, + "frame": {"x":1123,"y":2537,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -82,7 +138,7 @@ }, "sprites/belt/forward_17.png": { - "frame": {"x":1767,"y":1754,"w":100,"h":126}, + "frame": {"x":1323,"y":1687,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -90,7 +146,7 @@ }, "sprites/belt/forward_18.png": { - "frame": {"x":1871,"y":1754,"w":100,"h":126}, + "frame": {"x":1323,"y":1817,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -98,7 +154,7 @@ }, "sprites/belt/forward_19.png": { - "frame": {"x":1527,"y":1865,"w":100,"h":126}, + "frame": {"x":1329,"y":1947,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -106,7 +162,7 @@ }, "sprites/belt/forward_20.png": { - "frame": {"x":1735,"y":1884,"w":100,"h":126}, + "frame": {"x":1353,"y":2324,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -114,7 +170,55 @@ }, "sprites/belt/forward_21.png": { - "frame": {"x":1839,"y":1884,"w":100,"h":126}, + "frame": {"x":1260,"y":1301,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_22.png": +{ + "frame": {"x":1268,"y":1431,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_23.png": +{ + "frame": {"x":1427,"y":1678,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_24.png": +{ + "frame": {"x":1427,"y":1808,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_25.png": +{ + "frame": {"x":1433,"y":1938,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_26.png": +{ + "frame": {"x":1457,"y":2185,"w":100,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/forward_27.png": +{ + "frame": {"x":1457,"y":2315,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -122,7 +226,7 @@ }, "sprites/belt/left_0.png": { - "frame": {"x":239,"y":1898,"w":113,"h":113}, + "frame": {"x":1108,"y":1948,"w":113,"h":113}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, @@ -130,7 +234,71 @@ }, "sprites/belt/left_1.png": { - "frame": {"x":1085,"y":1870,"w":113,"h":113}, + "frame": {"x":1217,"y":1570,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_2.png": +{ + "frame": {"x":1461,"y":2575,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_3.png": +{ + "frame": {"x":1580,"y":1397,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_4.png": +{ + "frame": {"x":1697,"y":1409,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_5.png": +{ + "frame": {"x":1814,"y":1409,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_6.png": +{ + "frame": {"x":1451,"y":1482,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_7.png": +{ + "frame": {"x":1568,"y":1514,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_8.png": +{ + "frame": {"x":1685,"y":1526,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_9.png": +{ + "frame": {"x":1802,"y":1526,"w":113,"h":113}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, @@ -138,7 +306,7 @@ }, "sprites/belt/left_10.png": { - "frame": {"x":1306,"y":1849,"w":113,"h":113}, + "frame": {"x":1204,"y":2077,"w":113,"h":113}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, @@ -146,7 +314,7 @@ }, "sprites/belt/left_11.png": { - "frame": {"x":1873,"y":133,"w":113,"h":113}, + "frame": {"x":1321,"y":2077,"w":113,"h":113}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, @@ -154,7 +322,7 @@ }, "sprites/belt/left_12.png": { - "frame": {"x":1582,"y":1501,"w":113,"h":113}, + "frame": {"x":1236,"y":2194,"w":113,"h":113}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, @@ -162,7 +330,7 @@ }, "sprites/belt/left_13.png": { - "frame": {"x":1699,"y":1501,"w":113,"h":113}, + "frame": {"x":1236,"y":2311,"w":113,"h":113}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, @@ -170,7 +338,7 @@ }, "sprites/belt/left_14.png": { - "frame": {"x":1816,"y":1507,"w":113,"h":113}, + "frame": {"x":1236,"y":2428,"w":113,"h":113}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, @@ -178,7 +346,7 @@ }, "sprites/belt/left_15.png": { - "frame": {"x":1559,"y":1618,"w":113,"h":113}, + "frame": {"x":1227,"y":2545,"w":113,"h":113}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, @@ -186,15 +354,335 @@ }, "sprites/belt/left_16.png": { - "frame": {"x":1676,"y":1618,"w":113,"h":113}, + "frame": {"x":1353,"y":2454,"w":113,"h":113}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, "sourceSize": {"w":126,"h":126} }, +"sprites/belt/left_17.png": +{ + "frame": {"x":1344,"y":2571,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_18.png": +{ + "frame": {"x":1334,"y":1561,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_19.png": +{ + "frame": {"x":1438,"y":2068,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_20.png": +{ + "frame": {"x":1367,"y":1113,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_21.png": +{ + "frame": {"x":1367,"y":1230,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_22.png": +{ + "frame": {"x":1588,"y":1163,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_23.png": +{ + "frame": {"x":1588,"y":1280,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_24.png": +{ + "frame": {"x":1705,"y":1175,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_25.png": +{ + "frame": {"x":1822,"y":1175,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_26.png": +{ + "frame": {"x":1705,"y":1292,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/left_27.png": +{ + "frame": {"x":1822,"y":1292,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_0.png": +{ + "frame": {"x":1531,"y":1631,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_1.png": +{ + "frame": {"x":1648,"y":1643,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_2.png": +{ + "frame": {"x":1555,"y":1995,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_3.png": +{ + "frame": {"x":1795,"y":2228,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_4.png": +{ + "frame": {"x":1912,"y":2111,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_5.png": +{ + "frame": {"x":1912,"y":2228,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_6.png": +{ + "frame": {"x":1574,"y":2346,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_7.png": +{ + "frame": {"x":1691,"y":2345,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_8.png": +{ + "frame": {"x":1808,"y":2345,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_9.png": +{ + "frame": {"x":1925,"y":2345,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_10.png": +{ + "frame": {"x":1765,"y":1643,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_11.png": +{ + "frame": {"x":1635,"y":1760,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_12.png": +{ + "frame": {"x":1752,"y":1760,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_13.png": +{ + "frame": {"x":1537,"y":1878,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_14.png": +{ + "frame": {"x":1654,"y":1877,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_15.png": +{ + "frame": {"x":1771,"y":1877,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_16.png": +{ + "frame": {"x":1882,"y":1643,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_17.png": +{ + "frame": {"x":1869,"y":1760,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_18.png": +{ + "frame": {"x":1888,"y":1877,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_19.png": +{ + "frame": {"x":1919,"y":1526,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_20.png": +{ + "frame": {"x":1672,"y":1994,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_21.png": +{ + "frame": {"x":1789,"y":1994,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_22.png": +{ + "frame": {"x":1906,"y":1994,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_23.png": +{ + "frame": {"x":1561,"y":2112,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_24.png": +{ + "frame": {"x":1561,"y":2229,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_25.png": +{ + "frame": {"x":1678,"y":2111,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_26.png": +{ + "frame": {"x":1678,"y":2228,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/belt/right_27.png": +{ + "frame": {"x":1795,"y":2111,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/blueprints/advanced_processor.png": +{ + "frame": {"x":3,"y":1702,"w":374,"h":358}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":10,"y":12,"w":374,"h":358}, + "sourceSize": {"w":384,"h":384} +}, "sprites/blueprints/belt_left.png": { - "frame": {"x":3,"y":1898,"w":114,"h":114}, + "frame": {"x":1150,"y":1452,"w":114,"h":114}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":12,"w":114,"h":114}, @@ -202,7 +690,7 @@ }, "sprites/blueprints/belt_right.png": { - "frame": {"x":121,"y":1898,"w":114,"h":114}, + "frame": {"x":1099,"y":1570,"w":114,"h":114}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":12,"y":12,"w":114,"h":114}, @@ -210,7 +698,7 @@ }, "sprites/blueprints/belt_top.png": { - "frame": {"x":1873,"y":3,"w":102,"h":126}, + "frame": {"x":1260,"y":957,"w":102,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":12,"y":0,"w":102,"h":126}, @@ -226,7 +714,7 @@ }, "sprites/blueprints/cutter.png": { - "frame": {"x":391,"y":1707,"w":341,"h":191}, + "frame": {"x":381,"y":1707,"w":341,"h":191}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":23,"y":0,"w":341,"h":191}, @@ -234,15 +722,15 @@ }, "sprites/blueprints/energy_generator.png": { - "frame": {"x":735,"y":590,"w":339,"h":373}, + "frame": {"x":735,"y":590,"w":348,"h":364}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":25,"y":11,"w":339,"h":373}, + "spriteSourceSize": {"x":20,"y":20,"w":348,"h":364}, "sourceSize": {"w":384,"h":384} }, "sprites/blueprints/miner-chainable.png": { - "frame": {"x":1842,"y":783,"w":182,"h":190}, + "frame": {"x":763,"y":2290,"w":182,"h":190}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":182,"h":190}, @@ -250,7 +738,7 @@ }, "sprites/blueprints/miner.png": { - "frame": {"x":1843,"y":977,"w":182,"h":190}, + "frame": {"x":914,"y":2096,"w":182,"h":190}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":182,"h":190}, @@ -258,7 +746,7 @@ }, "sprites/blueprints/mixer.png": { - "frame": {"x":726,"y":1162,"w":347,"h":191}, + "frame": {"x":3,"y":2424,"w":347,"h":191}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":18,"y":0,"w":347,"h":191}, @@ -274,7 +762,7 @@ }, "sprites/blueprints/painter-mirrored.png": { - "frame": {"x":3,"y":1702,"w":384,"h":192}, + "frame": {"x":1485,"y":3,"w":384,"h":192}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":384,"h":192}, @@ -290,7 +778,7 @@ }, "sprites/blueprints/painter.png": { - "frame": {"x":1485,"y":3,"w":384,"h":192}, + "frame": {"x":1483,"y":199,"w":384,"h":192}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":384,"h":192}, @@ -298,7 +786,7 @@ }, "sprites/blueprints/rotater-ccw.png": { - "frame": {"x":1458,"y":956,"w":189,"h":191}, + "frame": {"x":922,"y":1694,"w":189,"h":191}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":189,"h":191}, @@ -306,7 +794,7 @@ }, "sprites/blueprints/rotater.png": { - "frame": {"x":1811,"y":588,"w":189,"h":191}, + "frame": {"x":550,"y":2460,"w":189,"h":191}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":189,"h":191}, @@ -314,7 +802,7 @@ }, "sprites/blueprints/splitter-compact-inverse.png": { - "frame": {"x":1651,"y":977,"w":188,"h":182}, + "frame": {"x":743,"y":2484,"w":188,"h":182}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":4,"w":188,"h":182}, @@ -322,7 +810,7 @@ }, "sprites/blueprints/splitter-compact.png": { - "frame": {"x":1649,"y":1163,"w":185,"h":182}, + "frame": {"x":1753,"y":989,"w":185,"h":182}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":7,"y":4,"w":185,"h":182}, @@ -330,7 +818,7 @@ }, "sprites/blueprints/splitter.png": { - "frame": {"x":1114,"y":966,"w":340,"h":191}, + "frame": {"x":724,"y":1347,"w":340,"h":191}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":23,"y":0,"w":340,"h":191}, @@ -338,7 +826,7 @@ }, "sprites/blueprints/stacker.png": { - "frame": {"x":724,"y":1357,"w":347,"h":191}, + "frame": {"x":726,"y":958,"w":347,"h":191}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":18,"y":0,"w":347,"h":191}, @@ -354,7 +842,7 @@ }, "sprites/blueprints/trash.png": { - "frame": {"x":1419,"y":590,"w":192,"h":192}, + "frame": {"x":726,"y":1694,"w":192,"h":192}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":192,"h":192}, @@ -362,7 +850,7 @@ }, "sprites/blueprints/underground_belt_entry-tier2.png": { - "frame": {"x":1419,"y":786,"w":183,"h":166}, + "frame": {"x":576,"y":2290,"w":183,"h":166}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":26,"w":183,"h":166}, @@ -370,7 +858,7 @@ }, "sprites/blueprints/underground_belt_entry.png": { - "frame": {"x":1646,"y":1349,"w":182,"h":148}, + "frame": {"x":913,"y":1542,"w":182,"h":148}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":44,"w":182,"h":148}, @@ -378,7 +866,7 @@ }, "sprites/blueprints/underground_belt_exit-tier2.png": { - "frame": {"x":1457,"y":1335,"w":185,"h":148}, + "frame": {"x":724,"y":1542,"w":185,"h":148}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":185,"h":148}, @@ -386,15 +874,79 @@ }, "sprites/blueprints/underground_belt_exit.png": { - "frame": {"x":1832,"y":1355,"w":182,"h":148}, + "frame": {"x":922,"y":1889,"w":182,"h":148}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":182,"h":148}, "sourceSize": {"w":192,"h":192} }, +"sprites/blueprints/wire_crossings-merger.png": +{ + "frame": {"x":380,"y":2290,"w":192,"h":136}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":192,"h":136}, + "sourceSize": {"w":192,"h":192} +}, +"sprites/blueprints/wire_crossings.png": +{ + "frame": {"x":1786,"y":854,"w":192,"h":131}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":61,"w":192,"h":131}, + "sourceSize": {"w":192,"h":192} +}, +"sprites/blueprints/wire_left.png": +{ + "frame": {"x":436,"y":2625,"w":79,"h":79}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":47,"w":79,"h":79}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/blueprints/wire_right.png": +{ + "frame": {"x":353,"y":2625,"w":79,"h":80}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":47,"y":46,"w":79,"h":80}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/blueprints/wire_top.png": +{ + "frame": {"x":1982,"y":854,"w":32,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":47,"y":0,"w":32,"h":126}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/buildings/advanced_processor.png": +{ + "frame": {"x":3,"y":2064,"w":373,"h":356}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":11,"y":13,"w":373,"h":356}, + "sourceSize": {"w":384,"h":384} +}, +"sprites/buildings/belt_left.png": +{ + "frame": {"x":1578,"y":2572,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/buildings/belt_right.png": +{ + "frame": {"x":1718,"y":2462,"w":113,"h":113}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, + "sourceSize": {"w":126,"h":126} +}, "sprites/buildings/belt_top.png": { - "frame": {"x":1202,"y":1870,"w":100,"h":126}, + "frame": {"x":1115,"y":1688,"w":100,"h":126}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, @@ -410,7 +962,7 @@ }, "sprites/buildings/cutter.png": { - "frame": {"x":736,"y":1552,"w":339,"h":190}, + "frame": {"x":381,"y":1902,"w":339,"h":190}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":24,"y":0,"w":339,"h":190}, @@ -418,10 +970,10 @@ }, "sprites/buildings/energy_generator.png": { - "frame": {"x":1078,"y":590,"w":337,"h":372}, + "frame": {"x":1087,"y":590,"w":346,"h":363}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":26,"y":12,"w":337,"h":372}, + "spriteSourceSize": {"x":21,"y":21,"w":346,"h":363}, "sourceSize": {"w":384,"h":384} }, "sprites/buildings/hub.png": @@ -434,7 +986,7 @@ }, "sprites/buildings/miner-chainable.png": { - "frame": {"x":1258,"y":1355,"w":179,"h":188}, + "frame": {"x":1077,"y":958,"w":179,"h":188}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":8,"y":1,"w":179,"h":188}, @@ -442,7 +994,7 @@ }, "sprites/buildings/miner.png": { - "frame": {"x":1075,"y":1357,"w":179,"h":189}, + "frame": {"x":949,"y":2290,"w":179,"h":189}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":8,"y":0,"w":179,"h":189}, @@ -450,7 +1002,7 @@ }, "sprites/buildings/mixer.png": { - "frame": {"x":736,"y":1746,"w":345,"h":190}, + "frame": {"x":1437,"y":785,"w":345,"h":190}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":19,"y":0,"w":345,"h":190}, @@ -466,7 +1018,7 @@ }, "sprites/buildings/painter-mirrored.png": { - "frame": {"x":1483,"y":199,"w":384,"h":191}, + "frame": {"x":1469,"y":395,"w":384,"h":191}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":384,"h":191}, @@ -482,7 +1034,7 @@ }, "sprites/buildings/painter.png": { - "frame": {"x":726,"y":967,"w":384,"h":191}, + "frame": {"x":1437,"y":590,"w":384,"h":191}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":384,"h":191}, @@ -490,7 +1042,7 @@ }, "sprites/buildings/rotater-ccw.png": { - "frame": {"x":1832,"y":394,"w":187,"h":190}, + "frame": {"x":723,"y":2096,"w":187,"h":190}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":187,"h":190}, @@ -498,7 +1050,7 @@ }, "sprites/buildings/rotater.png": { - "frame": {"x":1651,"y":783,"w":187,"h":190}, + "frame": {"x":724,"y":1902,"w":187,"h":190}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":187,"h":190}, @@ -506,7 +1058,7 @@ }, "sprites/buildings/splitter-compact-inverse.png": { - "frame": {"x":1458,"y":1151,"w":187,"h":180}, + "frame": {"x":1562,"y":979,"w":187,"h":180}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":5,"w":187,"h":180}, @@ -514,7 +1066,7 @@ }, "sprites/buildings/splitter-compact.png": { - "frame": {"x":1838,"y":1171,"w":184,"h":180}, + "frame": {"x":935,"y":2484,"w":184,"h":180}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":8,"y":5,"w":184,"h":180}, @@ -522,7 +1074,7 @@ }, "sprites/buildings/splitter.png": { - "frame": {"x":1114,"y":1161,"w":339,"h":190}, + "frame": {"x":380,"y":2096,"w":339,"h":190}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":24,"y":0,"w":339,"h":190}, @@ -530,7 +1082,7 @@ }, "sprites/buildings/stacker.png": { - "frame": {"x":1483,"y":394,"w":345,"h":190}, + "frame": {"x":726,"y":1153,"w":345,"h":190}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":19,"y":0,"w":345,"h":190}, @@ -546,7 +1098,7 @@ }, "sprites/buildings/trash.png": { - "frame": {"x":1615,"y":588,"w":192,"h":191}, + "frame": {"x":354,"y":2430,"w":192,"h":191}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":1,"w":192,"h":191}, @@ -554,7 +1106,7 @@ }, "sprites/buildings/underground_belt_entry-tier2.png": { - "frame": {"x":1079,"y":1550,"w":181,"h":165}, + "frame": {"x":1857,"y":395,"w":181,"h":165}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":7,"y":27,"w":181,"h":165}, @@ -562,7 +1114,7 @@ }, "sprites/buildings/underground_belt_entry.png": { - "frame": {"x":1085,"y":1719,"w":181,"h":147}, + "frame": {"x":1857,"y":564,"w":181,"h":147}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":7,"y":45,"w":181,"h":147}, @@ -570,7 +1122,7 @@ }, "sprites/buildings/underground_belt_exit-tier2.png": { - "frame": {"x":1264,"y":1547,"w":182,"h":147}, + "frame": {"x":1077,"y":1150,"w":182,"h":147}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":7,"y":0,"w":182,"h":147}, @@ -578,15 +1130,55 @@ }, "sprites/buildings/underground_belt_exit.png": { - "frame": {"x":1270,"y":1698,"w":181,"h":147}, + "frame": {"x":1075,"y":1301,"w":181,"h":147}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":7,"y":0,"w":181,"h":147}, "sourceSize": {"w":192,"h":192} }, +"sprites/buildings/wire_crossings-merger.png": +{ + "frame": {"x":1825,"y":715,"w":192,"h":135}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":192,"h":135}, + "sourceSize": {"w":192,"h":192} +}, +"sprites/buildings/wire_crossings.png": +{ + "frame": {"x":1366,"y":979,"w":192,"h":130}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":62,"w":192,"h":130}, + "sourceSize": {"w":192,"h":192} +}, +"sprites/buildings/wire_left.png": +{ + "frame": {"x":1068,"y":1452,"w":78,"h":78}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":48,"w":78,"h":78}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/buildings/wire_right.png": +{ + "frame": {"x":1100,"y":2195,"w":78,"h":78}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":48,"y":48,"w":78,"h":78}, + "sourceSize": {"w":126,"h":126} +}, +"sprites/buildings/wire_top.png": +{ + "frame": {"x":1942,"y":989,"w":30,"h":126}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":48,"y":0,"w":30,"h":126}, + "sourceSize": {"w":126,"h":126} +}, "sprites/debug/acceptor_slot.png": { - "frame": {"x":1975,"y":250,"w":50,"h":64}, + "frame": {"x":1182,"y":2195,"w":50,"h":64}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":7,"y":0,"w":50,"h":64}, @@ -594,7 +1186,7 @@ }, "sprites/debug/ejector_slot.png": { - "frame": {"x":1975,"y":318,"w":50,"h":64}, + "frame": {"x":1372,"y":1477,"w":50,"h":64}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":7,"y":0,"w":50,"h":64}, @@ -602,7 +1194,7 @@ }, "sprites/map_overview/belt_forward.png": { - "frame": {"x":706,"y":1902,"w":24,"h":32}, + "frame": {"x":1503,"y":1641,"w":24,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":4,"y":0,"w":24,"h":32}, @@ -610,7 +1202,7 @@ }, "sprites/map_overview/belt_left.png": { - "frame": {"x":1077,"y":1162,"w":28,"h":28}, + "frame": {"x":1825,"y":590,"w":28,"h":28}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":4,"w":28,"h":28}, @@ -618,7 +1210,7 @@ }, "sprites/map_overview/belt_right.png": { - "frame": {"x":1979,"y":3,"w":28,"h":28}, + "frame": {"x":1825,"y":622,"w":28,"h":28}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":4,"y":4,"w":28,"h":28}, @@ -626,15 +1218,23 @@ }, "sprites/misc/deletion_marker.png": { - "frame": {"x":620,"y":1902,"w":82,"h":82}, + "frame": {"x":267,"y":2619,"w":82,"h":82}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":7,"y":7,"w":82,"h":82}, "sourceSize": {"w":96,"h":96} }, +"sprites/misc/energy_generator_overlay.png": +{ + "frame": {"x":1873,"y":135,"w":153,"h":57}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":183,"y":290,"w":153,"h":57}, + "sourceSize": {"w":384,"h":384} +}, "sprites/misc/hub_direction_indicator.png": { - "frame": {"x":1615,"y":783,"w":32,"h":32}, + "frame": {"x":1099,"y":1534,"w":32,"h":32}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32}, @@ -642,7 +1242,7 @@ }, "sprites/misc/lock_direction_indicator.png": { - "frame": {"x":1306,"y":1966,"w":48,"h":30}, + "frame": {"x":1451,"y":1641,"w":48,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":48,"h":30}, @@ -650,7 +1250,7 @@ }, "sprites/misc/slot_bad_arrow.png": { - "frame": {"x":620,"y":1902,"w":82,"h":82}, + "frame": {"x":267,"y":2619,"w":82,"h":82}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":7,"y":7,"w":82,"h":82}, @@ -658,7 +1258,7 @@ }, "sprites/misc/slot_good_arrow.png": { - "frame": {"x":536,"y":1902,"w":80,"h":96}, + "frame": {"x":183,"y":2619,"w":80,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":8,"y":0,"w":80,"h":96}, @@ -666,7 +1266,7 @@ }, "sprites/misc/storage_overlay.png": { - "frame": {"x":356,"y":1902,"w":176,"h":86}, + "frame": {"x":3,"y":2619,"w":176,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":4,"w":176,"h":86}, @@ -674,20 +1274,115 @@ }, "sprites/misc/waypoint.png": { - "frame": {"x":1554,"y":1487,"w":24,"h":32}, + "frame": {"x":1786,"y":785,"w":24,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":4,"y":0,"w":24,"h":32}, "sourceSize": {"w":32,"h":32} +}, +"sprites/misc/wires_overlay_tile.png": +{ + "frame": {"x":1873,"y":3,"w":128,"h":128}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":128,"h":128}, + "sourceSize": {"w":128,"h":128} +}, +"sprites/wires/battery_empty.png": +{ + "frame": {"x":519,"y":2655,"w":38,"h":60}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":2,"w":38,"h":60}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/battery_full.png": +{ + "frame": {"x":1871,"y":329,"w":58,"h":38}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":3,"y":14,"w":58,"h":38}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/battery_low.png": +{ + "frame": {"x":1451,"y":1599,"w":58,"h":38}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":3,"y":14,"w":58,"h":38}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/battery_medium.png": +{ + "frame": {"x":1835,"y":2462,"w":58,"h":38}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":3,"y":14,"w":58,"h":38}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/negative_energy.png": +{ + "frame": {"x":561,"y":2655,"w":42,"h":42}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":11,"y":11,"w":42,"h":42}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/pin_negative_accept.png": +{ + "frame": {"x":1484,"y":1113,"w":73,"h":105}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":27,"y":0,"w":73,"h":105}, + "sourceSize": {"w":128,"h":128} +}, +"sprites/wires/pin_negative_eject.png": +{ + "frame": {"x":1975,"y":196,"w":63,"h":100}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":32,"y":0,"w":63,"h":100}, + "sourceSize": {"w":128,"h":128} +}, +"sprites/wires/pin_positive_accept.png": +{ + "frame": {"x":1651,"y":2463,"w":63,"h":100}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":32,"y":0,"w":63,"h":100}, + "sourceSize": {"w":128,"h":128} +}, +"sprites/wires/pin_positive_eject.png": +{ + "frame": {"x":1574,"y":2463,"w":73,"h":105}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":27,"y":0,"w":73,"h":105}, + "sourceSize": {"w":128,"h":128} +}, +"sprites/wires/positive_energy.png": +{ + "frame": {"x":1835,"y":2504,"w":42,"h":42}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":11,"y":11,"w":42,"h":42}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/waste_piled.png": +{ + "frame": {"x":1260,"y":1087,"w":58,"h":55}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":3,"y":4,"w":58,"h":55}, + "sourceSize": {"w":64,"h":64} }}, "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "1.0", "image": "atlas0_100.png", "format": "RGBA8888", - "size": {"w":2028,"h":2015}, + "size": {"w":2041,"h":2718}, "scale": "1", - "related_multi_packs": [ "atlas1_100.json" ], - "smartupdate": "$TexturePacker:SmartUpdate:dc34796c028235bbc69e5b8d854254ca:2765d0b8c8bcbb7a4aaaf1104853ad41:8778749683c68f53155587e6d831729a$" + "smartupdate": "$TexturePacker:SmartUpdate:4e5fb3bd7f1e5423e4fcea2215debe11:0c5d091d0b928944c68553dcc592c801:f159918d23e5952766c6d23ab52278c6$" } } diff --git a/res_built/atlas/atlas0_100.png b/res_built/atlas/atlas0_100.png index 2fb0cffb..a40f84d0 100644 Binary files a/res_built/atlas/atlas0_100.png and b/res_built/atlas/atlas0_100.png differ diff --git a/res_built/atlas/atlas0_25.json b/res_built/atlas/atlas0_25.json index 2065027f..dd58adcc 100644 --- a/res_built/atlas/atlas0_25.json +++ b/res_built/atlas/atlas0_25.json @@ -2,7 +2,7 @@ "sprites/belt/forward_0.png": { - "frame": {"x":191,"y":155,"w":28,"h":32}, + "frame": {"x":195,"y":433,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -10,7 +10,7 @@ }, "sprites/belt/forward_1.png": { - "frame": {"x":223,"y":155,"w":28,"h":32}, + "frame": {"x":741,"y":197,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -18,7 +18,7 @@ }, "sprites/belt/forward_2.png": { - "frame": {"x":865,"y":55,"w":28,"h":32}, + "frame": {"x":627,"y":252,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -26,7 +26,7 @@ }, "sprites/belt/forward_3.png": { - "frame": {"x":1121,"y":55,"w":28,"h":32}, + "frame": {"x":564,"y":289,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -34,7 +34,7 @@ }, "sprites/belt/forward_4.png": { - "frame": {"x":1149,"y":3,"w":28,"h":32}, + "frame": {"x":596,"y":288,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -42,7 +42,7 @@ }, "sprites/belt/forward_5.png": { - "frame": {"x":1087,"y":194,"w":28,"h":32}, + "frame": {"x":628,"y":288,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -50,7 +50,7 @@ }, "sprites/belt/forward_6.png": { - "frame": {"x":1108,"y":139,"w":28,"h":32}, + "frame": {"x":660,"y":288,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -58,7 +58,7 @@ }, "sprites/belt/forward_7.png": { - "frame": {"x":1122,"y":91,"w":28,"h":32}, + "frame": {"x":692,"y":283,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -66,7 +66,7 @@ }, "sprites/belt/forward_8.png": { - "frame": {"x":1153,"y":51,"w":28,"h":32}, + "frame": {"x":422,"y":331,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -74,7 +74,7 @@ }, "sprites/belt/forward_9.png": { - "frame": {"x":1181,"y":3,"w":28,"h":32}, + "frame": {"x":422,"y":367,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -82,7 +82,7 @@ }, "sprites/belt/forward_10.png": { - "frame": {"x":255,"y":155,"w":28,"h":32}, + "frame": {"x":227,"y":433,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -90,7 +90,7 @@ }, "sprites/belt/forward_11.png": { - "frame": {"x":287,"y":155,"w":28,"h":32}, + "frame": {"x":435,"y":253,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -98,7 +98,7 @@ }, "sprites/belt/forward_12.png": { - "frame": {"x":319,"y":155,"w":28,"h":32}, + "frame": {"x":467,"y":253,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -106,7 +106,7 @@ }, "sprites/belt/forward_13.png": { - "frame": {"x":351,"y":155,"w":28,"h":32}, + "frame": {"x":499,"y":253,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -114,7 +114,7 @@ }, "sprites/belt/forward_14.png": { - "frame": {"x":673,"y":55,"w":28,"h":32}, + "frame": {"x":531,"y":253,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -122,7 +122,7 @@ }, "sprites/belt/forward_15.png": { - "frame": {"x":705,"y":55,"w":28,"h":32}, + "frame": {"x":390,"y":295,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -130,7 +130,7 @@ }, "sprites/belt/forward_16.png": { - "frame": {"x":737,"y":55,"w":28,"h":32}, + "frame": {"x":390,"y":331,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -138,7 +138,7 @@ }, "sprites/belt/forward_17.png": { - "frame": {"x":769,"y":55,"w":28,"h":32}, + "frame": {"x":390,"y":367,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -146,7 +146,7 @@ }, "sprites/belt/forward_18.png": { - "frame": {"x":801,"y":55,"w":28,"h":32}, + "frame": {"x":563,"y":253,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -154,7 +154,7 @@ }, "sprites/belt/forward_19.png": { - "frame": {"x":833,"y":55,"w":28,"h":32}, + "frame": {"x":595,"y":252,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -162,7 +162,7 @@ }, "sprites/belt/forward_20.png": { - "frame": {"x":897,"y":55,"w":28,"h":32}, + "frame": {"x":659,"y":252,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -170,7 +170,7 @@ }, "sprites/belt/forward_21.png": { - "frame": {"x":929,"y":55,"w":28,"h":32}, + "frame": {"x":773,"y":197,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -178,7 +178,7 @@ }, "sprites/belt/forward_22.png": { - "frame": {"x":961,"y":55,"w":28,"h":32}, + "frame": {"x":792,"y":159,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -186,7 +186,7 @@ }, "sprites/belt/forward_23.png": { - "frame": {"x":993,"y":55,"w":28,"h":32}, + "frame": {"x":725,"y":249,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -194,7 +194,7 @@ }, "sprites/belt/forward_24.png": { - "frame": {"x":1025,"y":55,"w":28,"h":32}, + "frame": {"x":436,"y":289,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -202,7 +202,7 @@ }, "sprites/belt/forward_25.png": { - "frame": {"x":1057,"y":55,"w":28,"h":32}, + "frame": {"x":468,"y":289,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -210,7 +210,7 @@ }, "sprites/belt/forward_26.png": { - "frame": {"x":1089,"y":55,"w":28,"h":32}, + "frame": {"x":500,"y":289,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -218,7 +218,7 @@ }, "sprites/belt/forward_27.png": { - "frame": {"x":1090,"y":91,"w":28,"h":32}, + "frame": {"x":532,"y":289,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -226,7 +226,7 @@ }, "sprites/belt/left_0.png": { - "frame": {"x":1140,"y":139,"w":30,"h":30}, + "frame": {"x":691,"y":249,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -234,7 +234,7 @@ }, "sprites/belt/left_1.png": { - "frame": {"x":1123,"y":211,"w":30,"h":30}, + "frame": {"x":761,"y":233,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -242,7 +242,7 @@ }, "sprites/belt/left_2.png": { - "frame": {"x":1208,"y":107,"w":30,"h":30}, + "frame": {"x":758,"y":301,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -250,7 +250,7 @@ }, "sprites/belt/left_3.png": { - "frame": {"x":1315,"y":3,"w":30,"h":30}, + "frame": {"x":465,"y":393,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -258,7 +258,7 @@ }, "sprites/belt/left_4.png": { - "frame": {"x":1225,"y":175,"w":30,"h":30}, + "frame": {"x":499,"y":393,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -266,7 +266,7 @@ }, "sprites/belt/left_5.png": { - "frame": {"x":1253,"y":139,"w":30,"h":30}, + "frame": {"x":533,"y":393,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -274,7 +274,7 @@ }, "sprites/belt/left_6.png": { - "frame": {"x":1276,"y":105,"w":30,"h":30}, + "frame": {"x":567,"y":393,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -282,7 +282,7 @@ }, "sprites/belt/left_7.png": { - "frame": {"x":1290,"y":71,"w":30,"h":30}, + "frame": {"x":795,"y":233,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -290,7 +290,7 @@ }, "sprites/belt/left_8.png": { - "frame": {"x":1321,"y":37,"w":30,"h":30}, + "frame": {"x":792,"y":267,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -298,7 +298,7 @@ }, "sprites/belt/left_9.png": { - "frame": {"x":1349,"y":3,"w":30,"h":30}, + "frame": {"x":792,"y":301,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -306,7 +306,7 @@ }, "sprites/belt/left_10.png": { - "frame": {"x":1151,"y":173,"w":30,"h":30}, + "frame": {"x":724,"y":285,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -314,7 +314,7 @@ }, "sprites/belt/left_11.png": { - "frame": {"x":1157,"y":207,"w":30,"h":30}, + "frame": {"x":454,"y":325,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -322,7 +322,7 @@ }, "sprites/belt/left_12.png": { - "frame": {"x":1154,"y":87,"w":30,"h":30}, + "frame": {"x":454,"y":359,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -330,7 +330,7 @@ }, "sprites/belt/left_13.png": { - "frame": {"x":1185,"y":39,"w":30,"h":30}, + "frame": {"x":488,"y":325,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -338,7 +338,7 @@ }, "sprites/belt/left_14.png": { - "frame": {"x":1213,"y":3,"w":30,"h":30}, + "frame": {"x":488,"y":359,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -346,7 +346,7 @@ }, "sprites/belt/left_15.png": { - "frame": {"x":1174,"y":121,"w":30,"h":30}, + "frame": {"x":522,"y":325,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -354,7 +354,7 @@ }, "sprites/belt/left_16.png": { - "frame": {"x":1188,"y":73,"w":30,"h":30}, + "frame": {"x":522,"y":359,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -362,7 +362,7 @@ }, "sprites/belt/left_17.png": { - "frame": {"x":1219,"y":37,"w":30,"h":30}, + "frame": {"x":556,"y":325,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -370,7 +370,7 @@ }, "sprites/belt/left_18.png": { - "frame": {"x":1247,"y":3,"w":30,"h":30}, + "frame": {"x":556,"y":359,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -378,7 +378,7 @@ }, "sprites/belt/left_19.png": { - "frame": {"x":1185,"y":155,"w":30,"h":30}, + "frame": {"x":758,"y":267,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -386,7 +386,7 @@ }, "sprites/belt/left_20.png": { - "frame": {"x":1222,"y":71,"w":30,"h":30}, + "frame": {"x":295,"y":407,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -394,7 +394,7 @@ }, "sprites/belt/left_21.png": { - "frame": {"x":1253,"y":37,"w":30,"h":30}, + "frame": {"x":329,"y":407,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -402,7 +402,7 @@ }, "sprites/belt/left_22.png": { - "frame": {"x":1281,"y":3,"w":30,"h":30}, + "frame": {"x":363,"y":407,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -410,7 +410,7 @@ }, "sprites/belt/left_23.png": { - "frame": {"x":1191,"y":189,"w":30,"h":30}, + "frame": {"x":397,"y":403,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -418,7 +418,7 @@ }, "sprites/belt/left_24.png": { - "frame": {"x":1219,"y":141,"w":30,"h":30}, + "frame": {"x":291,"y":441,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -426,7 +426,7 @@ }, "sprites/belt/left_25.png": { - "frame": {"x":1242,"y":105,"w":30,"h":30}, + "frame": {"x":325,"y":441,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -434,7 +434,7 @@ }, "sprites/belt/left_26.png": { - "frame": {"x":1256,"y":71,"w":30,"h":30}, + "frame": {"x":359,"y":441,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -442,7 +442,7 @@ }, "sprites/belt/left_27.png": { - "frame": {"x":1287,"y":37,"w":30,"h":30}, + "frame": {"x":431,"y":403,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -450,7 +450,7 @@ }, "sprites/belt/right_0.png": { - "frame": {"x":1259,"y":173,"w":30,"h":30}, + "frame": {"x":465,"y":427,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -458,7 +458,7 @@ }, "sprites/belt/right_1.png": { - "frame": {"x":1287,"y":139,"w":30,"h":30}, + "frame": {"x":499,"y":427,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -466,7 +466,7 @@ }, "sprites/belt/right_2.png": { - "frame": {"x":1417,"y":3,"w":30,"h":30}, + "frame": {"x":601,"y":393,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -474,7 +474,7 @@ }, "sprites/belt/right_3.png": { - "frame": {"x":1361,"y":173,"w":30,"h":30}, + "frame": {"x":703,"y":387,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -482,7 +482,7 @@ }, "sprites/belt/right_4.png": { - "frame": {"x":1389,"y":139,"w":30,"h":30}, + "frame": {"x":703,"y":421,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -490,7 +490,7 @@ }, "sprites/belt/right_5.png": { - "frame": {"x":1412,"y":105,"w":30,"h":30}, + "frame": {"x":737,"y":384,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -498,7 +498,7 @@ }, "sprites/belt/right_6.png": { - "frame": {"x":1426,"y":71,"w":30,"h":30}, + "frame": {"x":737,"y":418,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -506,7 +506,7 @@ }, "sprites/belt/right_7.png": { - "frame": {"x":1446,"y":105,"w":30,"h":30}, + "frame": {"x":771,"y":369,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -514,7 +514,7 @@ }, "sprites/belt/right_8.png": { - "frame": {"x":1368,"y":207,"w":30,"h":30}, + "frame": {"x":771,"y":403,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -522,7 +522,7 @@ }, "sprites/belt/right_9.png": { - "frame": {"x":1395,"y":173,"w":30,"h":30}, + "frame": {"x":771,"y":437,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -530,7 +530,7 @@ }, "sprites/belt/right_10.png": { - "frame": {"x":1310,"y":105,"w":30,"h":30}, + "frame": {"x":533,"y":427,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -538,7 +538,7 @@ }, "sprites/belt/right_11.png": { - "frame": {"x":1324,"y":71,"w":30,"h":30}, + "frame": {"x":567,"y":427,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -546,7 +546,7 @@ }, "sprites/belt/right_12.png": { - "frame": {"x":1355,"y":37,"w":30,"h":30}, + "frame": {"x":590,"y":325,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -554,7 +554,7 @@ }, "sprites/belt/right_13.png": { - "frame": {"x":1383,"y":3,"w":30,"h":30}, + "frame": {"x":590,"y":359,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -562,7 +562,7 @@ }, "sprites/belt/right_14.png": { - "frame": {"x":1266,"y":207,"w":30,"h":30}, + "frame": {"x":624,"y":324,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -570,7 +570,7 @@ }, "sprites/belt/right_15.png": { - "frame": {"x":1293,"y":173,"w":30,"h":30}, + "frame": {"x":658,"y":324,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -578,7 +578,7 @@ }, "sprites/belt/right_16.png": { - "frame": {"x":1321,"y":139,"w":30,"h":30}, + "frame": {"x":692,"y":319,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -586,7 +586,7 @@ }, "sprites/belt/right_17.png": { - "frame": {"x":1344,"y":105,"w":30,"h":30}, + "frame": {"x":624,"y":358,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -594,7 +594,7 @@ }, "sprites/belt/right_18.png": { - "frame": {"x":1358,"y":71,"w":30,"h":30}, + "frame": {"x":658,"y":358,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -602,7 +602,7 @@ }, "sprites/belt/right_19.png": { - "frame": {"x":1389,"y":37,"w":30,"h":30}, + "frame": {"x":692,"y":353,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -610,7 +610,7 @@ }, "sprites/belt/right_20.png": { - "frame": {"x":1451,"y":3,"w":30,"h":30}, + "frame": {"x":601,"y":427,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -618,7 +618,7 @@ }, "sprites/belt/right_21.png": { - "frame": {"x":1300,"y":207,"w":30,"h":30}, + "frame": {"x":635,"y":392,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -626,7 +626,7 @@ }, "sprites/belt/right_22.png": { - "frame": {"x":1327,"y":173,"w":30,"h":30}, + "frame": {"x":635,"y":426,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -634,7 +634,7 @@ }, "sprites/belt/right_23.png": { - "frame": {"x":1355,"y":139,"w":30,"h":30}, + "frame": {"x":669,"y":392,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -642,7 +642,7 @@ }, "sprites/belt/right_24.png": { - "frame": {"x":1378,"y":105,"w":30,"h":30}, + "frame": {"x":669,"y":426,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -650,7 +650,7 @@ }, "sprites/belt/right_25.png": { - "frame": {"x":1392,"y":71,"w":30,"h":30}, + "frame": {"x":726,"y":350,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -658,7 +658,7 @@ }, "sprites/belt/right_26.png": { - "frame": {"x":1423,"y":37,"w":30,"h":30}, + "frame": {"x":760,"y":335,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -666,15 +666,23 @@ }, "sprites/belt/right_27.png": { - "frame": {"x":1334,"y":207,"w":30,"h":30}, + "frame": {"x":794,"y":335,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, "sourceSize": {"w":32,"h":32} }, +"sprites/blueprints/advanced_processor.png": +{ + "frame": {"x":3,"y":344,"w":95,"h":92}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":2,"w":95,"h":92}, + "sourceSize": {"w":96,"h":96} +}, "sprites/blueprints/belt_left.png": { - "frame": {"x":1423,"y":139,"w":30,"h":30}, + "frame": {"x":737,"y":452,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -682,7 +690,7 @@ }, "sprites/blueprints/belt_right.png": { - "frame": {"x":1402,"y":207,"w":30,"h":30}, + "frame": {"x":703,"y":455,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -690,7 +698,7 @@ }, "sprites/blueprints/belt_top.png": { - "frame": {"x":1119,"y":175,"w":28,"h":32}, + "frame": {"x":259,"y":432,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -698,7 +706,7 @@ }, "sprites/blueprints/cutter-quad.png": { - "frame": {"x":195,"y":191,"w":184,"h":48}, + "frame": {"x":3,"y":192,"w":184,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":184,"h":48}, @@ -706,7 +714,7 @@ }, "sprites/blueprints/cutter.png": { - "frame": {"x":844,"y":91,"w":87,"h":48}, + "frame": {"x":675,"y":55,"w":87,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":87,"h":48}, @@ -714,15 +722,15 @@ }, "sprites/blueprints/energy_generator.png": { - "frame": {"x":472,"y":103,"w":87,"h":94}, + "frame": {"x":102,"y":344,"w":89,"h":92}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":5,"y":2,"w":87,"h":94}, + "spriteSourceSize": {"x":4,"y":4,"w":89,"h":92}, "sourceSize": {"w":96,"h":96} }, "sprites/blueprints/miner-chainable.png": { - "frame": {"x":1006,"y":143,"w":47,"h":48}, + "frame": {"x":383,"y":205,"w":47,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":47,"h":48}, @@ -730,7 +738,7 @@ }, "sprites/blueprints/miner.png": { - "frame": {"x":1039,"y":91,"w":47,"h":48}, + "frame": {"x":434,"y":201,"w":47,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":47,"h":48}, @@ -738,7 +746,7 @@ }, "sprites/blueprints/mixer.png": { - "frame": {"x":751,"y":91,"w":89,"h":48}, + "frame": {"x":671,"y":3,"w":89,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":89,"h":48}, @@ -746,7 +754,7 @@ }, "sprites/blueprints/painter-double.png": { - "frame": {"x":191,"y":3,"w":96,"h":96}, + "frame": {"x":191,"y":107,"w":96,"h":96}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":96}, @@ -754,7 +762,7 @@ }, "sprites/blueprints/painter-mirrored.png": { - "frame": {"x":589,"y":195,"w":96,"h":48}, + "frame": {"x":383,"y":55,"w":96,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":48}, @@ -762,7 +770,7 @@ }, "sprites/blueprints/painter-quad.png": { - "frame": {"x":3,"y":192,"w":188,"h":48}, + "frame": {"x":191,"y":3,"w":188,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":188,"h":48}, @@ -770,7 +778,7 @@ }, "sprites/blueprints/painter.png": { - "frame": {"x":689,"y":195,"w":96,"h":48}, + "frame": {"x":571,"y":3,"w":96,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":48}, @@ -778,7 +786,7 @@ }, "sprites/blueprints/rotater-ccw.png": { - "frame": {"x":935,"y":91,"w":48,"h":48}, + "frame": {"x":764,"y":3,"w":48,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":48}, @@ -786,7 +794,7 @@ }, "sprites/blueprints/rotater.png": { - "frame": {"x":880,"y":195,"w":48,"h":48}, + "frame": {"x":766,"y":55,"w":48,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":48}, @@ -794,7 +802,7 @@ }, "sprites/blueprints/splitter-compact-inverse.png": { - "frame": {"x":932,"y":195,"w":48,"h":48}, + "frame": {"x":756,"y":107,"w":48,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":48}, @@ -802,7 +810,7 @@ }, "sprites/blueprints/splitter-compact.png": { - "frame": {"x":538,"y":201,"w":47,"h":47}, + "frame": {"x":639,"y":201,"w":47,"h":47}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":47,"h":47}, @@ -810,7 +818,7 @@ }, "sprites/blueprints/splitter.png": { - "frame": {"x":955,"y":3,"w":87,"h":48}, + "frame": {"x":665,"y":107,"w":87,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":87,"h":48}, @@ -818,7 +826,7 @@ }, "sprites/blueprints/stacker.png": { - "frame": {"x":770,"y":143,"w":89,"h":48}, + "frame": {"x":480,"y":107,"w":89,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":89,"h":48}, @@ -826,7 +834,7 @@ }, "sprites/blueprints/trash-storage.png": { - "frame": {"x":383,"y":103,"w":85,"h":96}, + "frame": {"x":291,"y":107,"w":85,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":85,"h":96}, @@ -834,7 +842,7 @@ }, "sprites/blueprints/trash.png": { - "frame": {"x":954,"y":143,"w":48,"h":48}, + "frame": {"x":286,"y":303,"w":48,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":48}, @@ -842,7 +850,7 @@ }, "sprites/blueprints/underground_belt_entry-tier2.png": { - "frame": {"x":383,"y":203,"w":48,"h":43}, + "frame": {"x":3,"y":440,"w":48,"h":43}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":5,"w":48,"h":43}, @@ -850,7 +858,7 @@ }, "sprites/blueprints/underground_belt_entry.png": { - "frame": {"x":563,"y":153,"w":48,"h":38}, + "frame": {"x":55,"y":440,"w":48,"h":38}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":10,"w":48,"h":38}, @@ -858,7 +866,7 @@ }, "sprites/blueprints/underground_belt_exit-tier2.png": { - "frame": {"x":615,"y":153,"w":48,"h":38}, + "frame": {"x":431,"y":159,"w":48,"h":38}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":38}, @@ -866,15 +874,63 @@ }, "sprites/blueprints/underground_belt_exit.png": { - "frame": {"x":667,"y":153,"w":48,"h":38}, + "frame": {"x":483,"y":159,"w":48,"h":38}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":38}, "sourceSize": {"w":48,"h":48} }, +"sprites/blueprints/wire_crossings-merger.png": +{ + "frame": {"x":107,"y":440,"w":48,"h":35}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":48,"h":35}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/blueprints/wire_crossings.png": +{ + "frame": {"x":740,"y":159,"w":48,"h":34}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":14,"w":48,"h":34}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/blueprints/wire_left.png": +{ + "frame": {"x":808,"y":107,"w":21,"h":21}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":11,"w":21,"h":21}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/blueprints/wire_right.png": +{ + "frame": {"x":808,"y":132,"w":21,"h":21}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":11,"y":11,"w":21,"h":21}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/blueprints/wire_top.png": +{ + "frame": {"x":816,"y":3,"w":10,"h":32}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":11,"y":0,"w":10,"h":32}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/buildings/advanced_processor.png": +{ + "frame": {"x":192,"y":207,"w":94,"h":91}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":2,"w":94,"h":91}, + "sourceSize": {"w":96,"h":96} +}, "sprites/buildings/belt_left.png": { - "frame": {"x":1429,"y":173,"w":30,"h":30}, + "frame": {"x":397,"y":437,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":30,"h":30}, @@ -882,7 +938,7 @@ }, "sprites/buildings/belt_right.png": { - "frame": {"x":1436,"y":207,"w":30,"h":30}, + "frame": {"x":431,"y":437,"w":30,"h":30}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":30,"h":30}, @@ -890,7 +946,7 @@ }, "sprites/buildings/belt_top.png": { - "frame": {"x":191,"y":155,"w":28,"h":32}, + "frame": {"x":195,"y":433,"w":28,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":28,"h":32}, @@ -898,7 +954,7 @@ }, "sprites/buildings/cutter-quad.png": { - "frame": {"x":563,"y":101,"w":184,"h":48}, + "frame": {"x":383,"y":3,"w":184,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":184,"h":48}, @@ -906,7 +962,7 @@ }, "sprites/buildings/cutter.png": { - "frame": {"x":789,"y":195,"w":87,"h":48}, + "frame": {"x":195,"y":302,"w":87,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":87,"h":48}, @@ -914,10 +970,10 @@ }, "sprites/buildings/energy_generator.png": { - "frame": {"x":480,"y":3,"w":87,"h":94}, + "frame": {"x":290,"y":207,"w":89,"h":92}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":5,"y":2,"w":87,"h":94}, + "spriteSourceSize": {"x":4,"y":4,"w":89,"h":92}, "sourceSize": {"w":96,"h":96} }, "sprites/buildings/hub.png": @@ -930,7 +986,7 @@ }, "sprites/buildings/miner-chainable.png": { - "frame": {"x":1098,"y":3,"w":47,"h":48}, + "frame": {"x":485,"y":201,"w":47,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":47,"h":48}, @@ -938,7 +994,7 @@ }, "sprites/buildings/miner.png": { - "frame": {"x":1036,"y":195,"w":47,"h":48}, + "frame": {"x":536,"y":201,"w":47,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":47,"h":48}, @@ -946,7 +1002,7 @@ }, "sprites/buildings/mixer.png": { - "frame": {"x":771,"y":3,"w":88,"h":48}, + "frame": {"x":583,"y":55,"w":88,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":4,"y":0,"w":88,"h":48}, @@ -954,7 +1010,7 @@ }, "sprites/buildings/painter-double.png": { - "frame": {"x":291,"y":3,"w":96,"h":96}, + "frame": {"x":3,"y":244,"w":96,"h":96}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":96}, @@ -962,7 +1018,7 @@ }, "sprites/buildings/painter-mirrored.png": { - "frame": {"x":571,"y":3,"w":96,"h":48}, + "frame": {"x":380,"y":107,"w":96,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":48}, @@ -970,7 +1026,7 @@ }, "sprites/buildings/painter-quad.png": { - "frame": {"x":191,"y":103,"w":188,"h":48}, + "frame": {"x":191,"y":55,"w":188,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":188,"h":48}, @@ -978,7 +1034,7 @@ }, "sprites/buildings/painter.png": { - "frame": {"x":671,"y":3,"w":96,"h":48}, + "frame": {"x":483,"y":55,"w":96,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":48}, @@ -986,7 +1042,7 @@ }, "sprites/buildings/rotater-ccw.png": { - "frame": {"x":987,"y":91,"w":48,"h":48}, + "frame": {"x":286,"y":355,"w":48,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":48}, @@ -994,7 +1050,7 @@ }, "sprites/buildings/rotater.png": { - "frame": {"x":1046,"y":3,"w":48,"h":48}, + "frame": {"x":338,"y":303,"w":48,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":48}, @@ -1002,7 +1058,7 @@ }, "sprites/buildings/splitter-compact-inverse.png": { - "frame": {"x":486,"y":201,"w":48,"h":47}, + "frame": {"x":587,"y":201,"w":48,"h":47}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":47}, @@ -1010,7 +1066,7 @@ }, "sprites/buildings/splitter-compact.png": { - "frame": {"x":1057,"y":143,"w":47,"h":47}, + "frame": {"x":690,"y":198,"w":47,"h":47}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":47,"h":47}, @@ -1018,7 +1074,7 @@ }, "sprites/buildings/splitter.png": { - "frame": {"x":863,"y":143,"w":87,"h":48}, + "frame": {"x":195,"y":354,"w":87,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":87,"h":48}, @@ -1026,7 +1082,7 @@ }, "sprites/buildings/stacker.png": { - "frame": {"x":863,"y":3,"w":88,"h":48}, + "frame": {"x":573,"y":107,"w":88,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":4,"y":0,"w":88,"h":48}, @@ -1034,7 +1090,7 @@ }, "sprites/buildings/trash-storage.png": { - "frame": {"x":391,"y":3,"w":85,"h":96}, + "frame": {"x":103,"y":244,"w":85,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":85,"h":96}, @@ -1042,7 +1098,7 @@ }, "sprites/buildings/trash.png": { - "frame": {"x":984,"y":195,"w":48,"h":48}, + "frame": {"x":338,"y":355,"w":48,"h":48}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":48,"h":48}, @@ -1050,7 +1106,7 @@ }, "sprites/buildings/underground_belt_entry-tier2.png": { - "frame": {"x":435,"y":203,"w":47,"h":42}, + "frame": {"x":380,"y":159,"w":47,"h":42}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":6,"w":47,"h":42}, @@ -1058,7 +1114,7 @@ }, "sprites/buildings/underground_belt_entry.png": { - "frame": {"x":719,"y":153,"w":47,"h":38}, + "frame": {"x":535,"y":159,"w":47,"h":38}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":10,"w":47,"h":38}, @@ -1066,7 +1122,7 @@ }, "sprites/buildings/underground_belt_exit-tier2.png": { - "frame": {"x":571,"y":55,"w":47,"h":38}, + "frame": {"x":586,"y":159,"w":47,"h":38}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":47,"h":38}, @@ -1074,15 +1130,55 @@ }, "sprites/buildings/underground_belt_exit.png": { - "frame": {"x":622,"y":55,"w":47,"h":38}, + "frame": {"x":637,"y":159,"w":47,"h":38}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":47,"h":38}, "sourceSize": {"w":48,"h":48} }, +"sprites/buildings/wire_crossings-merger.png": +{ + "frame": {"x":688,"y":159,"w":48,"h":35}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":48,"h":35}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/buildings/wire_crossings.png": +{ + "frame": {"x":383,"y":257,"w":48,"h":34}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":14,"w":48,"h":34}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/buildings/wire_left.png": +{ + "frame": {"x":270,"y":407,"w":21,"h":21}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":11,"w":21,"h":21}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/buildings/wire_right.png": +{ + "frame": {"x":805,"y":457,"w":21,"h":21}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":11,"y":11,"w":21,"h":21}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/buildings/wire_top.png": +{ + "frame": {"x":422,"y":295,"w":10,"h":32}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":11,"y":0,"w":10,"h":32}, + "sourceSize": {"w":32,"h":32} +}, "sprites/debug/acceptor_slot.png": { - "frame": {"x":1087,"y":230,"w":14,"h":16}, + "frame": {"x":259,"y":468,"w":14,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":14,"h":16}, @@ -1090,7 +1186,7 @@ }, "sprites/debug/ejector_slot.png": { - "frame": {"x":1105,"y":230,"w":14,"h":16}, + "frame": {"x":485,"y":461,"w":14,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":14,"h":16}, @@ -1098,7 +1194,7 @@ }, "sprites/map_overview/belt_forward.png": { - "frame": {"x":1106,"y":127,"w":8,"h":8}, + "frame": {"x":277,"y":468,"w":8,"h":8}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":8,"h":8}, @@ -1106,7 +1202,7 @@ }, "sprites/map_overview/belt_left.png": { - "frame": {"x":1149,"y":39,"w":8,"h":8}, + "frame": {"x":791,"y":471,"w":8,"h":8}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":8,"h":8}, @@ -1114,7 +1210,7 @@ }, "sprites/map_overview/belt_right.png": { - "frame": {"x":1118,"y":127,"w":8,"h":8}, + "frame": {"x":175,"y":476,"w":8,"h":8}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":8,"h":8}, @@ -1122,15 +1218,23 @@ }, "sprites/misc/deletion_marker.png": { - "frame": {"x":1457,"y":37,"w":22,"h":22}, + "frame": {"x":244,"y":406,"w":22,"h":22}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":1,"w":22,"h":22}, "sourceSize": {"w":24,"h":24} }, +"sprites/misc/energy_generator_overlay.png": +{ + "frame": {"x":195,"y":469,"w":40,"h":17}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":45,"y":71,"w":40,"h":17}, + "sourceSize": {"w":96,"h":96} +}, "sprites/misc/hub_direction_indicator.png": { - "frame": {"x":1130,"y":127,"w":8,"h":8}, + "frame": {"x":818,"y":55,"w":8,"h":8}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":8,"h":8}, @@ -1138,7 +1242,7 @@ }, "sprites/misc/lock_direction_indicator.png": { - "frame": {"x":1090,"y":127,"w":12,"h":10}, + "frame": {"x":159,"y":476,"w":12,"h":10}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":1,"w":12,"h":10}, @@ -1146,7 +1250,7 @@ }, "sprites/misc/slot_bad_arrow.png": { - "frame": {"x":1457,"y":37,"w":22,"h":22}, + "frame": {"x":244,"y":406,"w":22,"h":22}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":1,"w":22,"h":22}, @@ -1154,7 +1258,7 @@ }, "sprites/misc/slot_good_arrow.png": { - "frame": {"x":1191,"y":223,"w":22,"h":24}, + "frame": {"x":805,"y":429,"w":22,"h":24}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":22,"h":24}, @@ -1162,7 +1266,7 @@ }, "sprites/misc/storage_overlay.png": { - "frame": {"x":1217,"y":223,"w":45,"h":23}, + "frame": {"x":195,"y":406,"w":45,"h":23}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":45,"h":23}, @@ -1170,19 +1274,115 @@ }, "sprites/misc/waypoint.png": { - "frame": {"x":1161,"y":39,"w":8,"h":8}, + "frame": {"x":535,"y":461,"w":8,"h":8}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":8,"h":8}, "sourceSize": {"w":8,"h":8} +}, +"sprites/misc/wires_overlay_tile.png": +{ + "frame": {"x":159,"y":440,"w":32,"h":32}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":32,"h":32}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/battery_empty.png": +{ + "frame": {"x":503,"y":461,"w":12,"h":16}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":0,"w":12,"h":16}, + "sourceSize": {"w":16,"h":16} +}, +"sprites/wires/battery_full.png": +{ + "frame": {"x":741,"y":233,"w":16,"h":12}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":2,"w":16,"h":12}, + "sourceSize": {"w":16,"h":16} +}, +"sprites/wires/battery_low.png": +{ + "frame": {"x":771,"y":471,"w":16,"h":12}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":2,"w":16,"h":12}, + "sourceSize": {"w":16,"h":16} +}, +"sprites/wires/battery_medium.png": +{ + "frame": {"x":465,"y":461,"w":16,"h":12}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":2,"w":16,"h":12}, + "sourceSize": {"w":16,"h":16} +}, +"sprites/wires/negative_energy.png": +{ + "frame": {"x":816,"y":39,"w":12,"h":12}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":2,"w":12,"h":12}, + "sourceSize": {"w":16,"h":16} +}, +"sprites/wires/pin_negative_accept.png": +{ + "frame": {"x":805,"y":195,"w":20,"h":27}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":6,"y":0,"w":20,"h":27}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/pin_negative_eject.png": +{ + "frame": {"x":805,"y":369,"w":18,"h":26}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":7,"y":0,"w":18,"h":26}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/pin_positive_accept.png": +{ + "frame": {"x":805,"y":399,"w":18,"h":26}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":7,"y":0,"w":18,"h":26}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/pin_positive_eject.png": +{ + "frame": {"x":726,"y":319,"w":20,"h":27}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":6,"y":0,"w":20,"h":27}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/positive_energy.png": +{ + "frame": {"x":519,"y":461,"w":12,"h":12}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":2,"w":12,"h":12}, + "sourceSize": {"w":16,"h":16} +}, +"sprites/wires/waste_piled.png": +{ + "frame": {"x":239,"y":469,"w":16,"h":16}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, + "sourceSize": {"w":16,"h":16} }}, "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "1.0", "image": "atlas0_25.png", "format": "RGBA8888", - "size": {"w":1484,"h":251}, + "size": {"w":832,"h":489}, "scale": "0.25", - "smartupdate": "$TexturePacker:SmartUpdate:dc34796c028235bbc69e5b8d854254ca:2765d0b8c8bcbb7a4aaaf1104853ad41:8778749683c68f53155587e6d831729a$" + "smartupdate": "$TexturePacker:SmartUpdate:4e5fb3bd7f1e5423e4fcea2215debe11:0c5d091d0b928944c68553dcc592c801:f159918d23e5952766c6d23ab52278c6$" } } diff --git a/res_built/atlas/atlas0_25.png b/res_built/atlas/atlas0_25.png index 0d49e2e8..f4b2409b 100644 Binary files a/res_built/atlas/atlas0_25.png and b/res_built/atlas/atlas0_25.png differ diff --git a/res_built/atlas/atlas0_50.json b/res_built/atlas/atlas0_50.json index f9651cb6..4e89c4a1 100644 --- a/res_built/atlas/atlas0_50.json +++ b/res_built/atlas/atlas0_50.json @@ -2,7 +2,7 @@ "sprites/belt/forward_0.png": { - "frame": {"x":1234,"y":403,"w":51,"h":63}, + "frame": {"x":962,"y":484,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -10,7 +10,7 @@ }, "sprites/belt/forward_1.png": { - "frame": {"x":905,"y":503,"w":51,"h":63}, + "frame": {"x":740,"y":481,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -18,7 +18,7 @@ }, "sprites/belt/forward_2.png": { - "frame": {"x":588,"y":678,"w":51,"h":63}, + "frame": {"x":881,"y":735,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -26,7 +26,7 @@ }, "sprites/belt/forward_3.png": { - "frame": {"x":753,"y":666,"w":51,"h":63}, + "frame": {"x":991,"y":868,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -34,7 +34,7 @@ }, "sprites/belt/forward_4.png": { - "frame": {"x":753,"y":733,"w":51,"h":63}, + "frame": {"x":1046,"y":868,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -42,7 +42,7 @@ }, "sprites/belt/forward_5.png": { - "frame": {"x":808,"y":676,"w":51,"h":63}, + "frame": {"x":1017,"y":535,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -50,7 +50,7 @@ }, "sprites/belt/forward_6.png": { - "frame": {"x":808,"y":743,"w":51,"h":63}, + "frame": {"x":1015,"y":602,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -58,7 +58,7 @@ }, "sprites/belt/forward_7.png": { - "frame": {"x":863,"y":692,"w":51,"h":63}, + "frame": {"x":1047,"y":669,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -66,7 +66,7 @@ }, "sprites/belt/forward_8.png": { - "frame": {"x":863,"y":759,"w":51,"h":63}, + "frame": {"x":1102,"y":664,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -74,7 +74,7 @@ }, "sprites/belt/forward_9.png": { - "frame": {"x":918,"y":698,"w":51,"h":63}, + "frame": {"x":1157,"y":664,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -82,7 +82,7 @@ }, "sprites/belt/forward_10.png": { - "frame": {"x":960,"y":503,"w":51,"h":63}, + "frame": {"x":765,"y":591,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -90,7 +90,7 @@ }, "sprites/belt/forward_11.png": { - "frame": {"x":966,"y":570,"w":51,"h":63}, + "frame": {"x":766,"y":658,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -98,7 +98,7 @@ }, "sprites/belt/forward_12.png": { - "frame": {"x":1021,"y":564,"w":51,"h":63}, + "frame": {"x":766,"y":725,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -106,7 +106,7 @@ }, "sprites/belt/forward_13.png": { - "frame": {"x":1076,"y":564,"w":51,"h":63}, + "frame": {"x":763,"y":853,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -114,7 +114,7 @@ }, "sprites/belt/forward_14.png": { - "frame": {"x":1131,"y":564,"w":51,"h":63}, + "frame": {"x":821,"y":638,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -122,7 +122,7 @@ }, "sprites/belt/forward_15.png": { - "frame": {"x":1198,"y":503,"w":51,"h":63}, + "frame": {"x":821,"y":705,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -130,7 +130,7 @@ }, "sprites/belt/forward_16.png": { - "frame": {"x":1247,"y":570,"w":51,"h":63}, + "frame": {"x":876,"y":668,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -138,7 +138,7 @@ }, "sprites/belt/forward_17.png": { - "frame": {"x":472,"y":657,"w":51,"h":63}, + "frame": {"x":826,"y":772,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -146,7 +146,7 @@ }, "sprites/belt/forward_18.png": { - "frame": {"x":463,"y":785,"w":51,"h":63}, + "frame": {"x":992,"y":673,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -154,7 +154,7 @@ }, "sprites/belt/forward_19.png": { - "frame": {"x":466,"y":852,"w":51,"h":63}, + "frame": {"x":763,"y":920,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -162,7 +162,7 @@ }, "sprites/belt/forward_20.png": { - "frame": {"x":643,"y":677,"w":51,"h":63}, + "frame": {"x":936,"y":734,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -170,7 +170,7 @@ }, "sprites/belt/forward_21.png": { - "frame": {"x":588,"y":745,"w":51,"h":63}, + "frame": {"x":881,"y":802,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -178,7 +178,7 @@ }, "sprites/belt/forward_22.png": { - "frame": {"x":643,"y":744,"w":51,"h":63}, + "frame": {"x":936,"y":801,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -186,7 +186,7 @@ }, "sprites/belt/forward_23.png": { - "frame": {"x":521,"y":852,"w":51,"h":63}, + "frame": {"x":991,"y":801,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -194,7 +194,7 @@ }, "sprites/belt/forward_24.png": { - "frame": {"x":698,"y":677,"w":51,"h":63}, + "frame": {"x":826,"y":839,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -202,7 +202,7 @@ }, "sprites/belt/forward_25.png": { - "frame": {"x":698,"y":744,"w":51,"h":63}, + "frame": {"x":818,"y":906,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -210,7 +210,7 @@ }, "sprites/belt/forward_26.png": { - "frame": {"x":722,"y":599,"w":51,"h":63}, + "frame": {"x":881,"y":869,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -218,7 +218,7 @@ }, "sprites/belt/forward_27.png": { - "frame": {"x":777,"y":597,"w":51,"h":63}, + "frame": {"x":936,"y":868,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -226,7 +226,7 @@ }, "sprites/belt/left_0.png": { - "frame": {"x":1015,"y":503,"w":57,"h":57}, + "frame": {"x":1074,"y":481,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -234,7 +234,7 @@ }, "sprites/belt/left_1.png": { - "frame": {"x":1076,"y":503,"w":57,"h":57}, + "frame": {"x":1135,"y":481,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -242,7 +242,7 @@ }, "sprites/belt/left_2.png": { - "frame": {"x":973,"y":698,"w":57,"h":57}, + "frame": {"x":931,"y":673,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -250,7 +250,7 @@ }, "sprites/belt/left_3.png": { - "frame": {"x":1156,"y":692,"w":57,"h":57}, + "frame": {"x":1131,"y":603,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -258,7 +258,7 @@ }, "sprites/belt/left_4.png": { - "frame": {"x":1162,"y":753,"w":57,"h":57}, + "frame": {"x":1192,"y":603,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -266,7 +266,7 @@ }, "sprites/belt/left_5.png": { - "frame": {"x":576,"y":812,"w":57,"h":57}, + "frame": {"x":1253,"y":603,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -274,7 +274,7 @@ }, "sprites/belt/left_6.png": { - "frame": {"x":576,"y":873,"w":57,"h":57}, + "frame": {"x":1314,"y":603,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -282,7 +282,7 @@ }, "sprites/belt/left_7.png": { - "frame": {"x":561,"y":934,"w":57,"h":57}, + "frame": {"x":1212,"y":664,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -290,7 +290,7 @@ }, "sprites/belt/left_8.png": { - "frame": {"x":622,"y":934,"w":57,"h":57}, + "frame": {"x":1273,"y":664,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -298,7 +298,7 @@ }, "sprites/belt/left_9.png": { - "frame": {"x":979,"y":820,"w":57,"h":57}, + "frame": {"x":1052,"y":736,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -306,7 +306,7 @@ }, "sprites/belt/left_10.png": { - "frame": {"x":1137,"y":503,"w":57,"h":57}, + "frame": {"x":1196,"y":481,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -314,7 +314,7 @@ }, "sprites/belt/left_11.png": { - "frame": {"x":905,"y":570,"w":57,"h":57}, + "frame": {"x":1257,"y":481,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -322,7 +322,7 @@ }, "sprites/belt/left_12.png": { - "frame": {"x":1186,"y":570,"w":57,"h":57}, + "frame": {"x":1318,"y":481,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -330,7 +330,7 @@ }, "sprites/belt/left_13.png": { - "frame": {"x":527,"y":678,"w":57,"h":57}, + "frame": {"x":832,"y":516,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -338,7 +338,7 @@ }, "sprites/belt/left_14.png": { - "frame": {"x":466,"y":724,"w":57,"h":57}, + "frame": {"x":893,"y":546,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -346,7 +346,7 @@ }, "sprites/belt/left_15.png": { - "frame": {"x":527,"y":739,"w":57,"h":57}, + "frame": {"x":954,"y":551,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -354,7 +354,7 @@ }, "sprites/belt/left_16.png": { - "frame": {"x":832,"y":615,"w":57,"h":57}, + "frame": {"x":832,"y":577,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -362,7 +362,7 @@ }, "sprites/belt/left_17.png": { - "frame": {"x":893,"y":631,"w":57,"h":57}, + "frame": {"x":893,"y":607,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -370,7 +370,7 @@ }, "sprites/belt/left_18.png": { - "frame": {"x":954,"y":637,"w":57,"h":57}, + "frame": {"x":954,"y":612,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -378,7 +378,7 @@ }, "sprites/belt/left_19.png": { - "frame": {"x":918,"y":765,"w":57,"h":57}, + "frame": {"x":765,"y":792,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -386,7 +386,7 @@ }, "sprites/belt/left_20.png": { - "frame": {"x":979,"y":759,"w":57,"h":57}, + "frame": {"x":991,"y":740,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -394,7 +394,7 @@ }, "sprites/belt/left_21.png": { - "frame": {"x":1015,"y":637,"w":57,"h":57}, + "frame": {"x":873,"y":936,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -402,7 +402,7 @@ }, "sprites/belt/left_22.png": { - "frame": {"x":1076,"y":631,"w":57,"h":57}, + "frame": {"x":1072,"y":542,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -410,7 +410,7 @@ }, "sprites/belt/left_23.png": { - "frame": {"x":1137,"y":631,"w":57,"h":57}, + "frame": {"x":1133,"y":542,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -418,7 +418,7 @@ }, "sprites/belt/left_24.png": { - "frame": {"x":1034,"y":698,"w":57,"h":57}, + "frame": {"x":1194,"y":542,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -426,7 +426,7 @@ }, "sprites/belt/left_25.png": { - "frame": {"x":1040,"y":759,"w":57,"h":57}, + "frame": {"x":1255,"y":542,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -434,7 +434,7 @@ }, "sprites/belt/left_26.png": { - "frame": {"x":1095,"y":692,"w":57,"h":57}, + "frame": {"x":1316,"y":542,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -442,7 +442,7 @@ }, "sprites/belt/left_27.png": { - "frame": {"x":1101,"y":753,"w":57,"h":57}, + "frame": {"x":1070,"y":603,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -450,7 +450,7 @@ }, "sprites/belt/right_0.png": { - "frame": {"x":1040,"y":820,"w":57,"h":57}, + "frame": {"x":1113,"y":731,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -458,7 +458,7 @@ }, "sprites/belt/right_1.png": { - "frame": {"x":1101,"y":814,"w":57,"h":57}, + "frame": {"x":1067,"y":797,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -466,7 +466,7 @@ }, "sprites/belt/right_2.png": { - "frame": {"x":881,"y":826,"w":57,"h":57}, + "frame": {"x":1375,"y":603,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -474,7 +474,7 @@ }, "sprites/belt/right_3.png": { - "frame": {"x":1186,"y":875,"w":57,"h":57}, + "frame": {"x":1162,"y":914,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -482,7 +482,7 @@ }, "sprites/belt/right_4.png": { - "frame": {"x":927,"y":948,"w":57,"h":57}, + "frame": {"x":1223,"y":914,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -490,7 +490,7 @@ }, "sprites/belt/right_5.png": { - "frame": {"x":988,"y":942,"w":57,"h":57}, + "frame": {"x":1284,"y":908,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -498,7 +498,7 @@ }, "sprites/belt/right_6.png": { - "frame": {"x":1049,"y":942,"w":57,"h":57}, + "frame": {"x":1345,"y":908,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -506,7 +506,7 @@ }, "sprites/belt/right_7.png": { - "frame": {"x":1110,"y":942,"w":57,"h":57}, + "frame": {"x":573,"y":947,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -514,7 +514,7 @@ }, "sprites/belt/right_8.png": { - "frame": {"x":1171,"y":936,"w":57,"h":57}, + "frame": {"x":634,"y":947,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -522,7 +522,7 @@ }, "sprites/belt/right_9.png": { - "frame": {"x":1232,"y":936,"w":57,"h":57}, + "frame": {"x":695,"y":946,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -530,7 +530,7 @@ }, "sprites/belt/right_10.png": { - "frame": {"x":1162,"y":814,"w":57,"h":57}, + "frame": {"x":1334,"y":664,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -538,7 +538,7 @@ }, "sprites/belt/right_11.png": { - "frame": {"x":637,"y":812,"w":57,"h":57}, + "frame": {"x":1128,"y":792,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -546,7 +546,7 @@ }, "sprites/belt/right_12.png": { - "frame": {"x":637,"y":873,"w":57,"h":57}, + "frame": {"x":1174,"y":731,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -554,7 +554,7 @@ }, "sprites/belt/right_13.png": { - "frame": {"x":698,"y":811,"w":57,"h":57}, + "frame": {"x":1235,"y":725,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -562,7 +562,7 @@ }, "sprites/belt/right_14.png": { - "frame": {"x":698,"y":872,"w":57,"h":57}, + "frame": {"x":1296,"y":725,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -570,7 +570,7 @@ }, "sprites/belt/right_15.png": { - "frame": {"x":683,"y":934,"w":57,"h":57}, + "frame": {"x":1189,"y":792,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -578,7 +578,7 @@ }, "sprites/belt/right_16.png": { - "frame": {"x":744,"y":933,"w":57,"h":57}, + "frame": {"x":1250,"y":786,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -586,7 +586,7 @@ }, "sprites/belt/right_17.png": { - "frame": {"x":759,"y":810,"w":57,"h":57}, + "frame": {"x":1311,"y":786,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -594,7 +594,7 @@ }, "sprites/belt/right_18.png": { - "frame": {"x":759,"y":871,"w":57,"h":57}, + "frame": {"x":1357,"y":725,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -602,7 +602,7 @@ }, "sprites/belt/right_19.png": { - "frame": {"x":820,"y":826,"w":57,"h":57}, + "frame": {"x":1372,"y":786,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -610,7 +610,7 @@ }, "sprites/belt/right_20.png": { - "frame": {"x":820,"y":887,"w":57,"h":57}, + "frame": {"x":1377,"y":542,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -618,7 +618,7 @@ }, "sprites/belt/right_21.png": { - "frame": {"x":881,"y":887,"w":57,"h":57}, + "frame": {"x":1379,"y":481,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -626,7 +626,7 @@ }, "sprites/belt/right_22.png": { - "frame": {"x":805,"y":948,"w":57,"h":57}, + "frame": {"x":1101,"y":858,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -634,7 +634,7 @@ }, "sprites/belt/right_23.png": { - "frame": {"x":866,"y":948,"w":57,"h":57}, + "frame": {"x":1162,"y":853,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -642,7 +642,7 @@ }, "sprites/belt/right_24.png": { - "frame": {"x":942,"y":881,"w":57,"h":57}, + "frame": {"x":1223,"y":853,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -650,7 +650,7 @@ }, "sprites/belt/right_25.png": { - "frame": {"x":1003,"y":881,"w":57,"h":57}, + "frame": {"x":1284,"y":847,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -658,7 +658,7 @@ }, "sprites/belt/right_26.png": { - "frame": {"x":1064,"y":881,"w":57,"h":57}, + "frame": {"x":1345,"y":847,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -666,15 +666,23 @@ }, "sprites/belt/right_27.png": { - "frame": {"x":1125,"y":875,"w":57,"h":57}, + "frame": {"x":1101,"y":919,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, "sourceSize": {"w":63,"h":63} }, +"sprites/blueprints/advanced_processor.png": +{ + "frame": {"x":3,"y":669,"w":188,"h":181}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":4,"y":5,"w":188,"h":181}, + "sourceSize": {"w":192,"h":192} +}, "sprites/blueprints/belt_left.png": { - "frame": {"x":843,"y":491,"w":58,"h":58}, + "frame": {"x":838,"y":454,"w":58,"h":58}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":5,"w":58,"h":58}, @@ -682,7 +690,7 @@ }, "sprites/blueprints/belt_right.png": { - "frame": {"x":843,"y":553,"w":58,"h":58}, + "frame": {"x":900,"y":484,"w":58,"h":58}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":5,"w":58,"h":58}, @@ -690,7 +698,7 @@ }, "sprites/blueprints/belt_top.png": { - "frame": {"x":472,"y":590,"w":53,"h":63}, + "frame": {"x":1017,"y":468,"w":53,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":53,"h":63}, @@ -706,7 +714,7 @@ }, "sprites/blueprints/cutter.png": { - "frame": {"x":1126,"y":103,"w":172,"h":96}, + "frame": {"x":373,"y":399,"w":172,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":11,"y":0,"w":172,"h":96}, @@ -714,15 +722,15 @@ }, "sprites/blueprints/energy_generator.png": { - "frame": {"x":199,"y":474,"w":170,"h":187}, + "frame": {"x":195,"y":670,"w":175,"h":183}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":12,"y":5,"w":170,"h":187}, + "spriteSourceSize": {"x":9,"y":9,"w":175,"h":183}, "sourceSize": {"w":192,"h":192} }, "sprites/blueprints/miner-chainable.png": { - "frame": {"x":173,"y":669,"w":92,"h":96}, + "frame": {"x":473,"y":669,"w":92,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":92,"h":96}, @@ -730,7 +738,7 @@ }, "sprites/blueprints/miner.png": { - "frame": {"x":178,"y":864,"w":92,"h":96}, + "frame": {"x":477,"y":856,"w":92,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":92,"h":96}, @@ -738,7 +746,7 @@ }, "sprites/blueprints/mixer.png": { - "frame": {"x":1121,"y":3,"w":175,"h":96}, + "frame": {"x":3,"y":854,"w":175,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":8,"y":0,"w":175,"h":96}, @@ -770,7 +778,7 @@ }, "sprites/blueprints/painter.png": { - "frame": {"x":740,"y":203,"w":192,"h":96}, + "frame": {"x":1121,"y":3,"w":192,"h":96}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":192,"h":96}, @@ -778,7 +786,7 @@ }, "sprites/blueprints/rotater-ccw.png": { - "frame": {"x":1188,"y":303,"w":96,"h":96}, + "frame": {"x":1317,"y":3,"w":96,"h":96}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":96}, @@ -786,7 +794,7 @@ }, "sprites/blueprints/rotater.png": { - "frame": {"x":743,"y":497,"w":96,"h":96}, + "frame": {"x":1322,"y":103,"w":96,"h":96}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":96}, @@ -794,7 +802,7 @@ }, "sprites/blueprints/splitter-compact-inverse.png": { - "frame": {"x":269,"y":665,"w":95,"h":93}, + "frame": {"x":569,"y":599,"w":95,"h":93}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":1,"w":95,"h":93}, @@ -802,7 +810,7 @@ }, "sprites/blueprints/splitter-compact.png": { - "frame": {"x":270,"y":762,"w":93,"h":93}, + "frame": {"x":668,"y":599,"w":93,"h":93}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":1,"w":93,"h":93}, @@ -810,7 +818,7 @@ }, "sprites/blueprints/splitter.png": { - "frame": {"x":3,"y":865,"w":171,"h":96}, + "frame": {"x":549,"y":399,"w":171,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":11,"y":0,"w":171,"h":96}, @@ -818,7 +826,7 @@ }, "sprites/blueprints/stacker.png": { - "frame": {"x":947,"y":103,"w":175,"h":96}, + "frame": {"x":1143,"y":103,"w":175,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":8,"y":0,"w":175,"h":96}, @@ -834,7 +842,7 @@ }, "sprites/blueprints/trash.png": { - "frame": {"x":935,"y":403,"w":96,"h":96}, + "frame": {"x":1287,"y":203,"w":96,"h":96}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":96}, @@ -842,7 +850,7 @@ }, "sprites/blueprints/underground_belt_entry-tier2.png": { - "frame": {"x":838,"y":403,"w":93,"h":84}, + "frame": {"x":374,"y":769,"w":93,"h":84}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":12,"w":93,"h":84}, @@ -850,7 +858,7 @@ }, "sprites/blueprints/underground_belt_entry.png": { - "frame": {"x":369,"y":856,"w":93,"h":75}, + "frame": {"x":669,"y":696,"w":93,"h":75}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":21,"w":93,"h":75}, @@ -858,7 +866,7 @@ }, "sprites/blueprints/underground_belt_exit-tier2.png": { - "frame": {"x":368,"y":690,"w":94,"h":75}, + "frame": {"x":567,"y":769,"w":94,"h":75}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":94,"h":75}, @@ -866,15 +874,63 @@ }, "sprites/blueprints/underground_belt_exit.png": { - "frame": {"x":529,"y":599,"w":93,"h":75}, + "frame": {"x":1003,"y":389,"w":93,"h":75}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":93,"h":75}, "sourceSize": {"w":96,"h":96} }, +"sprites/blueprints/wire_crossings-merger.png": +{ + "frame": {"x":569,"y":696,"w":96,"h":69}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":96,"h":69}, + "sourceSize": {"w":96,"h":96} +}, +"sprites/blueprints/wire_crossings.png": +{ + "frame": {"x":369,"y":599,"w":96,"h":66}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":30,"w":96,"h":66}, + "sourceSize": {"w":96,"h":96} +}, +"sprites/blueprints/wire_left.png": +{ + "frame": {"x":268,"y":957,"w":40,"h":40}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":23,"w":40,"h":40}, + "sourceSize": {"w":63,"h":63} +}, +"sprites/blueprints/wire_right.png": +{ + "frame": {"x":224,"y":957,"w":40,"h":41}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":23,"y":22,"w":40,"h":41}, + "sourceSize": {"w":63,"h":63} +}, +"sprites/blueprints/wire_top.png": +{ + "frame": {"x":719,"y":499,"w":17,"h":63}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":23,"y":0,"w":17,"h":63}, + "sourceSize": {"w":63,"h":63} +}, +"sprites/buildings/advanced_processor.png": +{ + "frame": {"x":740,"y":203,"w":187,"h":179}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":5,"y":6,"w":187,"h":179}, + "sourceSize": {"w":192,"h":192} +}, "sprites/buildings/belt_left.png": { - "frame": {"x":1228,"y":637,"w":57,"h":57}, + "frame": {"x":934,"y":936,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":57,"h":57}, @@ -882,7 +938,7 @@ }, "sprites/buildings/belt_right.png": { - "frame": {"x":1223,"y":698,"w":57,"h":57}, + "frame": {"x":995,"y":935,"w":57,"h":57}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":6,"w":57,"h":57}, @@ -890,7 +946,7 @@ }, "sprites/buildings/belt_top.png": { - "frame": {"x":1234,"y":403,"w":51,"h":63}, + "frame": {"x":962,"y":484,"w":51,"h":63}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":6,"y":0,"w":51,"h":63}, @@ -906,7 +962,7 @@ }, "sprites/buildings/cutter.png": { - "frame": {"x":838,"y":303,"w":171,"h":96}, + "frame": {"x":369,"y":499,"w":171,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":11,"y":0,"w":171,"h":96}, @@ -914,10 +970,10 @@ }, "sprites/buildings/energy_generator.png": { - "frame": {"x":373,"y":399,"w":170,"h":187}, + "frame": {"x":931,"y":203,"w":174,"h":182}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":12,"y":5,"w":170,"h":187}, + "spriteSourceSize": {"x":10,"y":10,"w":174,"h":182}, "sourceSize": {"w":192,"h":192} }, "sprites/buildings/hub.png": @@ -930,7 +986,7 @@ }, "sprites/buildings/miner-chainable.png": { - "frame": {"x":743,"y":398,"w":91,"h":95}, + "frame": {"x":573,"y":848,"w":91,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":91,"h":95}, @@ -938,7 +994,7 @@ }, "sprites/buildings/miner.png": { - "frame": {"x":274,"y":859,"w":91,"h":95}, + "frame": {"x":668,"y":847,"w":91,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":91,"h":95}, @@ -946,7 +1002,7 @@ }, "sprites/buildings/mixer.png": { - "frame": {"x":936,"y":203,"w":174,"h":96}, + "frame": {"x":1109,"y":203,"w":174,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":174,"h":96}, @@ -962,7 +1018,7 @@ }, "sprites/buildings/painter-mirrored.png": { - "frame": {"x":547,"y":399,"w":192,"h":96}, + "frame": {"x":947,"y":103,"w":192,"h":96}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":192,"h":96}, @@ -978,7 +1034,7 @@ }, "sprites/buildings/painter.png": { - "frame": {"x":547,"y":499,"w":192,"h":96}, + "frame": {"x":182,"y":857,"w":192,"h":96}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":192,"h":96}, @@ -986,7 +1042,7 @@ }, "sprites/buildings/rotater-ccw.png": { - "frame": {"x":1135,"y":403,"w":95,"h":96}, + "frame": {"x":374,"y":669,"w":95,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":95,"h":96}, @@ -994,7 +1050,7 @@ }, "sprites/buildings/rotater.png": { - "frame": {"x":373,"y":590,"w":95,"h":96}, + "frame": {"x":378,"y":857,"w":95,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":95,"h":96}, @@ -1002,7 +1058,7 @@ }, "sprites/buildings/splitter-compact-inverse.png": { - "frame": {"x":740,"y":303,"w":94,"h":91}, + "frame": {"x":740,"y":386,"w":94,"h":91}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":94,"h":91}, @@ -1010,7 +1066,7 @@ }, "sprites/buildings/splitter-compact.png": { - "frame": {"x":173,"y":769,"w":93,"h":91}, + "frame": {"x":906,"y":389,"w":93,"h":91}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":2,"w":93,"h":91}, @@ -1018,7 +1074,7 @@ }, "sprites/buildings/splitter.png": { - "frame": {"x":1013,"y":303,"w":171,"h":96}, + "frame": {"x":544,"y":499,"w":171,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":11,"y":0,"w":171,"h":96}, @@ -1026,7 +1082,7 @@ }, "sprites/buildings/stacker.png": { - "frame": {"x":1114,"y":203,"w":174,"h":96}, + "frame": {"x":1109,"y":303,"w":174,"h":96}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":174,"h":96}, @@ -1034,7 +1090,7 @@ }, "sprites/buildings/trash-storage.png": { - "frame": {"x":3,"y":669,"w":166,"h":192}, + "frame": {"x":199,"y":474,"w":166,"h":192}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":14,"y":0,"w":166,"h":192}, @@ -1042,7 +1098,7 @@ }, "sprites/buildings/trash.png": { - "frame": {"x":1035,"y":403,"w":96,"h":96}, + "frame": {"x":1287,"y":303,"w":96,"h":96}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":96,"h":96}, @@ -1050,7 +1106,7 @@ }, "sprites/buildings/underground_belt_entry-tier2.png": { - "frame": {"x":367,"y":769,"w":92,"h":83}, + "frame": {"x":471,"y":769,"w":92,"h":83}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":13,"w":92,"h":83}, @@ -1058,7 +1114,7 @@ }, "sprites/buildings/underground_belt_entry.png": { - "frame": {"x":369,"y":935,"w":92,"h":74}, + "frame": {"x":1100,"y":403,"w":92,"h":74}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":22,"w":92,"h":74}, @@ -1066,7 +1122,7 @@ }, "sprites/buildings/underground_belt_exit-tier2.png": { - "frame": {"x":465,"y":935,"w":92,"h":74}, + "frame": {"x":1196,"y":403,"w":92,"h":74}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":92,"h":74}, @@ -1074,15 +1130,55 @@ }, "sprites/buildings/underground_belt_exit.png": { - "frame": {"x":626,"y":599,"w":92,"h":74}, + "frame": {"x":1292,"y":403,"w":92,"h":74}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":92,"h":74}, "sourceSize": {"w":96,"h":96} }, +"sprites/buildings/wire_crossings-merger.png": +{ + "frame": {"x":665,"y":775,"w":96,"h":68}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":96,"h":68}, + "sourceSize": {"w":96,"h":96} +}, +"sprites/buildings/wire_crossings.png": +{ + "frame": {"x":469,"y":599,"w":96,"h":66}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":30,"w":96,"h":66}, + "sourceSize": {"w":96,"h":96} +}, +"sprites/buildings/wire_left.png": +{ + "frame": {"x":312,"y":957,"w":40,"h":40}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":23,"w":40,"h":40}, + "sourceSize": {"w":63,"h":63} +}, +"sprites/buildings/wire_right.png": +{ + "frame": {"x":356,"y":957,"w":40,"h":40}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":23,"y":23,"w":40,"h":40}, + "sourceSize": {"w":63,"h":63} +}, +"sprites/buildings/wire_top.png": +{ + "frame": {"x":1046,"y":801,"w":17,"h":63}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":23,"y":0,"w":17,"h":63}, + "sourceSize": {"w":63,"h":63} +}, "sprites/debug/acceptor_slot.png": { - "frame": {"x":142,"y":965,"w":26,"h":32}, + "frame": {"x":1395,"y":664,"w":26,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":26,"h":32}, @@ -1090,7 +1186,7 @@ }, "sprites/debug/ejector_slot.png": { - "frame": {"x":1198,"y":631,"w":26,"h":32}, + "frame": {"x":400,"y":957,"w":26,"h":32}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":26,"h":32}, @@ -1098,7 +1194,7 @@ }, "sprites/map_overview/belt_forward.png": { - "frame": {"x":1284,"y":698,"w":14,"h":16}, + "frame": {"x":1417,"y":39,"w":14,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":14,"h":16}, @@ -1106,7 +1202,7 @@ }, "sprites/map_overview/belt_left.png": { - "frame": {"x":744,"y":994,"w":15,"h":15}, + "frame": {"x":1082,"y":935,"w":15,"h":15}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":1,"w":15,"h":15}, @@ -1114,7 +1210,7 @@ }, "sprites/map_overview/belt_right.png": { - "frame": {"x":763,"y":994,"w":15,"h":15}, + "frame": {"x":1082,"y":954,"w":15,"h":15}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":1,"w":15,"h":15}, @@ -1122,15 +1218,23 @@ }, "sprites/misc/deletion_marker.png": { - "frame": {"x":96,"y":965,"w":42,"h":42}, + "frame": {"x":178,"y":957,"w":42,"h":42}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":3,"w":42,"h":42}, "sourceSize": {"w":48,"h":48} }, +"sprites/misc/energy_generator_overlay.png": +{ + "frame": {"x":96,"y":954,"w":78,"h":30}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":91,"y":144,"w":78,"h":30}, + "sourceSize": {"w":192,"h":192} +}, "sprites/misc/hub_direction_indicator.png": { - "frame": {"x":942,"y":826,"w":16,"h":16}, + "frame": {"x":1421,"y":369,"w":16,"h":16}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":16,"h":16}, @@ -1138,7 +1242,7 @@ }, "sprites/misc/lock_direction_indicator.png": { - "frame": {"x":1234,"y":470,"w":24,"h":16}, + "frame": {"x":1406,"y":873,"w":24,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":4,"w":24,"h":16}, @@ -1146,7 +1250,7 @@ }, "sprites/misc/slot_bad_arrow.png": { - "frame": {"x":96,"y":965,"w":42,"h":42}, + "frame": {"x":178,"y":957,"w":42,"h":42}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":3,"w":42,"h":42}, @@ -1154,7 +1258,7 @@ }, "sprites/misc/slot_good_arrow.png": { - "frame": {"x":518,"y":800,"w":42,"h":48}, + "frame": {"x":1387,"y":317,"w":42,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":3,"y":0,"w":42,"h":48}, @@ -1162,7 +1266,7 @@ }, "sprites/misc/storage_overlay.png": { - "frame": {"x":3,"y":965,"w":89,"h":44}, + "frame": {"x":3,"y":954,"w":89,"h":44}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":1,"w":89,"h":44}, @@ -1170,19 +1274,115 @@ }, "sprites/misc/waypoint.png": { - "frame": {"x":1284,"y":718,"w":14,"h":16}, + "frame": {"x":1406,"y":893,"w":14,"h":16}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":14,"h":16}, "sourceSize": {"w":16,"h":16} +}, +"sprites/misc/wires_overlay_tile.png": +{ + "frame": {"x":838,"y":386,"w":64,"h":64}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":64,"h":64}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/battery_empty.png": +{ + "frame": {"x":1417,"y":3,"w":20,"h":32}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":6,"y":0,"w":20,"h":32}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/battery_full.png": +{ + "frame": {"x":1395,"y":700,"w":30,"h":21}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":6,"w":30,"h":21}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/battery_low.png": +{ + "frame": {"x":1387,"y":369,"w":30,"h":21}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":6,"w":30,"h":21}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/battery_medium.png": +{ + "frame": {"x":430,"y":957,"w":30,"h":21}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":6,"w":30,"h":21}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/negative_energy.png": +{ + "frame": {"x":1406,"y":847,"w":22,"h":22}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":5,"y":5,"w":22,"h":22}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/pin_negative_accept.png": +{ + "frame": {"x":1387,"y":203,"w":38,"h":53}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":38,"h":53}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/pin_negative_eject.png": +{ + "frame": {"x":795,"y":481,"w":33,"h":51}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":15,"y":0,"w":33,"h":51}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/pin_positive_accept.png": +{ + "frame": {"x":795,"y":536,"w":33,"h":51}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":15,"y":0,"w":33,"h":51}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/pin_positive_eject.png": +{ + "frame": {"x":1387,"y":260,"w":38,"h":53}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":13,"y":0,"w":38,"h":53}, + "sourceSize": {"w":64,"h":64} +}, +"sprites/wires/positive_energy.png": +{ + "frame": {"x":1056,"y":935,"w":22,"h":22}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":5,"y":5,"w":22,"h":22}, + "sourceSize": {"w":32,"h":32} +}, +"sprites/wires/waste_piled.png": +{ + "frame": {"x":719,"y":566,"w":30,"h":29}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":1,"y":1,"w":30,"h":29}, + "sourceSize": {"w":32,"h":32} }}, "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "1.0", "image": "atlas0_50.png", "format": "RGBA8888", - "size": {"w":1301,"h":1012}, + "size": {"w":1440,"h":1007}, "scale": "0.5", - "smartupdate": "$TexturePacker:SmartUpdate:dc34796c028235bbc69e5b8d854254ca:2765d0b8c8bcbb7a4aaaf1104853ad41:8778749683c68f53155587e6d831729a$" + "smartupdate": "$TexturePacker:SmartUpdate:4e5fb3bd7f1e5423e4fcea2215debe11:0c5d091d0b928944c68553dcc592c801:f159918d23e5952766c6d23ab52278c6$" } } diff --git a/res_built/atlas/atlas0_50.png b/res_built/atlas/atlas0_50.png index 29116b1b..dac64c2a 100644 Binary files a/res_built/atlas/atlas0_50.png and b/res_built/atlas/atlas0_50.png differ diff --git a/res_built/atlas/atlas0_75.json b/res_built/atlas/atlas0_75.json index 147b55c9..b9dac39c 100644 --- a/res_built/atlas/atlas0_75.json +++ b/res_built/atlas/atlas0_75.json @@ -2,7 +2,7 @@ "sprites/belt/forward_0.png": { - "frame": {"x":86,"y":1431,"w":77,"h":95}, + "frame": {"x":1907,"y":299,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -10,7 +10,7 @@ }, "sprites/belt/forward_1.png": { - "frame": {"x":167,"y":1431,"w":77,"h":95}, + "frame": {"x":1024,"y":887,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -18,7 +18,7 @@ }, "sprites/belt/forward_2.png": { - "frame": {"x":1519,"y":1282,"w":77,"h":95}, + "frame": {"x":1287,"y":1076,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -26,7 +26,7 @@ }, "sprites/belt/forward_3.png": { - "frame": {"x":960,"y":3,"w":77,"h":95}, + "frame": {"x":1374,"y":1167,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -34,7 +34,7 @@ }, "sprites/belt/forward_4.png": { - "frame": {"x":1041,"y":3,"w":77,"h":95}, + "frame": {"x":1392,"y":1266,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -42,7 +42,7 @@ }, "sprites/belt/forward_5.png": { - "frame": {"x":774,"y":548,"w":77,"h":95}, + "frame": {"x":1423,"y":1455,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -50,7 +50,7 @@ }, "sprites/belt/forward_6.png": { - "frame": {"x":815,"y":254,"w":77,"h":95}, + "frame": {"x":1449,"y":1032,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -58,7 +58,7 @@ }, "sprites/belt/forward_7.png": { - "frame": {"x":815,"y":353,"w":77,"h":95}, + "frame": {"x":1455,"y":1131,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -66,7 +66,7 @@ }, "sprites/belt/forward_8.png": { - "frame": {"x":855,"y":542,"w":77,"h":95}, + "frame": {"x":1473,"y":1230,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -74,7 +74,7 @@ }, "sprites/belt/forward_9.png": { - "frame": {"x":896,"y":254,"w":77,"h":95}, + "frame": {"x":1484,"y":1329,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -82,7 +82,7 @@ }, "sprites/belt/forward_10.png": { - "frame": {"x":248,"y":1431,"w":77,"h":95}, + "frame": {"x":1105,"y":880,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -90,7 +90,7 @@ }, "sprites/belt/forward_11.png": { - "frame": {"x":329,"y":1428,"w":77,"h":95}, + "frame": {"x":1122,"y":979,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -98,7 +98,7 @@ }, "sprites/belt/forward_12.png": { - "frame": {"x":410,"y":1428,"w":77,"h":95}, + "frame": {"x":1125,"y":1078,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -106,7 +106,7 @@ }, "sprites/belt/forward_13.png": { - "frame": {"x":491,"y":1428,"w":77,"h":95}, + "frame": {"x":1215,"y":878,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -114,7 +114,7 @@ }, "sprites/belt/forward_14.png": { - "frame": {"x":572,"y":1428,"w":77,"h":95}, + "frame": {"x":1131,"y":1177,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -122,7 +122,7 @@ }, "sprites/belt/forward_15.png": { - "frame": {"x":653,"y":1426,"w":77,"h":95}, + "frame": {"x":1203,"y":979,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -130,7 +130,7 @@ }, "sprites/belt/forward_16.png": { - "frame": {"x":734,"y":1426,"w":77,"h":95}, + "frame": {"x":1206,"y":1078,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -138,7 +138,7 @@ }, "sprites/belt/forward_17.png": { - "frame": {"x":815,"y":1426,"w":77,"h":95}, + "frame": {"x":1212,"y":1177,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -146,7 +146,7 @@ }, "sprites/belt/forward_18.png": { - "frame": {"x":1438,"y":1284,"w":77,"h":95}, + "frame": {"x":1932,"y":594,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -154,7 +154,7 @@ }, "sprites/belt/forward_19.png": { - "frame": {"x":1811,"y":806,"w":77,"h":95}, + "frame": {"x":1284,"y":977,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -162,7 +162,7 @@ }, "sprites/belt/forward_20.png": { - "frame": {"x":1600,"y":1282,"w":77,"h":95}, + "frame": {"x":1293,"y":1175,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -170,7 +170,7 @@ }, "sprites/belt/forward_21.png": { - "frame": {"x":1681,"y":1282,"w":77,"h":95}, + "frame": {"x":1311,"y":1274,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -178,7 +178,7 @@ }, "sprites/belt/forward_22.png": { - "frame": {"x":1755,"y":1406,"w":77,"h":95}, + "frame": {"x":1099,"y":1463,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -186,7 +186,7 @@ }, "sprites/belt/forward_23.png": { - "frame": {"x":555,"y":3,"w":77,"h":95}, + "frame": {"x":1180,"y":1463,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -194,7 +194,7 @@ }, "sprites/belt/forward_24.png": { - "frame": {"x":636,"y":3,"w":77,"h":95}, + "frame": {"x":1261,"y":1463,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -202,7 +202,7 @@ }, "sprites/belt/forward_25.png": { - "frame": {"x":717,"y":3,"w":77,"h":95}, + "frame": {"x":1342,"y":1463,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -210,7 +210,7 @@ }, "sprites/belt/forward_26.png": { - "frame": {"x":798,"y":3,"w":77,"h":95}, + "frame": {"x":1942,"y":398,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -218,7 +218,7 @@ }, "sprites/belt/forward_27.png": { - "frame": {"x":879,"y":3,"w":77,"h":95}, + "frame": {"x":1368,"y":1068,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -226,7 +226,7 @@ }, "sprites/belt/left_0.png": { - "frame": {"x":1707,"y":1102,"w":86,"h":86}, + "frame": {"x":786,"y":887,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -234,7 +234,7 @@ }, "sprites/belt/left_1.png": { - "frame": {"x":1797,"y":1136,"w":86,"h":86}, + "frame": {"x":1107,"y":691,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -242,7 +242,7 @@ }, "sprites/belt/left_2.png": { - "frame": {"x":995,"y":434,"w":86,"h":86}, + "frame": {"x":1124,"y":1366,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -250,7 +250,7 @@ }, "sprites/belt/left_3.png": { - "frame": {"x":1212,"y":3,"w":86,"h":86}, + "frame": {"x":1893,"y":824,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -258,7 +258,7 @@ }, "sprites/belt/left_4.png": { - "frame": {"x":1166,"y":287,"w":86,"h":86}, + "frame": {"x":1803,"y":914,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -266,7 +266,7 @@ }, "sprites/belt/left_5.png": { - "frame": {"x":1247,"y":197,"w":86,"h":86}, + "frame": {"x":1893,"y":914,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -274,7 +274,7 @@ }, "sprites/belt/left_6.png": { - "frame": {"x":1287,"y":107,"w":86,"h":86}, + "frame": {"x":1365,"y":824,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -282,7 +282,7 @@ }, "sprites/belt/left_7.png": { - "frame": {"x":1302,"y":3,"w":86,"h":86}, + "frame": {"x":1365,"y":914,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -290,7 +290,7 @@ }, "sprites/belt/left_8.png": { - "frame": {"x":1175,"y":377,"w":86,"h":86}, + "frame": {"x":1394,"y":1365,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -298,7 +298,7 @@ }, "sprites/belt/left_9.png": { - "frame": {"x":1256,"y":287,"w":86,"h":86}, + "frame": {"x":1519,"y":912,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -306,7 +306,7 @@ }, "sprites/belt/left_10.png": { - "frame": {"x":1707,"y":1192,"w":86,"h":86}, + "frame": {"x":1197,"y":698,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -314,7 +314,7 @@ }, "sprites/belt/left_11.png": { - "frame": {"x":1797,"y":1226,"w":86,"h":86}, + "frame": {"x":1189,"y":788,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -322,7 +322,7 @@ }, "sprites/belt/left_12.png": { - "frame": {"x":1762,"y":1316,"w":86,"h":86}, + "frame": {"x":1353,"y":734,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -330,7 +330,7 @@ }, "sprites/belt/left_13.png": { - "frame": {"x":815,"y":452,"w":86,"h":86}, + "frame": {"x":1443,"y":734,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -338,7 +338,7 @@ }, "sprites/belt/left_14.png": { - "frame": {"x":896,"y":353,"w":86,"h":86}, + "frame": {"x":1533,"y":732,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -346,7 +346,7 @@ }, "sprites/belt/left_15.png": { - "frame": {"x":977,"y":254,"w":86,"h":86}, + "frame": {"x":1623,"y":736,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -354,7 +354,7 @@ }, "sprites/belt/left_16.png": { - "frame": {"x":905,"y":443,"w":86,"h":86}, + "frame": {"x":1713,"y":736,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -362,7 +362,7 @@ }, "sprites/belt/left_17.png": { - "frame": {"x":986,"y":344,"w":86,"h":86}, + "frame": {"x":1803,"y":734,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -370,7 +370,7 @@ }, "sprites/belt/left_18.png": { - "frame": {"x":1067,"y":254,"w":86,"h":86}, + "frame": {"x":1893,"y":734,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -378,7 +378,7 @@ }, "sprites/belt/left_19.png": { - "frame": {"x":936,"y":533,"w":86,"h":86}, + "frame": {"x":1131,"y":1276,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -386,7 +386,7 @@ }, "sprites/belt/left_20.png": { - "frame": {"x":1076,"y":344,"w":86,"h":86}, + "frame": {"x":1221,"y":1276,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -394,7 +394,7 @@ }, "sprites/belt/left_21.png": { - "frame": {"x":1026,"y":524,"w":86,"h":86}, + "frame": {"x":1214,"y":1366,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -402,7 +402,7 @@ }, "sprites/belt/left_22.png": { - "frame": {"x":1085,"y":434,"w":86,"h":86}, + "frame": {"x":1304,"y":1373,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -410,7 +410,7 @@ }, "sprites/belt/left_23.png": { - "frame": {"x":1116,"y":524,"w":86,"h":86}, + "frame": {"x":1942,"y":497,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -418,7 +418,7 @@ }, "sprites/belt/left_24.png": { - "frame": {"x":1107,"y":107,"w":86,"h":86}, + "frame": {"x":1533,"y":822,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -426,7 +426,7 @@ }, "sprites/belt/left_25.png": { - "frame": {"x":1122,"y":3,"w":86,"h":86}, + "frame": {"x":1623,"y":826,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -434,7 +434,7 @@ }, "sprites/belt/left_26.png": { - "frame": {"x":1157,"y":197,"w":86,"h":86}, + "frame": {"x":1713,"y":826,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -442,7 +442,7 @@ }, "sprites/belt/left_27.png": { - "frame": {"x":1197,"y":107,"w":86,"h":86}, + "frame": {"x":1803,"y":824,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -450,7 +450,7 @@ }, "sprites/belt/right_0.png": { - "frame": {"x":1337,"y":197,"w":86,"h":86}, + "frame": {"x":1609,"y":916,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -458,7 +458,7 @@ }, "sprites/belt/right_1.png": { - "frame": {"x":1377,"y":107,"w":86,"h":86}, + "frame": {"x":1699,"y":916,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -466,7 +466,7 @@ }, "sprites/belt/right_2.png": { - "frame": {"x":1647,"y":107,"w":86,"h":86}, + "frame": {"x":1655,"y":1276,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -474,7 +474,7 @@ }, "sprites/belt/right_3.png": { - "frame": {"x":1386,"y":543,"w":86,"h":86}, + "frame": {"x":1824,"y":1184,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -482,7 +482,7 @@ }, "sprites/belt/right_4.png": { - "frame": {"x":1476,"y":453,"w":86,"h":86}, + "frame": {"x":1896,"y":1094,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -490,7 +490,7 @@ }, "sprites/belt/right_5.png": { - "frame": {"x":1476,"y":543,"w":86,"h":86}, + "frame": {"x":1835,"y":1274,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -498,7 +498,7 @@ }, "sprites/belt/right_6.png": { - "frame": {"x":1566,"y":377,"w":86,"h":86}, + "frame": {"x":1774,"y":1364,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -506,7 +506,7 @@ }, "sprites/belt/right_7.png": { - "frame": {"x":1656,"y":377,"w":86,"h":86}, + "frame": {"x":1774,"y":1454,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -514,7 +514,7 @@ }, "sprites/belt/right_8.png": { - "frame": {"x":1566,"y":467,"w":86,"h":86}, + "frame": {"x":1914,"y":1184,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -522,7 +522,7 @@ }, "sprites/belt/right_9.png": { - "frame": {"x":1656,"y":467,"w":86,"h":86}, + "frame": {"x":1925,"y":1274,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -530,7 +530,7 @@ }, "sprites/belt/right_10.png": { - "frame": {"x":1392,"y":3,"w":86,"h":86}, + "frame": {"x":1504,"y":1428,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -538,7 +538,7 @@ }, "sprites/belt/right_11.png": { - "frame": {"x":1206,"y":467,"w":86,"h":86}, + "frame": {"x":1789,"y":1004,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -546,7 +546,7 @@ }, "sprites/belt/right_12.png": { - "frame": {"x":1265,"y":377,"w":86,"h":86}, + "frame": {"x":1879,"y":1004,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -554,7 +554,7 @@ }, "sprites/belt/right_13.png": { - "frame": {"x":1346,"y":287,"w":86,"h":86}, + "frame": {"x":1530,"y":1006,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -562,7 +562,7 @@ }, "sprites/belt/right_14.png": { - "frame": {"x":1427,"y":197,"w":86,"h":86}, + "frame": {"x":1620,"y":1006,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -570,7 +570,7 @@ }, "sprites/belt/right_15.png": { - "frame": {"x":1467,"y":107,"w":86,"h":86}, + "frame": {"x":1536,"y":1096,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -578,7 +578,7 @@ }, "sprites/belt/right_16.png": { - "frame": {"x":1206,"y":557,"w":86,"h":86}, + "frame": {"x":1626,"y":1096,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -586,7 +586,7 @@ }, "sprites/belt/right_17.png": { - "frame": {"x":1482,"y":3,"w":86,"h":86}, + "frame": {"x":1554,"y":1186,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -594,7 +594,7 @@ }, "sprites/belt/right_18.png": { - "frame": {"x":1572,"y":3,"w":86,"h":86}, + "frame": {"x":1644,"y":1186,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -602,7 +602,7 @@ }, "sprites/belt/right_19.png": { - "frame": {"x":1557,"y":93,"w":86,"h":86}, + "frame": {"x":1565,"y":1276,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -610,7 +610,7 @@ }, "sprites/belt/right_20.png": { - "frame": {"x":1557,"y":183,"w":86,"h":86}, + "frame": {"x":1594,"y":1366,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -618,7 +618,7 @@ }, "sprites/belt/right_21.png": { - "frame": {"x":1647,"y":197,"w":86,"h":86}, + "frame": {"x":1594,"y":1456,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -626,7 +626,7 @@ }, "sprites/belt/right_22.png": { - "frame": {"x":1517,"y":273,"w":86,"h":86}, + "frame": {"x":1684,"y":1366,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -634,7 +634,7 @@ }, "sprites/belt/right_23.png": { - "frame": {"x":1607,"y":287,"w":86,"h":86}, + "frame": {"x":1684,"y":1456,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -642,7 +642,7 @@ }, "sprites/belt/right_24.png": { - "frame": {"x":1436,"y":363,"w":86,"h":86}, + "frame": {"x":1716,"y":1094,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -650,7 +650,7 @@ }, "sprites/belt/right_25.png": { - "frame": {"x":1296,"y":467,"w":86,"h":86}, + "frame": {"x":1806,"y":1094,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -658,7 +658,7 @@ }, "sprites/belt/right_26.png": { - "frame": {"x":1296,"y":557,"w":86,"h":86}, + "frame": {"x":1734,"y":1184,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -666,15 +666,23 @@ }, "sprites/belt/right_27.png": { - "frame": {"x":1386,"y":453,"w":86,"h":86}, + "frame": {"x":1745,"y":1274,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, "sourceSize": {"w":95,"h":95} }, +"sprites/blueprints/advanced_processor.png": +{ + "frame": {"x":3,"y":994,"w":281,"h":270}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":7,"y":8,"w":281,"h":270}, + "sourceSize": {"w":288,"h":288} +}, "sprites/blueprints/belt_left.png": { - "frame": {"x":1803,"y":954,"w":87,"h":87}, + "frame": {"x":695,"y":886,"w":87,"h":87}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":8,"w":87,"h":87}, @@ -682,7 +690,7 @@ }, "sprites/blueprints/belt_right.png": { - "frame": {"x":1803,"y":1045,"w":87,"h":87}, + "frame": {"x":695,"y":1456,"w":87,"h":87}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":8,"y":8,"w":87,"h":87}, @@ -690,7 +698,7 @@ }, "sprites/blueprints/belt_top.png": { - "frame": {"x":3,"y":1431,"w":79,"h":95}, + "frame": {"x":1077,"y":781,"w":79,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":8,"y":0,"w":79,"h":95}, @@ -698,7 +706,7 @@ }, "sprites/blueprints/cutter-quad.png": { - "frame": {"x":547,"y":988,"w":548,"h":144}, + "frame": {"x":3,"y":556,"w":548,"h":144}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":17,"y":0,"w":548,"h":144}, @@ -706,7 +714,7 @@ }, "sprites/blueprints/cutter.png": { - "frame": {"x":1111,"y":807,"w":256,"h":144}, + "frame": {"x":1411,"y":150,"w":256,"h":144}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":17,"y":0,"w":256,"h":144}, @@ -714,15 +722,15 @@ }, "sprites/blueprints/energy_generator.png": { - "frame": {"x":257,"y":556,"w":255,"h":280}, + "frame": {"x":288,"y":996,"w":262,"h":274}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":18,"y":8,"w":255,"h":280}, + "spriteSourceSize": {"x":14,"y":14,"w":262,"h":274}, "sourceSize": {"w":288,"h":288} }, "sprites/blueprints/miner-chainable.png": { - "frame": {"x":1755,"y":3,"w":136,"h":143}, + "frame": {"x":701,"y":977,"w":136,"h":143}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":136,"h":143}, @@ -730,7 +738,7 @@ }, "sprites/blueprints/miner.png": { - "frame": {"x":1755,"y":150,"w":136,"h":143}, + "frame": {"x":701,"y":1124,"w":136,"h":143}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":136,"h":143}, @@ -738,7 +746,7 @@ }, "sprites/blueprints/mixer.png": { - "frame": {"x":774,"y":659,"w":261,"h":144}, + "frame": {"x":547,"y":738,"w":261,"h":144}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":261,"h":144}, @@ -746,7 +754,7 @@ }, "sprites/blueprints/painter-double.png": { - "frame": {"x":3,"y":1140,"w":288,"h":287}, + "frame": {"x":555,"y":299,"w":288,"h":287}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":288,"h":287}, @@ -754,7 +762,7 @@ }, "sprites/blueprints/painter-mirrored.png": { - "frame": {"x":859,"y":1136,"w":288,"h":144}, + "frame": {"x":1119,"y":150,"w":288,"h":144}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":288,"h":144}, @@ -762,7 +770,7 @@ }, "sprites/blueprints/painter-quad.png": { - "frame": {"x":295,"y":1138,"w":560,"h":144}, + "frame": {"x":555,"y":3,"w":560,"h":144}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":560,"h":144}, @@ -770,7 +778,7 @@ }, "sprites/blueprints/painter.png": { - "frame": {"x":1099,"y":988,"w":288,"h":144}, + "frame": {"x":1671,"y":3,"w":288,"h":144}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":288,"h":144}, @@ -778,7 +786,7 @@ }, "sprites/blueprints/rotater-ccw.png": { - "frame": {"x":1519,"y":807,"w":143,"h":144}, + "frame": {"x":554,"y":993,"w":143,"h":144}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":143,"h":144}, @@ -786,7 +794,7 @@ }, "sprites/blueprints/rotater.png": { - "frame": {"x":1564,"y":659,"w":143,"h":144}, + "frame": {"x":554,"y":1141,"w":143,"h":144}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":1,"y":0,"w":143,"h":144}, @@ -794,7 +802,7 @@ }, "sprites/blueprints/splitter-compact-inverse.png": { - "frame": {"x":295,"y":1286,"w":142,"h":138}, + "frame": {"x":1355,"y":592,"w":142,"h":138}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":142,"h":138}, @@ -802,7 +810,7 @@ }, "sprites/blueprints/splitter-compact.png": { - "frame": {"x":441,"y":1286,"w":139,"h":138}, + "frame": {"x":1646,"y":594,"w":139,"h":138}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":2,"w":139,"h":138}, @@ -810,7 +818,7 @@ }, "sprites/blueprints/splitter.png": { - "frame": {"x":1304,"y":659,"w":256,"h":144}, + "frame": {"x":847,"y":591,"w":256,"h":144}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":17,"y":0,"w":256,"h":144}, @@ -818,7 +826,7 @@ }, "sprites/blueprints/stacker.png": { - "frame": {"x":1039,"y":659,"w":261,"h":144}, + "frame": {"x":812,"y":739,"w":261,"h":144}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":13,"y":0,"w":261,"h":144}, @@ -826,7 +834,7 @@ }, "sprites/blueprints/trash-storage.png": { - "frame": {"x":3,"y":556,"w":250,"h":288}, + "frame": {"x":847,"y":299,"w":250,"h":288}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":21,"y":0,"w":250,"h":288}, @@ -834,7 +842,7 @@ }, "sprites/blueprints/trash.png": { - "frame": {"x":1371,"y":807,"w":144,"h":144}, + "frame": {"x":1646,"y":446,"w":144,"h":144}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":144,"h":144}, @@ -842,7 +850,7 @@ }, "sprites/blueprints/underground_belt_entry-tier2.png": { - "frame": {"x":872,"y":1284,"w":138,"h":125}, + "frame": {"x":841,"y":1136,"w":138,"h":125}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":4,"y":19,"w":138,"h":125}, @@ -850,7 +858,7 @@ }, "sprites/blueprints/underground_belt_entry.png": { - "frame": {"x":1039,"y":1412,"w":138,"h":112}, + "frame": {"x":983,"y":1118,"w":138,"h":112}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":4,"y":32,"w":138,"h":112}, @@ -858,7 +866,7 @@ }, "sprites/blueprints/underground_belt_exit-tier2.png": { - "frame": {"x":896,"y":1413,"w":139,"h":112}, + "frame": {"x":552,"y":1436,"w":139,"h":112}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":4,"y":0,"w":139,"h":112}, @@ -866,15 +874,63 @@ }, "sprites/blueprints/underground_belt_exit.png": { - "frame": {"x":1155,"y":1284,"w":138,"h":112}, + "frame": {"x":841,"y":1265,"w":138,"h":112}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":4,"y":0,"w":138,"h":112}, "sourceSize": {"w":144,"h":144} }, +"sprites/blueprints/wire_crossings-merger.png": +{ + "frame": {"x":547,"y":886,"w":144,"h":103}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":144,"h":103}, + "sourceSize": {"w":144,"h":144} +}, +"sprites/blueprints/wire_crossings.png": +{ + "frame": {"x":876,"y":887,"w":144,"h":99}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":45,"w":144,"h":99}, + "sourceSize": {"w":144,"h":144} +}, +"sprites/blueprints/wire_left.png": +{ + "frame": {"x":1365,"y":1004,"w":60,"h":60}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":35,"w":60,"h":60}, + "sourceSize": {"w":95,"h":95} +}, +"sprites/blueprints/wire_right.png": +{ + "frame": {"x":852,"y":1496,"w":60,"h":61}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":35,"y":34,"w":60,"h":61}, + "sourceSize": {"w":95,"h":95} +}, +"sprites/blueprints/wire_top.png": +{ + "frame": {"x":1160,"y":781,"w":25,"h":95}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":35,"y":0,"w":25,"h":95}, + "sourceSize": {"w":95,"h":95} +}, +"sprites/buildings/advanced_processor.png": +{ + "frame": {"x":3,"y":1268,"w":280,"h":268}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":8,"y":9,"w":280,"h":268}, + "sourceSize": {"w":288,"h":288} +}, "sprites/buildings/belt_left.png": { - "frame": {"x":1566,"y":557,"w":86,"h":86}, + "frame": {"x":1864,"y":1364,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":9,"w":86,"h":86}, @@ -882,7 +938,7 @@ }, "sprites/buildings/belt_right.png": { - "frame": {"x":1656,"y":557,"w":86,"h":86}, + "frame": {"x":1864,"y":1454,"w":86,"h":86}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":9,"w":86,"h":86}, @@ -890,7 +946,7 @@ }, "sprites/buildings/belt_top.png": { - "frame": {"x":86,"y":1431,"w":77,"h":95}, + "frame": {"x":1907,"y":299,"w":77,"h":95}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":9,"y":0,"w":77,"h":95}, @@ -898,7 +954,7 @@ }, "sprites/buildings/cutter-quad.png": { - "frame": {"x":555,"y":107,"w":548,"h":143}, + "frame": {"x":1119,"y":3,"w":548,"h":143}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":17,"y":0,"w":548,"h":143}, @@ -906,7 +962,7 @@ }, "sprites/buildings/cutter.png": { - "frame": {"x":555,"y":254,"w":256,"h":143}, + "frame": {"x":1647,"y":299,"w":256,"h":143}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":17,"y":0,"w":256,"h":143}, @@ -914,10 +970,10 @@ }, "sprites/buildings/energy_generator.png": { - "frame": {"x":516,"y":556,"w":254,"h":280}, + "frame": {"x":287,"y":1274,"w":261,"h":273}, "rotated": false, "trimmed": true, - "spriteSourceSize": {"x":19,"y":8,"w":254,"h":280}, + "spriteSourceSize": {"x":15,"y":15,"w":261,"h":273}, "sourceSize": {"w":288,"h":288} }, "sprites/buildings/hub.png": @@ -930,7 +986,7 @@ }, "sprites/buildings/miner-chainable.png": { - "frame": {"x":1755,"y":297,"w":136,"h":142}, + "frame": {"x":1101,"y":445,"w":136,"h":142}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":136,"h":142}, @@ -938,7 +994,7 @@ }, "sprites/buildings/miner.png": { - "frame": {"x":1755,"y":443,"w":136,"h":142}, + "frame": {"x":841,"y":990,"w":136,"h":142}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":136,"h":142}, @@ -946,7 +1002,7 @@ }, "sprites/buildings/mixer.png": { - "frame": {"x":1443,"y":1103,"w":260,"h":143}, + "frame": {"x":1119,"y":298,"w":260,"h":143}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":14,"y":0,"w":260,"h":143}, @@ -954,7 +1010,7 @@ }, "sprites/buildings/painter-double.png": { - "frame": {"x":255,"y":848,"w":288,"h":286}, + "frame": {"x":3,"y":704,"w":288,"h":286}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":0,"w":288,"h":286}, @@ -962,7 +1018,7 @@ }, "sprites/buildings/painter-mirrored.png": { - "frame": {"x":1151,"y":1136,"w":288,"h":144}, + "frame": {"x":1671,"y":151,"w":288,"h":144}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":288,"h":144}, @@ -970,7 +1026,7 @@ }, "sprites/buildings/painter-quad.png": { - "frame": {"x":547,"y":840,"w":560,"h":144}, + "frame": {"x":555,"y":151,"w":560,"h":144}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":560,"h":144}, @@ -978,7 +1034,7 @@ }, "sprites/buildings/painter.png": { - "frame": {"x":1463,"y":1383,"w":288,"h":144}, + "frame": {"x":555,"y":590,"w":288,"h":144}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":288,"h":144}, @@ -986,7 +1042,7 @@ }, "sprites/buildings/rotater-ccw.png": { - "frame": {"x":1666,"y":807,"w":141,"h":143}, + "frame": {"x":1501,"y":445,"w":141,"h":143}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":141,"h":143}, @@ -994,7 +1050,7 @@ }, "sprites/buildings/rotater.png": { - "frame": {"x":1711,"y":659,"w":141,"h":143}, + "frame": {"x":552,"y":1289,"w":141,"h":143}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":141,"h":143}, @@ -1002,7 +1058,7 @@ }, "sprites/buildings/splitter-compact-inverse.png": { - "frame": {"x":584,"y":1286,"w":141,"h":136}, + "frame": {"x":1501,"y":592,"w":141,"h":136}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":3,"w":141,"h":136}, @@ -1010,7 +1066,7 @@ }, "sprites/buildings/splitter-compact.png": { - "frame": {"x":729,"y":1286,"w":139,"h":136}, + "frame": {"x":1789,"y":594,"w":139,"h":136}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":3,"w":139,"h":136}, @@ -1018,7 +1074,7 @@ }, "sprites/buildings/splitter.png": { - "frame": {"x":555,"y":401,"w":256,"h":143}, + "frame": {"x":1241,"y":445,"w":256,"h":143}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":17,"y":0,"w":256,"h":143}, @@ -1026,7 +1082,7 @@ }, "sprites/buildings/stacker.png": { - "frame": {"x":1539,"y":955,"w":260,"h":143}, + "frame": {"x":1383,"y":298,"w":260,"h":143}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":14,"y":0,"w":260,"h":143}, @@ -1034,7 +1090,7 @@ }, "sprites/buildings/trash-storage.png": { - "frame": {"x":3,"y":848,"w":248,"h":288}, + "frame": {"x":295,"y":704,"w":248,"h":288}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":22,"y":0,"w":248,"h":288}, @@ -1042,7 +1098,7 @@ }, "sprites/buildings/trash.png": { - "frame": {"x":1391,"y":955,"w":144,"h":144}, + "frame": {"x":1794,"y":446,"w":144,"h":144}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":144,"h":144}, @@ -1050,7 +1106,7 @@ }, "sprites/buildings/underground_belt_entry-tier2.png": { - "frame": {"x":1014,"y":1284,"w":137,"h":124}, + "frame": {"x":981,"y":990,"w":137,"h":124}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":20,"w":137,"h":124}, @@ -1058,7 +1114,7 @@ }, "sprites/buildings/underground_belt_entry.png": { - "frame": {"x":1181,"y":1400,"w":137,"h":111}, + "frame": {"x":983,"y":1336,"w":137,"h":111}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":33,"w":137,"h":111}, @@ -1066,7 +1122,7 @@ }, "sprites/buildings/underground_belt_exit-tier2.png": { - "frame": {"x":1297,"y":1284,"w":137,"h":111}, + "frame": {"x":697,"y":1341,"w":137,"h":111}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":137,"h":111}, @@ -1074,15 +1130,55 @@ }, "sprites/buildings/underground_belt_exit.png": { - "frame": {"x":1322,"y":1399,"w":137,"h":111}, + "frame": {"x":838,"y":1381,"w":137,"h":111}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":137,"h":111}, "sourceSize": {"w":144,"h":144} }, +"sprites/buildings/wire_crossings-merger.png": +{ + "frame": {"x":1207,"y":592,"w":144,"h":102}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":0,"w":144,"h":102}, + "sourceSize": {"w":144,"h":144} +}, +"sprites/buildings/wire_crossings.png": +{ + "frame": {"x":983,"y":1234,"w":144,"h":98}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":46,"w":144,"h":98}, + "sourceSize": {"w":144,"h":144} +}, +"sprites/buildings/wire_left.png": +{ + "frame": {"x":1455,"y":904,"w":60,"h":60}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":0,"y":35,"w":60,"h":60}, + "sourceSize": {"w":95,"h":95} +}, +"sprites/buildings/wire_right.png": +{ + "frame": {"x":1455,"y":968,"w":60,"h":60}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":35,"y":35,"w":60,"h":60}, + "sourceSize": {"w":95,"h":95} +}, +"sprites/buildings/wire_top.png": +{ + "frame": {"x":1186,"y":880,"w":25,"h":95}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":35,"y":0,"w":25,"h":95}, + "sourceSize": {"w":95,"h":95} +}, "sprites/debug/acceptor_slot.png": { - "frame": {"x":1711,"y":3,"w":38,"h":48}, + "frame": {"x":1710,"y":1006,"w":38,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":38,"h":48}, @@ -1090,7 +1186,7 @@ }, "sprites/debug/ejector_slot.png": { - "frame": {"x":1711,"y":55,"w":38,"h":48}, + "frame": {"x":1954,"y":1364,"w":38,"h":48}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":38,"h":48}, @@ -1098,7 +1194,7 @@ }, "sprites/map_overview/belt_forward.png": { - "frame": {"x":842,"y":807,"w":20,"h":24}, + "frame": {"x":1907,"y":398,"w":20,"h":24}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":20,"h":24}, @@ -1106,7 +1202,7 @@ }, "sprites/map_overview/belt_left.png": { - "frame": {"x":890,"y":807,"w":22,"h":22}, + "frame": {"x":1429,"y":1004,"w":22,"h":22}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":2,"w":22,"h":22}, @@ -1114,7 +1210,7 @@ }, "sprites/map_overview/belt_right.png": { - "frame": {"x":916,"y":807,"w":22,"h":22}, + "frame": {"x":1980,"y":693,"w":22,"h":22}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":22,"h":22}, @@ -1122,15 +1218,23 @@ }, "sprites/misc/deletion_marker.png": { - "frame": {"x":1355,"y":377,"w":62,"h":62}, + "frame": {"x":786,"y":1496,"w":62,"h":62}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":5,"w":62,"h":62}, "sourceSize": {"w":72,"h":72} }, +"sprites/misc/energy_generator_overlay.png": +{ + "frame": {"x":979,"y":1451,"w":116,"h":44}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":137,"y":217,"w":116,"h":44}, + "sourceSize": {"w":288,"h":288} +}, "sprites/misc/hub_direction_indicator.png": { - "frame": {"x":814,"y":807,"w":24,"h":24}, + "frame": {"x":1077,"y":739,"w":24,"h":24}, "rotated": false, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":24,"h":24}, @@ -1138,7 +1242,7 @@ }, "sprites/misc/lock_direction_indicator.png": { - "frame": {"x":774,"y":807,"w":36,"h":24}, + "frame": {"x":1552,"y":1518,"w":36,"h":24}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":0,"y":6,"w":36,"h":24}, @@ -1146,7 +1250,7 @@ }, "sprites/misc/slot_bad_arrow.png": { - "frame": {"x":1355,"y":377,"w":62,"h":62}, + "frame": {"x":786,"y":1496,"w":62,"h":62}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":5,"w":62,"h":62}, @@ -1154,7 +1258,7 @@ }, "sprites/misc/slot_good_arrow.png": { - "frame": {"x":1436,"y":287,"w":62,"h":72}, + "frame": {"x":1287,"y":698,"w":62,"h":72}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":5,"y":0,"w":62,"h":72}, @@ -1162,7 +1266,7 @@ }, "sprites/misc/storage_overlay.png": { - "frame": {"x":1755,"y":589,"w":133,"h":66}, + "frame": {"x":701,"y":1271,"w":133,"h":66}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":2,"w":133,"h":66}, @@ -1170,19 +1274,115 @@ }, "sprites/misc/waypoint.png": { - "frame": {"x":866,"y":807,"w":20,"h":24}, + "frame": {"x":1508,"y":824,"w":20,"h":24}, "rotated": false, "trimmed": true, "spriteSourceSize": {"x":2,"y":0,"w":20,"h":24}, "sourceSize": {"w":24,"h":24} +}, +"sprites/misc/wires_overlay_tile.png": +{ + "frame": {"x":1107,"y":591,"w":96,"h":96}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":96,"h":96}, + "sourceSize": {"w":96,"h":96} +}, +"sprites/wires/battery_empty.png": +{ + "frame": {"x":1963,"y":249,"w":29,"h":46}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":9,"y":1,"w":29,"h":46}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/wires/battery_full.png": +{ + "frame": {"x":786,"y":1456,"w":44,"h":30}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":10,"w":44,"h":30}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/wires/battery_low.png": +{ + "frame": {"x":1932,"y":693,"w":44,"h":30}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":10,"w":44,"h":30}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/wires/battery_medium.png": +{ + "frame": {"x":1504,"y":1518,"w":44,"h":30}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":10,"w":44,"h":30}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/wires/negative_energy.png": +{ + "frame": {"x":1710,"y":1058,"w":32,"h":32}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":8,"y":8,"w":32,"h":32}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/wires/pin_negative_accept.png": +{ + "frame": {"x":1963,"y":3,"w":56,"h":79}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":20,"y":0,"w":56,"h":79}, + "sourceSize": {"w":96,"h":96} +}, +"sprites/wires/pin_negative_eject.png": +{ + "frame": {"x":1963,"y":169,"w":49,"h":76}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":23,"y":0,"w":49,"h":76}, + "sourceSize": {"w":96,"h":96} +}, +"sprites/wires/pin_positive_accept.png": +{ + "frame": {"x":1455,"y":824,"w":49,"h":76}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":23,"y":0,"w":49,"h":76}, + "sourceSize": {"w":96,"h":96} +}, +"sprites/wires/pin_positive_eject.png": +{ + "frame": {"x":1963,"y":86,"w":56,"h":79}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":20,"y":0,"w":56,"h":79}, + "sourceSize": {"w":96,"h":96} +}, +"sprites/wires/positive_energy.png": +{ + "frame": {"x":1746,"y":1058,"w":32,"h":32}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":8,"y":8,"w":32,"h":32}, + "sourceSize": {"w":48,"h":48} +}, +"sprites/wires/waste_piled.png": +{ + "frame": {"x":916,"y":1496,"w":44,"h":43}, + "rotated": false, + "trimmed": true, + "spriteSourceSize": {"x":2,"y":2,"w":44,"h":43}, + "sourceSize": {"w":48,"h":48} }}, "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "1.0", "image": "atlas0_75.png", "format": "RGBA8888", - "size": {"w":1894,"h":1530}, + "size": {"w":2031,"h":1561}, "scale": "0.75", - "smartupdate": "$TexturePacker:SmartUpdate:dc34796c028235bbc69e5b8d854254ca:2765d0b8c8bcbb7a4aaaf1104853ad41:8778749683c68f53155587e6d831729a$" + "smartupdate": "$TexturePacker:SmartUpdate:4e5fb3bd7f1e5423e4fcea2215debe11:0c5d091d0b928944c68553dcc592c801:f159918d23e5952766c6d23ab52278c6$" } } diff --git a/res_built/atlas/atlas0_75.png b/res_built/atlas/atlas0_75.png index 5b42712a..0916f7aa 100644 Binary files a/res_built/atlas/atlas0_75.png and b/res_built/atlas/atlas0_75.png differ diff --git a/res_built/atlas/atlas1_100.json b/res_built/atlas/atlas1_100.json deleted file mode 100644 index 3581b36a..00000000 --- a/res_built/atlas/atlas1_100.json +++ /dev/null @@ -1,509 +0,0 @@ -{"frames": { - -"sprites/belt/forward_3.png": -{ - "frame": {"x":3,"y":783,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_4.png": -{ - "frame": {"x":3,"y":913,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_5.png": -{ - "frame": {"x":3,"y":1043,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_6.png": -{ - "frame": {"x":3,"y":1173,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_7.png": -{ - "frame": {"x":3,"y":1303,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_8.png": -{ - "frame": {"x":107,"y":3,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_9.png": -{ - "frame": {"x":107,"y":133,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_22.png": -{ - "frame": {"x":3,"y":3,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_23.png": -{ - "frame": {"x":3,"y":133,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_24.png": -{ - "frame": {"x":3,"y":263,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_25.png": -{ - "frame": {"x":3,"y":393,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_26.png": -{ - "frame": {"x":3,"y":523,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/forward_27.png": -{ - "frame": {"x":3,"y":653,"w":100,"h":126}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":0,"w":100,"h":126}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_2.png": -{ - "frame": {"x":3,"y":1784,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_3.png": -{ - "frame": {"x":107,"y":965,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_4.png": -{ - "frame": {"x":107,"y":1082,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_5.png": -{ - "frame": {"x":107,"y":1199,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_6.png": -{ - "frame": {"x":107,"y":1316,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_7.png": -{ - "frame": {"x":120,"y":1433,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_8.png": -{ - "frame": {"x":120,"y":1550,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_9.png": -{ - "frame": {"x":120,"y":1667,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_17.png": -{ - "frame": {"x":3,"y":1433,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_18.png": -{ - "frame": {"x":3,"y":1550,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_19.png": -{ - "frame": {"x":3,"y":1667,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_20.png": -{ - "frame": {"x":107,"y":263,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_21.png": -{ - "frame": {"x":211,"y":3,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_22.png": -{ - "frame": {"x":211,"y":120,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_23.png": -{ - "frame": {"x":107,"y":380,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_24.png": -{ - "frame": {"x":107,"y":497,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_25.png": -{ - "frame": {"x":107,"y":614,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_26.png": -{ - "frame": {"x":107,"y":731,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/left_27.png": -{ - "frame": {"x":107,"y":848,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_0.png": -{ - "frame": {"x":120,"y":1784,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_1.png": -{ - "frame": {"x":224,"y":237,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_2.png": -{ - "frame": {"x":224,"y":1290,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_3.png": -{ - "frame": {"x":341,"y":705,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_4.png": -{ - "frame": {"x":341,"y":822,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_5.png": -{ - "frame": {"x":341,"y":939,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_6.png": -{ - "frame": {"x":341,"y":1056,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_7.png": -{ - "frame": {"x":341,"y":1173,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_8.png": -{ - "frame": {"x":341,"y":1290,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_9.png": -{ - "frame": {"x":354,"y":1407,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_10.png": -{ - "frame": {"x":328,"y":3,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_11.png": -{ - "frame": {"x":328,"y":120,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_12.png": -{ - "frame": {"x":224,"y":354,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_13.png": -{ - "frame": {"x":224,"y":471,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_14.png": -{ - "frame": {"x":224,"y":588,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_15.png": -{ - "frame": {"x":224,"y":705,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_16.png": -{ - "frame": {"x":224,"y":822,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_17.png": -{ - "frame": {"x":224,"y":939,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_18.png": -{ - "frame": {"x":224,"y":1056,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_19.png": -{ - "frame": {"x":224,"y":1173,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_20.png": -{ - "frame": {"x":237,"y":1407,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_21.png": -{ - "frame": {"x":237,"y":1524,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_22.png": -{ - "frame": {"x":237,"y":1641,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_23.png": -{ - "frame": {"x":237,"y":1758,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_24.png": -{ - "frame": {"x":341,"y":237,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_25.png": -{ - "frame": {"x":341,"y":354,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_26.png": -{ - "frame": {"x":341,"y":471,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/belt/right_27.png": -{ - "frame": {"x":341,"y":588,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/buildings/belt_left.png": -{ - "frame": {"x":354,"y":1524,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":0,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}, -"sprites/buildings/belt_right.png": -{ - "frame": {"x":354,"y":1641,"w":113,"h":113}, - "rotated": false, - "trimmed": true, - "spriteSourceSize": {"x":13,"y":13,"w":113,"h":113}, - "sourceSize": {"w":126,"h":126} -}}, -"meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "1.0", - "image": "atlas1_100.png", - "format": "RGBA8888", - "size": {"w":470,"h":1900}, - "scale": "1", - "related_multi_packs": [ "atlas0_100.json" ], - "smartupdate": "$TexturePacker:SmartUpdate:dc34796c028235bbc69e5b8d854254ca:2765d0b8c8bcbb7a4aaaf1104853ad41:8778749683c68f53155587e6d831729a$" -} -} diff --git a/res_built/atlas/atlas1_100.png b/res_built/atlas/atlas1_100.png deleted file mode 100644 index 75210aad..00000000 Binary files a/res_built/atlas/atlas1_100.png and /dev/null differ diff --git a/res_raw/atlas.tps b/res_raw/atlas.tps index d4e8f4e0..87eacd70 100644 --- a/res_raw/atlas.tps +++ b/res_raw/atlas.tps @@ -19,9 +19,9 @@ maxTextureSize width - 2048 + 4096 height - 2048 + 4096 @@ -53,9 +53,9 @@ maxTextureSize width - -1 + 2048 height - -1 + 2048 @@ -70,9 +70,9 @@ maxTextureSize width - -1 + 1024 height - -1 + 1024 @@ -255,6 +255,11 @@ sprites/buildings/miner.png sprites/buildings/rotater.png sprites/buildings/trash.png + sprites/misc/wires_overlay_tile.png + sprites/wires/pin_negative_accept.png + sprites/wires/pin_negative_eject.png + sprites/wires/pin_positive_accept.png + sprites/wires/pin_positive_eject.png pivotPoint 0.5,0.5 @@ -353,9 +358,19 @@ sprites/blueprints/belt_left.png sprites/blueprints/belt_right.png sprites/blueprints/belt_top.png + sprites/blueprints/wire_crossings-merger.png + sprites/blueprints/wire_crossings.png + sprites/blueprints/wire_left.png + sprites/blueprints/wire_right.png + sprites/blueprints/wire_top.png sprites/buildings/belt_left.png sprites/buildings/belt_right.png sprites/buildings/belt_top.png + sprites/buildings/wire_crossings-merger.png + sprites/buildings/wire_crossings.png + sprites/buildings/wire_left.png + sprites/buildings/wire_right.png + sprites/buildings/wire_top.png pivotPoint 0.5,0.5 @@ -370,6 +385,28 @@ scale9FromFile + sprites/blueprints/advanced_processor.png + sprites/blueprints/energy_generator.png + sprites/blueprints/painter-double.png + sprites/blueprints/trash-storage.png + sprites/buildings/advanced_processor.png + sprites/buildings/energy_generator.png + sprites/buildings/painter-double.png + sprites/misc/energy_generator_overlay.png + + pivotPoint + 0.5,0.5 + spriteScale + 1 + scale9Enabled + + scale9Borders + 96,96,192,192 + scale9Paddings + 96,96,192,192 + scale9FromFile + + sprites/blueprints/cutter-quad.png sprites/blueprints/painter-quad.png sprites/buildings/cutter-quad.png @@ -409,25 +446,6 @@ scale9FromFile - sprites/blueprints/energy_generator.png - sprites/blueprints/painter-double.png - sprites/blueprints/trash-storage.png - sprites/buildings/energy_generator.png - sprites/buildings/painter-double.png - - pivotPoint - 0.5,0.5 - spriteScale - 1 - scale9Enabled - - scale9Borders - 96,96,192,192 - scale9Paddings - 96,96,192,192 - scale9FromFile - - sprites/blueprints/miner-chainable.png sprites/blueprints/miner.png sprites/blueprints/rotater-ccw.png @@ -578,6 +596,27 @@ scale9FromFile + sprites/wires/battery_empty.png + sprites/wires/battery_full.png + sprites/wires/battery_low.png + sprites/wires/battery_medium.png + sprites/wires/negative_energy.png + sprites/wires/positive_energy.png + sprites/wires/waste_piled.png + + pivotPoint + 0.5,0.5 + spriteScale + 1 + scale9Enabled + + scale9Borders + 16,16,32,32 + scale9Paddings + 16,16,32,32 + scale9FromFile + + fileList diff --git a/res_raw/sounds/music/menu.mp3 b/res_raw/sounds/music/menu.mp3 deleted file mode 100644 index 87864f71..00000000 --- a/res_raw/sounds/music/menu.mp3 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e94039ba13b6af3a9e59d8675ed2f7373aad20fc9bb0c12e35b1a901d906efd -size 1463494 diff --git a/res_raw/sounds/music/menu.wav b/res_raw/sounds/music/menu.wav new file mode 100644 index 00000000..4024b94a --- /dev/null +++ b/res_raw/sounds/music/menu.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e5dcd6de724297149a8c704bf07c850f002b6430fd6cf744519d0a20c8545bb +size 18285574 diff --git a/res_raw/sounds/music/theme.wav b/res_raw/sounds/music/theme.wav index a2014603..555caaee 100644 --- a/res_raw/sounds/music/theme.wav +++ b/res_raw/sounds/music/theme.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c334a9f100fce4647b4803d2a8270b30e26d53622b3717bdb81b3ea07f84aed -size 150286082 +oid sha256:df7487fb5e8cb34cecee2519b9c3162a5107d2d7b1301c4a550904cfb108a015 +size 223361394 diff --git a/res_raw/sprites/blueprints/advanced_processor.png b/res_raw/sprites/blueprints/advanced_processor.png new file mode 100644 index 00000000..ab385816 Binary files /dev/null and b/res_raw/sprites/blueprints/advanced_processor.png differ diff --git a/res_raw/sprites/blueprints/energy_generator.png b/res_raw/sprites/blueprints/energy_generator.png index e1534b57..42258c63 100644 Binary files a/res_raw/sprites/blueprints/energy_generator.png and b/res_raw/sprites/blueprints/energy_generator.png differ diff --git a/res_raw/sprites/blueprints/wire_crossings-merger.png b/res_raw/sprites/blueprints/wire_crossings-merger.png new file mode 100644 index 00000000..82d9862c Binary files /dev/null and b/res_raw/sprites/blueprints/wire_crossings-merger.png differ diff --git a/res_raw/sprites/blueprints/wire_crossings.png b/res_raw/sprites/blueprints/wire_crossings.png new file mode 100644 index 00000000..113af179 Binary files /dev/null and b/res_raw/sprites/blueprints/wire_crossings.png differ diff --git a/res_raw/sprites/blueprints/wire_left.png b/res_raw/sprites/blueprints/wire_left.png new file mode 100644 index 00000000..232c13e9 Binary files /dev/null and b/res_raw/sprites/blueprints/wire_left.png differ diff --git a/res_raw/sprites/blueprints/wire_right.png b/res_raw/sprites/blueprints/wire_right.png new file mode 100644 index 00000000..fba98482 Binary files /dev/null and b/res_raw/sprites/blueprints/wire_right.png differ diff --git a/res_raw/sprites/blueprints/wire_top.png b/res_raw/sprites/blueprints/wire_top.png new file mode 100644 index 00000000..52efcc01 Binary files /dev/null and b/res_raw/sprites/blueprints/wire_top.png differ diff --git a/res_raw/sprites/buildings/advanced_processor.png b/res_raw/sprites/buildings/advanced_processor.png new file mode 100644 index 00000000..5402760b Binary files /dev/null and b/res_raw/sprites/buildings/advanced_processor.png differ diff --git a/res_raw/sprites/buildings/energy_generator.png b/res_raw/sprites/buildings/energy_generator.png index e06b86ea..5bd9f9a2 100644 Binary files a/res_raw/sprites/buildings/energy_generator.png and b/res_raw/sprites/buildings/energy_generator.png differ diff --git a/res_raw/sprites/buildings/wire_crossings-merger.png b/res_raw/sprites/buildings/wire_crossings-merger.png new file mode 100644 index 00000000..42cef3f8 Binary files /dev/null and b/res_raw/sprites/buildings/wire_crossings-merger.png differ diff --git a/res_raw/sprites/buildings/wire_crossings.png b/res_raw/sprites/buildings/wire_crossings.png new file mode 100644 index 00000000..814349ba Binary files /dev/null and b/res_raw/sprites/buildings/wire_crossings.png differ diff --git a/res_raw/sprites/buildings/wire_left.png b/res_raw/sprites/buildings/wire_left.png new file mode 100644 index 00000000..5799ab5b Binary files /dev/null and b/res_raw/sprites/buildings/wire_left.png differ diff --git a/res_raw/sprites/buildings/wire_right.png b/res_raw/sprites/buildings/wire_right.png new file mode 100644 index 00000000..b3f2df5a Binary files /dev/null and b/res_raw/sprites/buildings/wire_right.png differ diff --git a/res_raw/sprites/buildings/wire_top.png b/res_raw/sprites/buildings/wire_top.png new file mode 100644 index 00000000..a9f90aaa Binary files /dev/null and b/res_raw/sprites/buildings/wire_top.png differ diff --git a/res_raw/sprites/create_blueprint_previews.py b/res_raw/sprites/create_blueprint_previews.py index 586c4760..cceefae0 100644 --- a/res_raw/sprites/create_blueprint_previews.py +++ b/res_raw/sprites/create_blueprint_previews.py @@ -21,6 +21,8 @@ def rgb2gray(rgb): return np.dot(rgb[..., :3], [0.2989, 0.5870, 0.1140]) + + def save_image(data, outfilename, src_image): img = Image.fromarray(np.asarray( np.clip(data, 0, 255), dtype="uint8"), "L") @@ -32,6 +34,18 @@ def save_image(data, outfilename, src_image): mask = src_image.filter(ImageFilter.GaussianBlur(10)).load() orig = src_image.load() + + isWire = "wire" in outfilename + + targetR = 104 + targetG = 200 + targetB = 255 + + if isWire: + targetR = 255 + targetG = 104 + targetB = 232 + for x in range(img.width): for y in range(img.height): realpixl = realSrc[x, y] @@ -49,9 +63,9 @@ def save_image(data, outfilename, src_image): noShadow = 1 - shadow dst[x, y] = ( - min(255, int((realpixl[0] / 255.0 * 0.4 + 0.6) * 104 * 1.1)), - min(255, int((realpixl[1] / 255.0 * 0.4 + 0.6) * 200 * 1.1)), - min(255, int((realpixl[2] / 255.0 * 0.4 + 0.6) * 255 * 1.1)), + min(255, int((realpixl[0] / 255.0 * 0.4 + 0.6) * targetR * 1.1)), + min(255, int((realpixl[1] / 255.0 * 0.4 + 0.6) * targetG * 1.1)), + min(255, int((realpixl[2] / 255.0 * 0.4 + 0.6) * targetB * 1.1)), min(255, int(float(realpixl[3]) * (0.6 + 5 * edgeFactor)))) diff --git a/res_raw/sprites/misc/energy_generator_overlay.png b/res_raw/sprites/misc/energy_generator_overlay.png new file mode 100644 index 00000000..634c2e10 Binary files /dev/null and b/res_raw/sprites/misc/energy_generator_overlay.png differ diff --git a/res_raw/sprites/misc/wires_overlay_tile.png b/res_raw/sprites/misc/wires_overlay_tile.png new file mode 100644 index 00000000..b8ec3480 Binary files /dev/null and b/res_raw/sprites/misc/wires_overlay_tile.png differ diff --git a/res_raw/sprites/wires/battery_empty.png b/res_raw/sprites/wires/battery_empty.png new file mode 100644 index 00000000..78095666 Binary files /dev/null and b/res_raw/sprites/wires/battery_empty.png differ diff --git a/res_raw/sprites/wires/battery_full.png b/res_raw/sprites/wires/battery_full.png new file mode 100644 index 00000000..5256150f Binary files /dev/null and b/res_raw/sprites/wires/battery_full.png differ diff --git a/res_raw/sprites/wires/battery_low.png b/res_raw/sprites/wires/battery_low.png new file mode 100644 index 00000000..79fbd8a4 Binary files /dev/null and b/res_raw/sprites/wires/battery_low.png differ diff --git a/res_raw/sprites/wires/battery_medium.png b/res_raw/sprites/wires/battery_medium.png new file mode 100644 index 00000000..ba0151a0 Binary files /dev/null and b/res_raw/sprites/wires/battery_medium.png differ diff --git a/res_raw/sprites/wires/negative_energy.png b/res_raw/sprites/wires/negative_energy.png new file mode 100644 index 00000000..cc372330 Binary files /dev/null and b/res_raw/sprites/wires/negative_energy.png differ diff --git a/res_raw/sprites/wires/pin_negative_accept.png b/res_raw/sprites/wires/pin_negative_accept.png new file mode 100644 index 00000000..82581abb Binary files /dev/null and b/res_raw/sprites/wires/pin_negative_accept.png differ diff --git a/res_raw/sprites/wires/pin_negative_eject.png b/res_raw/sprites/wires/pin_negative_eject.png new file mode 100644 index 00000000..e816bd83 Binary files /dev/null and b/res_raw/sprites/wires/pin_negative_eject.png differ diff --git a/res_raw/sprites/wires/pin_positive_accept.png b/res_raw/sprites/wires/pin_positive_accept.png new file mode 100644 index 00000000..57044532 Binary files /dev/null and b/res_raw/sprites/wires/pin_positive_accept.png differ diff --git a/res_raw/sprites/wires/pin_positive_eject.png b/res_raw/sprites/wires/pin_positive_eject.png new file mode 100644 index 00000000..a7da6bc0 Binary files /dev/null and b/res_raw/sprites/wires/pin_positive_eject.png differ diff --git a/res_raw/sprites/wires/positive_energy.png b/res_raw/sprites/wires/positive_energy.png new file mode 100644 index 00000000..c95c80c9 Binary files /dev/null and b/res_raw/sprites/wires/positive_energy.png differ diff --git a/res_raw/sprites/wires/waste_piled.png b/res_raw/sprites/wires/waste_piled.png new file mode 100644 index 00000000..062d0df6 Binary files /dev/null and b/res_raw/sprites/wires/waste_piled.png differ diff --git a/src/css/icons.scss b/src/css/icons.scss index bfc67713..a0967656 100644 --- a/src/css/icons.scss +++ b/src/css/icons.scss @@ -1,5 +1,5 @@ $buildings: belt, cutter, miner, mixer, painter, rotater, splitter, stacker, trash, underground_belt, - energy_generator; + energy_generator, wire, advanced_processor, wire_crossings; @each $building in $buildings { [data-icon="building_icons/#{$building}.png"] { diff --git a/src/css/ingame_hud/buildings_toolbar.scss b/src/css/ingame_hud/buildings_toolbar.scss index d481407e..ed5bb7a2 100644 --- a/src/css/ingame_hud/buildings_toolbar.scss +++ b/src/css/ingame_hud/buildings_toolbar.scss @@ -1,4 +1,4 @@ -#ingame_HUD_buildings_toolbar { +.ingame_buildingsToolbar { position: fixed; @include S(bottom, 0px); left: 50%; diff --git a/src/css/ingame_hud/debug_info.scss b/src/css/ingame_hud/debug_info.scss index f370d04e..3a077d53 100644 --- a/src/css/ingame_hud/debug_info.scss +++ b/src/css/ingame_hud/debug_info.scss @@ -5,8 +5,30 @@ text-align: right; font-size: 15px; - display: flex; + display: grid; line-height: 15px; - flex-direction: column; color: #fff; + grid-gap: 2px; + text-shadow: 1px 1px 3px rgba(#000, 0.4); + font-weight: bold; + + &:not([data-mode="detailed"]) { + .mousePosition, + .cameraPosition { + display: none; + } + } + + code { + background: #333; + min-width: 30px; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 14px; + line-height: 15px; + padding: 1px; + font-family: "GameFont"; + border-radius: 3px; + } } diff --git a/src/css/ingame_hud/sandbox_controller.scss b/src/css/ingame_hud/sandbox_controller.scss new file mode 100644 index 00000000..0202f5ef --- /dev/null +++ b/src/css/ingame_hud/sandbox_controller.scss @@ -0,0 +1,50 @@ +#ingame_HUD_SandboxController { + position: absolute; + background: $ingameHudBg; + @include S(padding, 5px); + @include S(bottom, 10px); + @include S(left, 10px); + + @include SuperSmallText; + color: #eee; + display: flex; + flex-direction: column; + + > label { + text-transform: uppercase; + } + + .hint { + color: #aaa; + } + + .plusMinus { + @include S(margin-top, 4px); + display: grid; + grid-template-columns: 1fr auto auto; + align-items: center; + @include S(grid-gap, 4px); + + button { + @include PlainText; + @include S(padding, 0); + display: flex; + align-items: center; + justify-content: center; + @include S(width, 15px); + @include S(height, 15px); + @include IncreasedClickArea(0px); + } + } + + .additionalOptions { + display: flex; + flex-direction: column; + @include S(margin-top, 10px); + button { + @include S(margin-bottom, 2px); + @include IncreasedClickArea(0px); + @include SuperSmallText; + } + } +} diff --git a/src/css/ingame_hud/waypoints.scss b/src/css/ingame_hud/waypoints.scss index fecb2c66..7a9941c0 100644 --- a/src/css/ingame_hud/waypoints.scss +++ b/src/css/ingame_hud/waypoints.scss @@ -49,16 +49,19 @@ font-weight: bold; &:hover { - opacity: 1; + opacity: 0.8; } - .deleteButton { + .editButton { @include S(width, 10px); @include S(height, 10px); @include S(margin-left, 4px); - background: uiResource("icons/close.png") center center / 60% no-repeat; + background: uiResource("icons/edit_key.png") center center / 70% no-repeat; pointer-events: all; cursor: pointer; + position: relative; + @include IncreasedClickArea(2px); + transition: transform 0.04s ease-in-out; &:hover { transform: scale(1.5); diff --git a/src/css/main.scss b/src/css/main.scss index 6b758e80..fa3ed356 100644 --- a/src/css/main.scss +++ b/src/css/main.scss @@ -51,6 +51,7 @@ @import "ingame_hud/interactive_tutorial"; @import "ingame_hud/color_blind_helper"; @import "ingame_hud/shape_viewer"; +@import "ingame_hud/sandbox_controller"; // prettier-ignore $elements: @@ -73,10 +74,12 @@ ingame_HUD_EntityDebugger, ingame_HUD_InteractiveTutorial, ingame_HUD_TutorialHints, ingame_HUD_buildings_toolbar, +ingame_HUD_wires_toolbar, ingame_HUD_BlueprintPlacer, ingame_HUD_Waypoints_Hint, ingame_HUD_Watermark, ingame_HUD_ColorBlindBelowTileHelper, +ingame_HUD_SandboxController, // Overlays ingame_HUD_BetaOverlay, diff --git a/src/css/states/main_menu.scss b/src/css/states/main_menu.scss index be3bcce4..0981cdfc 100644 --- a/src/css/states/main_menu.scss +++ b/src/css/states/main_menu.scss @@ -147,6 +147,7 @@ flex-grow: 1; align-items: center; justify-content: center; + flex-direction: column; @include S(padding-top, 20px); img { @@ -160,6 +161,24 @@ background: uiResource("demo_badge.png") center center / contain no-repeat; display: inline-block; } + + position: relative; + .updateLabel { + position: absolute; + transform: translateX(50%) rotate(-5deg); + color: $colorRedBright; + @include Heading; + text-transform: uppercase; + font-weight: bold; + @include S(right, 40px); + @include S(bottom, 20px); + + @include InlineAnimation(1.3s ease-in-out infinite) { + 50% { + transform: translateX(50%) rotate(-7deg) scale(1.1); + } + } + } } .betaWarning { diff --git a/src/js/application.js b/src/js/application.js index f08b467e..1726bd2d 100644 --- a/src/js/application.js +++ b/src/js/application.js @@ -1,6 +1,5 @@ import { AnimationFrame } from "./core/animation_frame"; import { BackgroundResourcesLoader } from "./core/background_resources_loader"; -import { performanceNow } from "./core/builtins"; import { IS_MOBILE } from "./core/config"; import { GameState } from "./core/game_state"; import { GLOBAL_APP, setGlobalApp } from "./core/globals"; @@ -356,7 +355,7 @@ export class Application { return; } - const time = performanceNow(); + const time = performance.now(); // Periodically check for resizes, this is expensive (takes 2-3ms so only do it once in a while!) if (!this.lastResizeCheck || time - this.lastResizeCheck > 1000) { diff --git a/src/js/changelog.js b/src/js/changelog.js index d4751f5b..16a9d692 100644 --- a/src/js/changelog.js +++ b/src/js/changelog.js @@ -1,16 +1,49 @@ export const CHANGELOG = [ { - version: "1.1.18", - date: "24.06.2020", + version: "1.2.0", + date: "unreleased", entries: [ - "Preparations for the wires update", - "Update belt placement performance on huge factories (by Phlosioneer)", + "WIRES", + "Allow holding ALT in belt planner to reverse direction (by jakobhellermann)", + "Clear cursor when trying to pipette the same building twice (by hexy)", + "Allow binding TAB (by swtw7466)", + "Added keybinding to close menus (by isaisstillalive / Sandwichs-del)", + "Fix rare crash regarding the buildings toolbar (by isaisstillalive)", + "Fixed some phrases (by EnderDoom77)", + "Zoom towards mouse cursor (by Dimava)", + "Updated the soundtrack again, it is now 20 minutes in total!", + "Updated and added new translations (Thanks to all contributors!)", + "Allow editing waypoints (by isaisstillalive)", + "Show confirmation when cutting area which is too expensive to get pasted again (by isaisstillalive)", + "Show mouse and camera tile on debug overlay (F4) (by dengr)", + "Fix tunnels entrances connecting to exits sometimes when they shouldn't", + "The initial belt planner direction is now based on the cursor movement (by MizardX)", + "Fix preferred variant not getting saved when clicking on the hud (by Danacus)", + ], + }, + { + version: "1.1.19", + date: "02.07.2020", + entries: [ + "There are now notifications every 15 minutes in the demo version to buy the full version (For further details and the reason, check the #surveys channel in the discord)", + "I'm still working on the wires update, I hope to release it mid july!", + ], + }, + { + version: "1.1.18", + date: "27.06.2020", + entries: [ + "Huge performance improvements - up to double fps and tick-rate! This will wipe out all current items on belts.", + "Reduce story shapes required until unlocking blueprints", "Allow clicking on variants to select them", - "Allow clicking 'Q' over a shape or color patch to automatically select the miner building (by Gerdon262)", "Add 'copy key' button to shape viewer", + "Add more FPS to the belt animation and fix belt animation seeming to go 'backwards' on high belt speeds", "Fix deconstruct sound being played when right clicking hub", + "Allow clicking 'Q' over a shape or color patch to automatically select the miner building (by Gerdon262)", + "Update belt placement performance on huge factories (by Phlosioneer)", + "Fix duplicate waypoints with a shape not rendering (by hexy)", + "Fix smart tunnel placement deleting wrong tunnels (by mordof)", "Add setting (on by default) to store the last used rotation per building instead of globally storing it (by Magos)", - "Add more FPS to the belt animation", "Added chinese (traditional) translation", "Updated translations", ], diff --git a/src/js/core/animation_frame.js b/src/js/core/animation_frame.js index b7243af7..0e921174 100644 --- a/src/js/core/animation_frame.js +++ b/src/js/core/animation_frame.js @@ -4,8 +4,6 @@ import { Signal } from "./signal"; import BackgroundAnimationFrameEmitterWorker from "../webworkers/background_animation_frame_emittter.worker"; import { createLogger } from "./logging"; -import { performanceNow } from "./builtins"; - const logger = createLogger("animation_frame"); const maxDtMs = 1000; @@ -34,7 +32,7 @@ export class AnimationFrame { * @param {MessageEvent} event */ handleBackgroundTick(event) { - const time = performanceNow(); + const time = performance.now(); if (!this.bgLastTime) { // First update, first delta is always 16ms this.bgFrameEmitted.dispatch(1000 / 60); diff --git a/src/js/core/async_compression.js b/src/js/core/async_compression.js index 4afed1ea..b11f8fd5 100644 --- a/src/js/core/async_compression.js +++ b/src/js/core/async_compression.js @@ -2,8 +2,6 @@ import CompressionWorker from "../webworkers/compression.worker"; import { createLogger } from "./logging"; import { compressX64 } from "./lzstring"; -import { performanceNow, JSON_stringify } from "./builtins"; - const logger = createLogger("async_compression"); export let compressionPrefix = String.fromCodePoint(1); @@ -53,7 +51,7 @@ class AsynCompression { return; } - const duration = performanceNow() - jobData.startTime; + const duration = performance.now() - jobData.startTime; // log(this, "Got response from worker within", duration.toFixed(2), "ms"); const resolver = jobData.resolver; delete this.currentJobs[jobId]; @@ -100,7 +98,7 @@ class AsynCompression { this.currentJobs[jobId] = { errorHandler, resolver: resolve, - startTime: performanceNow(), + startTime: performance.now(), }; this.worker.postMessage({ jobId, job, data }); }); diff --git a/src/js/core/buffer_utils.js b/src/js/core/buffer_utils.js index 3c087d1b..228560bc 100644 --- a/src/js/core/buffer_utils.js +++ b/src/js/core/buffer_utils.js @@ -1,5 +1,4 @@ import { globalConfig } from "./config"; -import { Math_max, Math_floor, Math_abs } from "./builtins"; import { fastArrayDelete } from "./utils"; import { createLogger } from "./logging"; @@ -70,8 +69,8 @@ export function makeOffscreenBuffer(w, h, { smooth = true, reusable = true, labe } if (w < 1 || h < 1) { logger.error("Offscreen buffer size < 0:", w, "x", h); - w = Math_max(1, w); - h = Math_max(1, h); + w = Math.max(1, w); + h = Math.max(1, h); } const recommendedSize = 1024 * 1024; @@ -79,8 +78,8 @@ export function makeOffscreenBuffer(w, h, { smooth = true, reusable = true, labe logger.warn("Creating huge buffer:", w, "x", h, "with label", label); } - w = Math_floor(w); - h = Math_floor(h); + w = Math.floor(w); + h = Math.floor(h); let canvas = null; let context = null; @@ -103,7 +102,7 @@ export function makeOffscreenBuffer(w, h, { smooth = true, reusable = true, labe } const otherPixels = useableCanvas.width * useableCanvas.height; - const diff = Math_abs(otherPixels - currentPixels); + const diff = Math.abs(otherPixels - currentPixels); if (diff < bestMatchingPixelsDiff) { bestMatchingPixelsDiff = diff; bestMatchingOne = { diff --git a/src/js/core/builtins.js b/src/js/core/builtins.js deleted file mode 100644 index 77f40b77..00000000 --- a/src/js/core/builtins.js +++ /dev/null @@ -1,34 +0,0 @@ -// Store the original version of all builtins to prevent modification - -export const JSON_stringify = JSON.stringify.bind(JSON); -export const JSON_parse = JSON.parse.bind(JSON); - -export function Math_radians(degrees) { - return (degrees * Math_PI) / 180.0; -} - -export function Math_degrees(radians) { - return (radians * 180.0) / Math_PI; -} - -export const performanceNow = performance.now.bind(performance); - -export const Math_abs = Math.abs.bind(Math); -export const Math_ceil = Math.ceil.bind(Math); -export const Math_floor = Math.floor.bind(Math); -export const Math_round = Math.round.bind(Math); -export const Math_sign = Math.sign.bind(Math); -export const Math_sqrt = Math.sqrt.bind(Math); -export const Math_min = Math.min.bind(Math); -export const Math_max = Math.max.bind(Math); -export const Math_sin = Math.sin.bind(Math); -export const Math_cos = Math.cos.bind(Math); -export const Math_tan = Math.tan.bind(Math); -export const Math_hypot = Math.hypot.bind(Math); -export const Math_atan2 = Math.atan2.bind(Math); -export const Math_pow = Math.pow.bind(Math); -export const Math_random = Math.random.bind(Math); -export const Math_exp = Math.exp.bind(Math); -export const Math_log10 = Math.log10.bind(Math); - -export const Math_PI = 3.1415926; diff --git a/src/js/core/click_detector.js b/src/js/core/click_detector.js index 508e9375..ea6abf48 100644 --- a/src/js/core/click_detector.js +++ b/src/js/core/click_detector.js @@ -1,4 +1,3 @@ -import { performanceNow } from "../core/builtins"; import { createLogger } from "../core/logging"; import { Signal } from "../core/signal"; import { fastArrayDelete, fastArrayDeleteValueIfContained } from "./utils"; @@ -246,7 +245,7 @@ export class ClickDetector { } if (window.TouchEvent && event instanceof TouchEvent) { - clickDetectorGlobals.lastTouchTime = performanceNow(); + clickDetectorGlobals.lastTouchTime = performance.now(); // console.log("Got touches", event.targetTouches.length, "vs", expectedRemainingTouches); if (event.targetTouches.length !== expectedRemainingTouches) { @@ -255,7 +254,7 @@ export class ClickDetector { } if (event instanceof MouseEvent) { - if (performanceNow() - clickDetectorGlobals.lastTouchTime < 1000.0) { + if (performance.now() - clickDetectorGlobals.lastTouchTime < 1000.0) { return false; } } @@ -340,7 +339,7 @@ export class ClickDetector { // Store where the touch started this.clickDownPosition = position; - this.clickStartTime = performanceNow(); + this.clickStartTime = performance.now(); this.touchstartSimple.dispatch(this.clickDownPosition.x, this.clickDownPosition.y); // If we are not currently within a click, register it diff --git a/src/js/core/config.js b/src/js/core/config.js index 6825e762..e06f9422 100644 --- a/src/js/core/config.js +++ b/src/js/core/config.js @@ -38,22 +38,28 @@ export const globalConfig = { // Production analytics statisticsGraphDpi: 2.5, statisticsGraphSlices: 100, - analyticsSliceDurationSeconds: 10, + analyticsSliceDurationSeconds: G_IS_DEV ? 1 : 10, minimumTickRate: 25, maximumTickRate: 500, // Map mapChunkSize: 16, - mapChunkPrerenderMinZoom: 1.15, + mapChunkPrerenderMinZoom: -1, mapChunkOverviewMinZoom: 0.7, // Belt speeds // NOTICE: Update webpack.production.config too! beltSpeedItemsPerSecond: 2, - itemSpacingOnBelts: 0.8, minerSpeedItemsPerSecond: 0, // COMPUTED + beltItemSpacingByLayer: { + regular: 0.63, + wires: 0.4, + }, + + wiresSpeedItemsPerSecond: 6, + undergroundBeltMaxTilesByTier: [5, 8], buildingSpeeds: { @@ -66,6 +72,7 @@ export const globalConfig = { painterQuad: 1 / 8, mixer: 1 / 5, stacker: 1 / 6, + advancedProcessor: 1 / 3, }, // Zooming diff --git a/src/js/core/config.local.js b/src/js/core/config.local.js index 2060f495..7bf9a002 100644 --- a/src/js/core/config.local.js +++ b/src/js/core/config.local.js @@ -35,7 +35,7 @@ export default { // Unlocks all buildings // allBuildingsUnlocked: true, // ----------------------------------------------------------------------------------- - // Disables cost of bluepirnts + // Disables cost of blueprints // blueprintsNoCost: true, // ----------------------------------------------------------------------------------- // Disables cost of upgrades @@ -78,10 +78,22 @@ export default { // instantMiners: true, // ----------------------------------------------------------------------------------- // When using fastGameEnter, controls whether a new game is started or the last one is resumed - // resumeGameOnFastEnter: false, + // resumeGameOnFastEnter: true, // ----------------------------------------------------------------------------------- // Special option used to render the trailer // renderForTrailer: true, // ----------------------------------------------------------------------------------- + // Whether to render changes + // renderChanges: true, + // ----------------------------------------------------------------------------------- + // Whether to render belt paths + // renderBeltPaths: true, + // ----------------------------------------------------------------------------------- + // Whether to check belt paths + // checkBeltPaths: true, + // ----------------------------------------------------------------------------------- + // Whether to items / s instead of items / m in stats + // detailedStatistics: true, + // ----------------------------------------------------------------------------------- /* dev:end */ }; diff --git a/src/js/core/dpi_manager.js b/src/js/core/dpi_manager.js index 2045a5e0..0388c5f9 100644 --- a/src/js/core/dpi_manager.js +++ b/src/js/core/dpi_manager.js @@ -1,5 +1,4 @@ import { globalConfig } from "../core/config"; -import { Math_ceil, Math_floor, Math_round } from "./builtins"; import { round1Digit, round2Digits } from "./utils"; /** @@ -23,7 +22,7 @@ export function smoothenDpi(dpi) { } else if (dpi < 1) { return round1Digit(dpi); } else { - return round1Digit(Math_round(dpi / 0.5) * 0.5); + return round1Digit(Math.round(dpi / 0.5) * 0.5); } } @@ -59,11 +58,11 @@ export function prepareHighDPIContext(context, smooth = true) { export function resizeHighDPICanvas(canvas, w, h, smooth = true) { const dpi = getDeviceDPI(); - const wNumber = Math_floor(w); - const hNumber = Math_floor(h); + const wNumber = Math.floor(w); + const hNumber = Math.floor(h); - const targetW = Math_floor(wNumber * dpi); - const targetH = Math_floor(hNumber * dpi); + const targetW = Math.floor(wNumber * dpi); + const targetH = Math.floor(hNumber * dpi); if (targetW !== canvas.width || targetH !== canvas.height) { // console.log("Resize Canvas from", canvas.width, canvas.height, "to", targetW, targetH) @@ -82,8 +81,8 @@ export function resizeHighDPICanvas(canvas, w, h, smooth = true) { * @param {number} h */ export function resizeCanvas(canvas, w, h, setStyle = true) { - const actualW = Math_ceil(w); - const actualH = Math_ceil(h); + const actualW = Math.ceil(w); + const actualH = Math.ceil(h); if (actualW !== canvas.width || actualH !== canvas.height) { canvas.width = actualW; canvas.height = actualH; @@ -103,8 +102,8 @@ export function resizeCanvas(canvas, w, h, setStyle = true) { * @param {number} h */ export function resizeCanvasAndClear(canvas, context, w, h) { - const actualW = Math_ceil(w); - const actualH = Math_ceil(h); + const actualW = Math.ceil(w); + const actualH = Math.ceil(h); if (actualW !== canvas.width || actualH !== canvas.height) { canvas.width = actualW; canvas.height = actualH; diff --git a/src/js/core/draw_utils.js b/src/js/core/draw_utils.js index 8057a211..1b37b929 100644 --- a/src/js/core/draw_utils.js +++ b/src/js/core/draw_utils.js @@ -3,7 +3,6 @@ import { AtlasSprite } from "./sprites"; import { DrawParameters } from "./draw_parameters"; /* typehints:end */ -import { Math_PI, Math_round, Math_atan2, Math_hypot, Math_floor } from "./builtins"; import { Vector } from "./vector"; import { Rectangle } from "./rectangle"; import { createLogger } from "./logging"; @@ -40,7 +39,7 @@ export function initDrawUtils() { return; } this.beginPath(); - this.arc(x, y, r, 0, 2.0 * Math_PI); + this.arc(x, y, r, 0, 2.0 * Math.PI); }; } @@ -68,8 +67,8 @@ export function drawLineFast(context, { x1, x2, y1, y2, color = null, lineSize = const dX = x2 - x1; const dY = y2 - y1; - const angle = Math_atan2(dY, dX) + 0.0 * Math_PI; - const len = Math_hypot(dX, dY); + const angle = Math.atan2(dY, dX) + 0.0 * Math.PI; + const len = Math.hypot(dX, dY); context.translate(x1, y1); context.rotate(angle); @@ -247,7 +246,7 @@ export function hslToRgb(h, s, l) { b = hue2rgb(p, q, h - 1 / 3); } - return [Math_round(r * 255), Math_round(g * 255), Math_round(b * 255)]; + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; } export function wrapText(context, text, x, y, maxWidth, lineHeight, stroke = false) { @@ -306,7 +305,7 @@ export function rotateTrapezRightFaced(x, y, w, h, leftHeight, angle) { */ export function mapClampedColorValueToHex(value) { const hex = "0123456789abcdef"; - return hex[Math_floor(value / 16)] + hex[value % 16]; + return hex[Math.floor(value / 16)] + hex[value % 16]; } /** diff --git a/src/js/core/error_handler.js b/src/js/core/error_handler.js index bcb6fcf4..686e4e4e 100644 --- a/src/js/core/error_handler.js +++ b/src/js/core/error_handler.js @@ -48,7 +48,7 @@ function catchErrors(message, source, lineno, colno, error) { console.log("\n\n⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️\n\n\n"); logSection("APPLICATION CRASH", "#e53935"); - console.log("Error:", message, "->", error); + console.error("Error:", message, "->", error); console.log("Payload:", fullPayload); if (window.Sentry && !window.anyModLoaded) { diff --git a/src/js/core/game_state.js b/src/js/core/game_state.js index cd3cb677..cee962f5 100644 --- a/src/js/core/game_state.js +++ b/src/js/core/game_state.js @@ -134,8 +134,6 @@ export class GameState { */ cancelAllAsyncOperations() { this.asyncChannel.cancelAll(); - // TODO - // this.app.api.cancelRequests(); } //// CALLBACKS //// diff --git a/src/js/core/logging.js b/src/js/core/logging.js index 20786241..f3e938e5 100644 --- a/src/js/core/logging.js +++ b/src/js/core/logging.js @@ -1,6 +1,4 @@ import { globalConfig } from "../core/config"; -import { Math_floor, performanceNow } from "./builtins"; - const circularJson = require("circular-json"); /* @@ -231,7 +229,7 @@ function logInternal(handle, consoleMethod, args) { const labelColor = handle && handle.LOG_LABEL_COLOR ? handle.LOG_LABEL_COLOR : "#aaa"; if (G_IS_DEV && globalConfig.debug.logTimestamps) { - const timestamp = "⏱ %c" + (Math_floor(performanceNow()) + "").padEnd(6, " ") + ""; + const timestamp = "⏱ %c" + (Math.floor(performance.now()) + "").padEnd(6, " ") + ""; consoleMethod.call( console, timestamp + " %c" + context, diff --git a/src/js/core/modal_dialog_elements.js b/src/js/core/modal_dialog_elements.js index 0902a193..8252487a 100644 --- a/src/js/core/modal_dialog_elements.js +++ b/src/js/core/modal_dialog_elements.js @@ -365,10 +365,12 @@ export class DialogWithForm extends Dialog { * @param {Application} param0.app * @param {string} param0.title * @param {string} param0.desc - * @param {string=} param0.confirmButton + * @param {array=} param0.buttons + * @param {string=} param0.confirmButtonId + * @param {string=} param0.extraButton * @param {Array} param0.formElements */ - constructor({ app, title, desc, formElements, confirmButton = "ok:good" }) { + constructor({ app, title, desc, formElements, buttons = ["cancel", "ok:good"], confirmButtonId = "ok" }) { let html = ""; html += desc + "
"; for (let i = 0; i < formElements.length; ++i) { @@ -379,14 +381,14 @@ export class DialogWithForm extends Dialog { app, title: title, contentHTML: html, - buttons: ["cancel:bad", confirmButton], + buttons: buttons, type: "info", closeButton: true, }); - this.confirmButtonId = confirmButton.split(":")[0]; + this.confirmButtonId = confirmButtonId; this.formElements = formElements; - this.enterHandler = "ok"; + this.enterHandler = confirmButtonId; } internalButtonHandler(id, ...payload) { diff --git a/src/js/core/modal_dialog_forms.js b/src/js/core/modal_dialog_forms.js index 4d1c9f97..1ded9a8b 100644 --- a/src/js/core/modal_dialog_forms.js +++ b/src/js/core/modal_dialog_forms.js @@ -19,7 +19,7 @@ export class FormElement { abstract; } - focus(parent) {} + focus() {} isValid() { return true; diff --git a/src/js/core/polyfills.js b/src/js/core/polyfills.js index e5efca1d..8f6f8ffe 100644 --- a/src/js/core/polyfills.js +++ b/src/js/core/polyfills.js @@ -1,12 +1,12 @@ function mathPolyfills() { // Converts from degrees to radians. Math.radians = function (degrees) { - return (degrees * Math_PI) / 180.0; + return (degrees * Math.PI) / 180.0; }; // Converts from radians to degrees. Math.degrees = function (radians) { - return (radians * 180.0) / Math_PI; + return (radians * 180.0) / Math.PI; }; } @@ -72,6 +72,7 @@ function objectPolyfills() { } if (!Object.entries) { + // @ts-ignore Object.entries = function entries(O) { return reduce( keys(O), @@ -97,8 +98,6 @@ function initExtensions() { // Fetch polyfill import "whatwg-fetch"; -import { Math_PI } from "./builtins"; - // Other polyfills initPolyfills(); initExtensions(); diff --git a/src/js/core/query_parameters.js b/src/js/core/query_parameters.js index 8a27801f..7837acb5 100644 --- a/src/js/core/query_parameters.js +++ b/src/js/core/query_parameters.js @@ -4,6 +4,7 @@ const options = queryString.parse(location.search); export let queryParamOptions = { embedProvider: null, fullVersion: false, + sandboxMode: false, }; if (options.embed) { @@ -14,3 +15,8 @@ if (options.embed) { if (options.fullVersion && !G_IS_RELEASE) { queryParamOptions.fullVersion = true; } + +// Allow testing full version outside of standalone +if (options.sandboxMode && !G_IS_RELEASE) { + queryParamOptions.sandboxMode = true; +} diff --git a/src/js/core/read_write_proxy.js b/src/js/core/read_write_proxy.js index ee568dc6..5474467a 100644 --- a/src/js/core/read_write_proxy.js +++ b/src/js/core/read_write_proxy.js @@ -7,7 +7,6 @@ import { createLogger } from "./logging"; import { FILE_NOT_FOUND } from "../platform/storage"; import { accessNestedPropertyReverse } from "./utils"; import { IS_DEBUG, globalConfig } from "./config"; -import { JSON_stringify, JSON_parse } from "./builtins"; import { ExplainedResult } from "./explained_result"; import { decompressX64, compressX64 } from ".//lzstring"; import { asyncCompressor, compressionPrefix } from "./async_compression"; @@ -84,7 +83,7 @@ export class ReadWriteProxy { * @param {object} obj */ static serializeObject(obj) { - const jsonString = JSON_stringify(compressObject(obj)); + const jsonString = JSON.stringify(compressObject(obj)); const checksum = sha1(jsonString + salt); return compressionPrefix + compressX64(checksum + jsonString); } @@ -129,7 +128,7 @@ export class ReadWriteProxy { logger.error("Tried to write invalid data to", this.filename, "reason:", verifyResult.reason); return Promise.reject(verifyResult.reason); } - const jsonString = JSON_stringify(compressObject(this.currentData)); + const jsonString = JSON.stringify(compressObject(this.currentData)); // if (!this.app.pageVisible || this.app.unloaded) { // logger.log("Saving file sync because in unload handler"); @@ -189,7 +188,7 @@ export class ReadWriteProxy { .then(rawData => { if (rawData == null) { // So, the file has not been found, use default data - return JSON_stringify(compressObject(this.getDefaultData())); + return JSON.stringify(compressObject(this.getDefaultData())); } if (rawData.startsWith(compressionPrefix)) { @@ -223,7 +222,7 @@ export class ReadWriteProxy { // Parse JSON, this could throw but thats fine .then(res => { try { - return JSON_parse(res); + return JSON.parse(res); } catch (ex) { logger.error( "Failed to parse file content of", diff --git a/src/js/core/rectangle.js b/src/js/core/rectangle.js index 79136b9f..75279e58 100644 --- a/src/js/core/rectangle.js +++ b/src/js/core/rectangle.js @@ -1,5 +1,4 @@ import { globalConfig } from "./config"; -import { Math_ceil, Math_floor, Math_max, Math_min } from "./builtins"; import { clamp, epsilonCompare, round2Digits } from "./utils"; import { Vector } from "./vector"; @@ -38,10 +37,10 @@ export class Rectangle { * @param {Vector} p2 */ static fromTwoPoints(p1, p2) { - const left = Math_min(p1.x, p2.x); - const top = Math_min(p1.y, p2.y); - const right = Math_max(p1.x, p2.x); - const bottom = Math_max(p1.y, p2.y); + const left = Math.min(p1.x, p2.x); + const top = Math.min(p1.y, p2.y); + const right = Math.max(p1.x, p2.x); + const bottom = Math.max(p1.y, p2.y); return new Rectangle(left, top, right - left, bottom - top); } @@ -67,10 +66,10 @@ export class Rectangle { let maxY = -1e10; for (let i = 0; i < points.length; ++i) { const rotated = points[i].rotated(angle); - minX = Math_min(minX, rotated.x); - minY = Math_min(minY, rotated.y); - maxX = Math_max(maxX, rotated.x); - maxY = Math_max(maxY, rotated.y); + minX = Math.min(minX, rotated.x); + minY = Math.min(minY, rotated.y); + maxX = Math.max(maxX, rotated.x); + maxY = Math.max(maxY, rotated.y); } return new Rectangle(minX, minY, maxX - minX, maxY - minY); } @@ -98,10 +97,10 @@ export class Rectangle { this.w = halfWidth * 2; this.h = halfHeight * 2; } else { - this.setLeft(Math_min(this.x, centerX - halfWidth)); - this.setRight(Math_max(this.right(), centerX + halfWidth)); - this.setTop(Math_min(this.y, centerY - halfHeight)); - this.setBottom(Math_max(this.bottom(), centerY + halfHeight)); + this.setLeft(Math.min(this.x, centerX - halfWidth)); + this.setRight(Math.max(this.right(), centerX + halfWidth)); + this.setTop(Math.min(this.y, centerY - halfHeight)); + this.setBottom(Math.max(this.bottom(), centerY + halfHeight)); } } @@ -326,11 +325,11 @@ export class Rectangle { * @returns {Rectangle|null} */ getIntersection(rect) { - const left = Math_max(this.x, rect.x); - const top = Math_max(this.y, rect.y); + const left = Math.max(this.x, rect.x); + const top = Math.max(this.y, rect.y); - const right = Math_min(this.x + this.w, rect.x + rect.w); - const bottom = Math_min(this.y + this.h, rect.y + rect.h); + const right = Math.min(this.x + this.w, rect.x + rect.w); + const bottom = Math.min(this.y + this.h, rect.y + rect.h); if (right <= left || bottom <= top) { return null; @@ -354,10 +353,10 @@ export class Rectangle { } // Find contained area - const left = Math_min(this.x, rect.x); - const top = Math_min(this.y, rect.y); - const right = Math_max(this.right(), rect.right()); - const bottom = Math_max(this.bottom(), rect.bottom()); + const left = Math.min(this.x, rect.x); + const top = Math.min(this.y, rect.y); + const right = Math.max(this.right(), rect.right()); + const bottom = Math.max(this.bottom(), rect.bottom()); return Rectangle.fromTRBL(top, right, bottom, left); } @@ -388,10 +387,10 @@ export class Rectangle { if (includeHalfTiles) { // Increase rectangle size scaled = Rectangle.fromTRBL( - Math_floor(scaled.y), - Math_ceil(scaled.right()), - Math_ceil(scaled.bottom()), - Math_floor(scaled.x) + Math.floor(scaled.y), + Math.ceil(scaled.right()), + Math.ceil(scaled.bottom()), + Math.floor(scaled.x) ); } diff --git a/src/js/core/rng.js b/src/js/core/rng.js index 3322aafa..9c5c1c43 100644 --- a/src/js/core/rng.js +++ b/src/js/core/rng.js @@ -1,5 +1,3 @@ -import { Math_random } from "./builtins"; - // ALEA RNG function Mash() { @@ -72,7 +70,7 @@ export class RandomNumberGenerator { * @param {number|string=} seed */ constructor(seed) { - this.internalRng = makeNewRng(seed || Math_random()); + this.internalRng = makeNewRng(seed || Math.random()); } /** @@ -80,7 +78,7 @@ export class RandomNumberGenerator { * @param {number|string} seed */ reseed(seed) { - this.internalRng = makeNewRng(seed || Math_random()); + this.internalRng = makeNewRng(seed || Math.random()); } /** diff --git a/src/js/core/sprites.js b/src/js/core/sprites.js index 4251bee1..26cd65b2 100644 --- a/src/js/core/sprites.js +++ b/src/js/core/sprites.js @@ -1,5 +1,4 @@ import { DrawParameters } from "./draw_parameters"; -import { Math_floor } from "./builtins"; import { Rectangle } from "./rectangle"; import { epsilonCompare, round3Digits } from "./utils"; @@ -89,6 +88,11 @@ export class AtlasSprite extends BaseSprite { const link = this.linksByResolution[ORIGINAL_SCALE]; + assert( + link, + "Link not known: " + ORIGINAL_SCALE + " (having " + Object.keys(this.linksByResolution) + ")" + ); + const width = w || link.w; const height = h || link.h; @@ -144,15 +148,18 @@ export class AtlasSprite extends BaseSprite { */ drawCached(parameters, x, y, w = null, h = null, clipping = true) { if (G_IS_DEV) { - assertAlways(parameters instanceof DrawParameters, "Not a valid context"); - assertAlways(!!w && w > 0, "Not a valid width:" + w); - assertAlways(!!h && h > 0, "Not a valid height:" + h); + assert(parameters instanceof DrawParameters, "Not a valid context"); + assert(!!w && w > 0, "Not a valid width:" + w); + assert(!!h && h > 0, "Not a valid height:" + h); } const visibleRect = parameters.visibleRect; const scale = parameters.desiredAtlasScale; const link = this.linksByResolution[scale]; + + assert(link, "Link not known: " + scale + " (having " + Object.keys(this.linksByResolution) + ")"); + const scaleW = w / link.w; const scaleH = h / link.h; @@ -195,20 +202,20 @@ export class AtlasSprite extends BaseSprite { link.atlas, // atlas src pos - Math_floor(srcX), - Math_floor(srcY), + Math.floor(srcX), + Math.floor(srcY), // atlas src size - Math_floor(srcW), - Math_floor(srcH), + Math.floor(srcW), + Math.floor(srcH), // dest pos - Math_floor(destX), - Math_floor(destY), + Math.floor(destX), + Math.floor(destY), // dest size - Math_floor(destW), - Math_floor(destH) + Math.floor(destW), + Math.floor(destH) ); } else { parameters.context.drawImage( diff --git a/src/js/core/utils.js b/src/js/core/utils.js index 23368317..cb00e465 100644 --- a/src/js/core/utils.js +++ b/src/js/core/utils.js @@ -1,19 +1,4 @@ import { globalConfig, IS_DEBUG } from "./config"; -import { - Math_abs, - Math_atan2, - Math_ceil, - Math_floor, - Math_log10, - Math_max, - Math_min, - Math_PI, - Math_pow, - Math_random, - Math_round, - Math_sin, - performanceNow, -} from "./builtins"; import { Vector } from "./vector"; import { T } from "../translations"; @@ -212,7 +197,7 @@ export function newEmptyMap() { * @param {number} end */ export function randomInt(start, end) { - return start + Math_round(Math_random() * (end - start)); + return start + Math.round(Math.random() * (end - start)); } /** @@ -233,7 +218,7 @@ export function accessNestedPropertyReverse(obj, keys) { * @param {Array | string} arr */ export function randomChoice(arr) { - return arr[Math_floor(Math_random() * arr.length)]; + return arr[Math.floor(Math.random() * arr.length)]; } /** @@ -327,12 +312,12 @@ export function arrayDeleteValue(array, value) { * @returns {number} in range [0, 7] */ export function angleToSpriteIndex(offset, inverse = false) { - const twoPi = 2.0 * Math_PI; + const twoPi = 2.0 * Math.PI; const factor = inverse ? -1 : 1; const offs = inverse ? 2.5 : 3.5; - const angle = (factor * Math_atan2(offset.y, offset.x) + offs * Math_PI) % twoPi; + const angle = (factor * Math.atan2(offset.y, offset.x) + offs * Math.PI) % twoPi; - const index = Math_round((angle / twoPi) * 8) % 8; + const index = Math.round((angle / twoPi) * 8) % 8; return index; } @@ -343,7 +328,7 @@ export function angleToSpriteIndex(offset, inverse = false) { * @returns {boolean} */ export function epsilonCompare(a, b, epsilon = 1e-5) { - return Math_abs(a - b) < epsilon; + return Math.abs(a - b) < epsilon; } /** @@ -394,26 +379,24 @@ export function findNiceValue(num) { roundAmount = 5; } - const niceValue = Math_floor(num / roundAmount) * roundAmount; + const niceValue = Math.floor(num / roundAmount) * roundAmount; if (num >= 10) { - return Math_round(niceValue); + return Math.round(niceValue); } if (num >= 1) { - return Math_round(niceValue * 10) / 10; + return Math.round(niceValue * 10) / 10; } - return Math_round(niceValue * 100) / 100; + return Math.round(niceValue * 100) / 100; } -window.fn = findNiceValue; - /** * Finds a nice integer value * @see findNiceValue * @param {number} num */ export function findNiceIntegerValue(num) { - return Math_ceil(findNiceValue(num)); + return Math.ceil(findNiceValue(num)); } /** @@ -424,18 +407,18 @@ function roundSmart(n) { if (n < 100) { return n.toFixed(1); } - return Math_round(n); + return Math.round(n); } /** * Formats a big number * @param {number} num - * @param {string=} divider THe divider for numbers like 50,000 (divider=',') + * @param {string=} separator The decimal separator for numbers like 50.1 (separator='.') * @returns {string} */ -export function formatBigNumber(num, divider = ".") { +export function formatBigNumber(num, separator = T.global.decimalSeparator) { const sign = num < 0 ? "-" : ""; - num = Math_abs(num); + num = Math.abs(num); if (num > 1e54) { return sign + T.global.infinite; @@ -447,7 +430,7 @@ export function formatBigNumber(num, divider = ".") { if (num < 50 && !Number.isInteger(num)) { return sign + num.toFixed(1); } - num = Math_floor(num); + num = Math.floor(num); if (num < 1000) { return sign + "" + num; @@ -462,7 +445,10 @@ export function formatBigNumber(num, divider = ".") { } } const leadingDigitsRounded = round1Digit(leadingDigits); - const leadingDigitsNoTrailingDecimal = leadingDigitsRounded.toString().replace(".0", ""); + const leadingDigitsNoTrailingDecimal = leadingDigitsRounded + .toString() + .replace(".0", "") + .replace(".", separator); return sign + leadingDigitsNoTrailingDecimal + suffix; } } @@ -470,7 +456,7 @@ export function formatBigNumber(num, divider = ".") { /** * Formats a big number, but does not add any suffix and instead uses its full representation * @param {number} num - * @param {string=} divider THe divider for numbers like 50,000 (divider=',') + * @param {string=} divider The divider for numbers like 50,000 (divider=',') * @returns {string} */ export function formatBigNumberFull(num, divider = T.global.thousandsDivider) { @@ -484,7 +470,7 @@ export function formatBigNumberFull(num, divider = T.global.thousandsDivider) { let out = ""; while (rest >= 1000) { out = (rest % 1000).toString().padStart(3, "0") + divider + out; - rest = Math_floor(rest / 1000); + rest = Math.floor(rest / 1000); } out = rest + divider + out; @@ -502,11 +488,11 @@ export function artificialDelayedPromise(promise, minTimeMs = 500) { return promise; } - const startTime = performanceNow(); + const startTime = performance.now(); return promise.then( result => { - const timeTaken = performanceNow() - startTime; - const waitTime = Math_floor(minTimeMs - timeTaken); + const timeTaken = performance.now() - startTime; + const waitTime = Math.floor(minTimeMs - timeTaken); if (waitTime > 0) { return new Promise(resolve => { setTimeout(() => { @@ -518,8 +504,8 @@ export function artificialDelayedPromise(promise, minTimeMs = 500) { } }, error => { - const timeTaken = performanceNow() - startTime; - const waitTime = Math_floor(minTimeMs - timeTaken); + const timeTaken = performance.now() - startTime; + const waitTime = Math.floor(minTimeMs - timeTaken); if (waitTime > 0) { // @ts-ignore return new Promise((resolve, reject) => { @@ -541,7 +527,7 @@ export function artificialDelayedPromise(promise, minTimeMs = 500) { * @param {number} seed Seed to offset the animation */ export function pulseAnimation(time, duration = 1.0, seed = 0.0) { - return Math_sin((time * Math_PI * 2.0) / duration + seed * 5642.86729349) * 0.5 + 0.5; + return Math.sin((time * Math.PI * 2.0) / duration + seed * 5642.86729349) * 0.5 + 0.5; } /** @@ -551,7 +537,7 @@ export function pulseAnimation(time, duration = 1.0, seed = 0.0) { * @returns {number} 0 .. 2 PI */ export function smallestAngle(a, b) { - return safeMod(a - b + Math_PI, 2.0 * Math_PI) - Math_PI; + return safeMod(a - b + Math.PI, 2.0 * Math.PI) - Math.PI; } /** @@ -568,7 +554,7 @@ export function safeMod(n, m) { * @param {number} angle */ export function wrapAngle(angle) { - return safeMod(angle, 2.0 * Math_PI); + return safeMod(angle, 2.0 * Math.PI); } /** @@ -591,7 +577,7 @@ export function waitNextFrame() { * @returns {number} */ export function round1Digit(n) { - return Math_floor(n * 10.0) / 10.0; + return Math.floor(n * 10.0) / 10.0; } /** @@ -600,7 +586,7 @@ export function round1Digit(n) { * @returns {number} */ export function round2Digits(n) { - return Math_floor(n * 100.0) / 100.0; + return Math.floor(n * 100.0) / 100.0; } /** @@ -609,7 +595,7 @@ export function round2Digits(n) { * @returns {number} */ export function round3Digits(n) { - return Math_floor(n * 1000.0) / 1000.0; + return Math.floor(n * 1000.0) / 1000.0; } /** @@ -618,7 +604,7 @@ export function round3Digits(n) { * @returns {number} */ export function round4Digits(n) { - return Math_floor(n * 10000.0) / 10000.0; + return Math.floor(n * 10000.0) / 10000.0; } /** @@ -628,7 +614,7 @@ export function round4Digits(n) { * @param {number=} maximum Default 1 */ export function clamp(v, minimum = 0, maximum = 1) { - return Math_max(minimum, Math_min(maximum, v)); + return Math.max(minimum, Math.min(maximum, v)); } /** @@ -637,11 +623,11 @@ export function clamp(v, minimum = 0, maximum = 1) { * @param {function():void} target */ export function measure(name, target) { - const now = performanceNow(); + const now = performance.now(); for (let i = 0; i < 25; ++i) { target(); } - const dur = (performanceNow() - now) / 25.0; + const dur = (performance.now() - now) / 25.0; console.warn("->", name, "took", dur.toFixed(2), "ms"); } @@ -891,28 +877,28 @@ export function fastRotateMultipleOf90(x, y, deg) { * @returns {string} */ export function formatSecondsToTimeAgo(secs) { - const seconds = Math_floor(secs); - const minutes = Math_floor(seconds / 60); - const hours = Math_floor(minutes / 60); - const days = Math_floor(hours / 24); + const seconds = Math.floor(secs); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); - if (seconds <= 60) { - if (seconds <= 1) { + if (seconds < 60) { + if (seconds === 1) { return T.global.time.oneSecondAgo; } return T.global.time.xSecondsAgo.replace("", "" + seconds); - } else if (minutes <= 60) { - if (minutes <= 1) { + } else if (minutes < 60) { + if (minutes === 1) { return T.global.time.oneMinuteAgo; } return T.global.time.xMinutesAgo.replace("", "" + minutes); - } else if (hours <= 60) { - if (hours <= 1) { + } else if (hours < 24) { + if (hours === 1) { return T.global.time.oneHourAgo; } return T.global.time.xHoursAgo.replace("", "" + hours); } else { - if (days <= 1) { + if (days === 1) { return T.global.time.oneDayAgo; } return T.global.time.xDaysAgo.replace("", "" + days); @@ -926,18 +912,18 @@ export function formatSecondsToTimeAgo(secs) { */ export function formatSeconds(secs) { const trans = T.global.time; - secs = Math_ceil(secs); + secs = Math.ceil(secs); if (secs < 60) { return trans.secondsShort.replace("", "" + secs); } else if (secs < 60 * 60) { - const minutes = Math_floor(secs / 60); + const minutes = Math.floor(secs / 60); const seconds = secs % 60; return trans.minutesAndSecondsShort .replace("", "" + seconds) .replace("", "" + minutes); } else { - const hours = Math_floor(secs / 3600); - const minutes = Math_floor(secs / 60) % 60; + const hours = Math.floor(secs / 3600); + const minutes = Math.floor(secs / 60) % 60; return trans.hoursAndMinutesShort.replace("", "" + minutes).replace("", "" + hours); } } @@ -971,10 +957,13 @@ export function capitalizeFirstLetter(str) { * Formats a number like 2.5 to "2.5 items / s" * @param {number} speed * @param {boolean=} double + * @param {string=} separator The decimal separator for numbers like 50.1 (separator='.') */ -export function formatItemsPerSecond(speed, double = false) { +export function formatItemsPerSecond(speed, double = false, separator = T.global.decimalSeparator) { return speed === 1.0 ? T.ingame.buildingPlacement.infoTexts.oneItemPerSecond - : T.ingame.buildingPlacement.infoTexts.itemsPerSecond.replace("", "" + round2Digits(speed)) + - (double ? " " + T.ingame.buildingPlacement.infoTexts.itemsPerSecondDouble : ""); + : T.ingame.buildingPlacement.infoTexts.itemsPerSecond.replace( + "", + round2Digits(speed).toString().replace(".", separator) + ) + (double ? " " + T.ingame.buildingPlacement.infoTexts.itemsPerSecondDouble : ""); } diff --git a/src/js/core/vector.js b/src/js/core/vector.js index 635556d6..b0a2d3fa 100644 --- a/src/js/core/vector.js +++ b/src/js/core/vector.js @@ -1,17 +1,4 @@ import { globalConfig } from "./config"; -import { - Math_abs, - Math_floor, - Math_PI, - Math_max, - Math_min, - Math_round, - Math_hypot, - Math_atan2, - Math_sin, - Math_cos, - Math_ceil, -} from "./builtins"; const tileSize = globalConfig.tileSize; const halfTileSize = globalConfig.halfTileSize; @@ -158,7 +145,7 @@ export class Vector { * @returns {number} */ length() { - return Math_hypot(this.x, this.y); + return Math.hypot(this.x, this.y); } /** @@ -226,7 +213,7 @@ export class Vector { * @returns {Vector} */ maxScalar(f) { - return new Vector(Math_max(f, this.x), Math_max(f, this.y)); + return new Vector(Math.max(f, this.x), Math.max(f, this.y)); } /** @@ -244,7 +231,7 @@ export class Vector { * @returns {Vector} */ min(v) { - return new Vector(Math_min(v.x, this.x), Math_min(v.y, this.y)); + return new Vector(Math.min(v.x, this.x), Math.min(v.y, this.y)); } /** @@ -253,14 +240,14 @@ export class Vector { * @returns {Vector} */ max(v) { - return new Vector(Math_max(v.x, this.x), Math_max(v.y, this.y)); + return new Vector(Math.max(v.x, this.x), Math.max(v.y, this.y)); } /** * Computes the component wise absolute * @returns {Vector} */ abs() { - return new Vector(Math_abs(this.x), Math_abs(this.y)); + return new Vector(Math.abs(this.x), Math.abs(this.y)); } /** @@ -278,7 +265,7 @@ export class Vector { * @returns {number} */ distance(v) { - return Math_hypot(this.x - v.x, this.y - v.y); + return Math.hypot(this.x - v.x, this.y - v.y); } /** @@ -308,7 +295,7 @@ export class Vector { * @returns {Vector} */ floor() { - return new Vector(Math_floor(this.x), Math_floor(this.y)); + return new Vector(Math.floor(this.x), Math.floor(this.y)); } /** @@ -316,7 +303,7 @@ export class Vector { * @returns {Vector} */ ceil() { - return new Vector(Math_ceil(this.x), Math_ceil(this.y)); + return new Vector(Math.ceil(this.x), Math.ceil(this.y)); } /** @@ -324,7 +311,7 @@ export class Vector { * @returns {Vector} */ round() { - return new Vector(Math_round(this.x), Math_round(this.y)); + return new Vector(Math.round(this.x), Math.round(this.y)); } /** @@ -332,7 +319,7 @@ export class Vector { * @returns {Vector} */ toTileSpace() { - return new Vector(Math_floor(this.x / tileSize), Math_floor(this.y / tileSize)); + return new Vector(Math.floor(this.x / tileSize), Math.floor(this.y / tileSize)); } /** @@ -340,7 +327,7 @@ export class Vector { * @returns {Vector} */ toStreetSpace() { - return new Vector(Math_floor(this.x / halfTileSize + 0.25), Math_floor(this.y / halfTileSize + 0.25)); + return new Vector(Math.floor(this.x / halfTileSize + 0.25), Math.floor(this.y / halfTileSize + 0.25)); } /** @@ -364,7 +351,7 @@ export class Vector { * @returns {Vector} */ snapWorldToTile() { - return new Vector(Math_floor(this.x / tileSize) * tileSize, Math_floor(this.y / tileSize) * tileSize); + return new Vector(Math.floor(this.x / tileSize) * tileSize, Math.floor(this.y / tileSize) * tileSize); } /** @@ -372,7 +359,7 @@ export class Vector { * @returns {Vector} */ normalize() { - const len = Math_max(1e-5, Math_hypot(this.x, this.y)); + const len = Math.max(1e-5, Math.hypot(this.x, this.y)); return new Vector(this.x / len, this.y / len); } @@ -381,7 +368,7 @@ export class Vector { * @returns {Vector} */ normalizeIfGreaterOne() { - const len = Math_max(1, Math_hypot(this.x, this.y)); + const len = Math.max(1, Math.hypot(this.x, this.y)); return new Vector(this.x / len, this.y / len); } @@ -393,7 +380,7 @@ export class Vector { normalizedDirection(v) { const dx = v.x - this.x; const dy = v.y - this.y; - const len = Math_max(1e-5, Math_hypot(dx, dy)); + const len = Math.max(1e-5, Math.hypot(dx, dy)); return new Vector(dx / len, dy / len); } @@ -437,8 +424,8 @@ export class Vector { * @returns {Vector} new vector */ rotated(angle) { - const sin = Math_sin(angle); - const cos = Math_cos(angle); + const sin = Math.sin(angle); + const cos = Math.cos(angle); return new Vector(this.x * cos - this.y * sin, this.x * sin + this.y * cos); } @@ -448,8 +435,8 @@ export class Vector { * @returns {Vector} this vector */ rotateInplaceFastMultipleOf90(angle) { - // const sin = Math_sin(angle); - // const cos = Math_cos(angle); + // const sin = Math.sin(angle); + // const cos = Math.cos(angle); // let sin = 0, cos = 1; assert(angle >= 0 && angle <= 360, "Invalid angle, please clamp first: " + angle); @@ -598,7 +585,7 @@ export class Vector { * @returns {Boolean} */ equalsEpsilon(v, epsilon = 1e-5) { - return Math_abs(this.x - v.x) < 1e-5 && Math_abs(this.y - v.y) < epsilon; + return Math.abs(this.x - v.x) < 1e-5 && Math.abs(this.y - v.y) < epsilon; } /** @@ -606,7 +593,7 @@ export class Vector { * @returns {number} 0 .. 2 PI */ angle() { - return Math_atan2(this.y, this.x) + Math_PI / 2; + return Math.atan2(this.y, this.x) + Math.PI / 2; } /** @@ -638,7 +625,7 @@ export class Vector { */ static deserializeTileFromInt(i) { const x = i % 256; - const y = Math_floor(i / 256); + const y = Math.floor(i / 256); return new Vector(x, y); } diff --git a/src/js/game/automatic_save.js b/src/js/game/automatic_save.js index 1b3f13ca..e32b9b62 100644 --- a/src/js/game/automatic_save.js +++ b/src/js/game/automatic_save.js @@ -1,6 +1,5 @@ import { GameRoot } from "./root"; import { globalConfig, IS_DEBUG } from "../core/config"; -import { Math_max } from "../core/builtins"; import { createLogger } from "../core/logging"; // How important it is that a savegame is created @@ -29,7 +28,7 @@ export class AutomaticSave { } setSaveImportance(importance) { - this.saveImportance = Math_max(this.saveImportance, importance); + this.saveImportance = Math.max(this.saveImportance, importance); } doSave() { @@ -54,7 +53,7 @@ export class AutomaticSave { } // Check when the last save was, but make sure that if it fails, we don't spam - const lastSaveTime = Math_max(this.lastSaveAttempt, this.root.savegame.getRealLastUpdate()); + const lastSaveTime = Math.max(this.lastSaveAttempt, this.root.savegame.getRealLastUpdate()); const secondsSinceLastSave = (Date.now() - lastSaveTime) / 1000.0; let shouldSave = false; diff --git a/src/js/game/base_item.js b/src/js/game/base_item.js index e70263df..d0da5fa1 100644 --- a/src/js/game/base_item.js +++ b/src/js/game/base_item.js @@ -1,6 +1,26 @@ import { DrawParameters } from "../core/draw_parameters"; -import { BasicSerializableObject, types } from "../savegame/serialization"; -import { THEME } from "./theme"; +import { BasicSerializableObject } from "../savegame/serialization"; +import { enumLayer } from "./root"; + +/** @enum {string} */ +export const enumItemType = { + shape: "shape", + color: "color", + positiveEnergy: "positiveEnergy", + negativeEnergy: "negativeEnergy", + + // Can be used for filters + genericEnergy: "genericEnergy", +}; + +/** @enum {enumLayer} */ +export const enumItemTypeToLayer = { + [enumItemType.shape]: enumLayer.regular, + [enumItemType.color]: enumLayer.regular, + [enumItemType.positiveEnergy]: enumLayer.wires, + [enumItemType.negativeEnergy]: enumLayer.wires, + [enumItemType.genericEnergy]: enumLayer.wires, +}; /** * Class for items on belts etc. Not an entity for performance reasons @@ -19,6 +39,12 @@ export class BaseItem extends BasicSerializableObject { return {}; } + /** @returns {enumItemType} */ + getItemType() { + abstract; + return ""; + } + /** * Draws the item at the given position * @param {number} x diff --git a/src/js/game/belt_path.js b/src/js/game/belt_path.js new file mode 100644 index 00000000..0b6da48c --- /dev/null +++ b/src/js/game/belt_path.js @@ -0,0 +1,1166 @@ +import { globalConfig } from "../core/config"; +import { DrawParameters } from "../core/draw_parameters"; +import { createLogger } from "../core/logging"; +import { epsilonCompare, round4Digits } from "../core/utils"; +import { Vector } from "../core/vector"; +import { BaseItem } from "./base_item"; +import { Entity } from "./entity"; +import { GameRoot, enumLayer } from "./root"; +import { Rectangle } from "../core/rectangle"; +import { BasicSerializableObject, types } from "../savegame/serialization"; +import { gItemRegistry } from "../core/global_registries"; + +const logger = createLogger("belt_path"); + +// Helpers for more semantic access into interleaved arrays +const _nextDistance = 0; +const _item = 1; + +const DEBUG = G_IS_DEV && false; + +/** + * Stores a path of belts, used for optimizing performance + */ +export class BeltPath extends BasicSerializableObject { + static getId() { + return "BeltPath"; + } + + static getSchema() { + return { + entityPath: types.array(types.entity), + items: types.array(types.pair(types.ufloat, types.obj(gItemRegistry))), + spacingToFirstItem: types.ufloat, + }; + } + + /** + * Creates a path from a serialized object + * @param {GameRoot} root + * @param {Object} data + * @returns {BeltPath|string} + */ + static fromSerialized(root, data) { + // Create fake object which looks like a belt path but skips the constructor + const fakeObject = /** @type {BeltPath} */ (Object.create(BeltPath.prototype)); + fakeObject.root = root; + + // Deserialize the data + const errorCodeDeserialize = fakeObject.deserialize(data); + if (errorCodeDeserialize) { + return errorCodeDeserialize; + } + + // Compute other properties + fakeObject.init(false); + + return fakeObject; + } + + /** + * @param {GameRoot} root + * @param {Array} entityPath + */ + constructor(root, entityPath) { + super(); + this.root = root; + + assert(entityPath.length > 0, "invalid entity path"); + this.entityPath = entityPath; + + /** + * Stores the items sorted, and their distance to the previous item (or start) + * Layout: [distanceToNext, item] + * @type {Array<[number, BaseItem]>} + */ + this.items = []; + + /** + * Stores the spacing to the first item + */ + + this.init(); + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("constructor"); + } + } + /** + * Initializes the path by computing the properties which are not saved + * @param {boolean} computeSpacing Whether to also compute the spacing + */ + init(computeSpacing = true) { + this.onPathChanged(); + + this.totalLength = this.computeTotalLength(); + + if (computeSpacing) { + this.spacingToFirstItem = this.totalLength; + } + + /** + * Current bounds of this path + * @type {Rectangle} + */ + this.worldBounds = this.computeBounds(); + + // Connect the belts + for (let i = 0; i < this.entityPath.length; ++i) { + this.entityPath[i].components.Belt.assignedPath = this; + } + } + + /** + * Returns whether this path can accept a new item + * @returns {boolean} + */ + canAcceptItem() { + return this.spacingToFirstItem >= this.getItemSpacing(); + } + + /** + * Returns the spacing between items + */ + getItemSpacing() { + return globalConfig.beltItemSpacingByLayer[this.layer]; + } + + /** + * Returns the layer of the this path + * @returns {enumLayer} + */ + getLayer() { + return this.entityPath[0].layer; + } + + /** + * Tries to accept the item + * @param {BaseItem} item + */ + tryAcceptItem(item) { + if (this.spacingToFirstItem >= this.getItemSpacing()) { + // So, since we already need one tick to accept this item we will add this directly. + const beltProgressPerTick = + this.root.hubGoals.getBeltBaseSpeed(this.layer) * + this.root.dynamicTickrate.deltaSeconds * + this.getItemSpacing(); + + // First, compute how much progress we can make *at max* + const maxProgress = Math.max(0, this.spacingToFirstItem - this.getItemSpacing()); + const initialProgress = Math.min(maxProgress, beltProgressPerTick); + + this.items.unshift([this.spacingToFirstItem - initialProgress, item]); + this.spacingToFirstItem = initialProgress; + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("accept-item"); + } + + return true; + } + return false; + } + + /** + * SLOW / Tries to find the item closest to the given tile + * @param {Vector} tile + * @returns {BaseItem|null} + */ + findItemAtTile(tile) { + // TODO: This breaks color blind mode otherwise + return null; + } + + /** + * Computes the tile bounds of the path + * @returns {Rectangle} + */ + computeBounds() { + let bounds = this.entityPath[0].components.StaticMapEntity.getTileSpaceBounds(); + for (let i = 1; i < this.entityPath.length; ++i) { + const staticComp = this.entityPath[i].components.StaticMapEntity; + const otherBounds = staticComp.getTileSpaceBounds(); + bounds = bounds.getUnion(otherBounds); + } + return bounds.allScaled(globalConfig.tileSize); + } + + /** + * Updates all ejectors on the path, so that only the last ejector + */ + onPathChanged() { + this.ejectorComp = this.entityPath[this.entityPath.length - 1].components.ItemEjector; + this.ejectorSlot = this.ejectorComp.slots[0]; + + for (let i = 0; i < this.entityPath.length; ++i) { + const ejectorComp = this.entityPath[i].components.ItemEjector; + const isLast = i === this.entityPath.length - 1; + ejectorComp.enabled = isLast; + + // Clear all slots of non-end entities + if (!isLast) { + for (let k = 0; k < ejectorComp.slots.length; ++k) { + ejectorComp.slots[k].item = null; + ejectorComp.slots[k].progress = 0.0; + } + } + } + + this.layer = this.entityPath[0].layer; + } + + // Following code will be compiled out outside of dev versions + /* dev:start */ + + /** + * Helper to throw an error on mismatch + * @param {string} change + * @param {Array} reason + */ + debug_failIntegrity(change, ...reason) { + throw new Error("belt path invalid (" + change + "): " + reason.map(i => "" + i).join(" ")); + } + + /** + * Checks if this path is valid + */ + debug_checkIntegrity(currentChange = "change") { + const fail = (...args) => this.debug_failIntegrity(currentChange, ...args); + + // Check for empty path + if (this.entityPath.length === 0) { + return fail("Belt path is empty"); + } + + // Check for mismatching length + const totalLength = this.computeTotalLength(); + if (!epsilonCompare(this.totalLength, totalLength, 0.01)) { + return this.debug_failIntegrity( + currentChange, + "Total length mismatch, stored =", + this.totalLength, + "but correct is", + totalLength + ); + } + + // Check for misconnected entities + for (let i = 0; i < this.entityPath.length - 1; ++i) { + const entity = this.entityPath[i]; + if (entity.destroyed) { + return fail("Reference to destroyed entity " + entity.uid); + } + + const enabledState = i === this.entityPath.length - 1; + if (entity.components.ItemEjector.enabled !== enabledState) { + return fail("Item ejector enabled state is not synchronized (index =" + i + ")"); + } + + const followUp = this.root.systemMgr.systems.belt.findFollowUpEntity(entity); + if (!followUp) { + return fail( + "Follow up entity for the", + i, + "-th entity (total length", + this.entityPath.length, + ") was null!" + ); + } + if (followUp !== this.entityPath[i + 1]) { + return fail( + "Follow up entity mismatch, stored is", + this.entityPath[i + 1].uid, + "but real one is", + followUp.uid + ); + } + if (entity.components.Belt.assignedPath !== this) { + return fail( + "Entity with uid", + entity.uid, + "doesn't have this path assigned, but this path contains the entity." + ); + } + } + + // Check for right ejector component and slot + if (this.ejectorComp !== this.entityPath[this.entityPath.length - 1].components.ItemEjector) { + return fail("Stale ejectorComp handle"); + } + if (this.ejectorSlot !== this.ejectorComp.slots[0]) { + return fail("Stale ejector slot handle"); + } + if (!this.ejectorComp) { + return fail("Ejector comp not set"); + } + if (!this.ejectorSlot) { + return fail("Ejector slot not set"); + } + + // Check spacing + if (this.spacingToFirstItem > this.totalLength + 0.005) { + return fail( + currentChange, + "spacing to first item (", + this.spacingToFirstItem, + ") is greater than total length (", + this.totalLength, + ")" + ); + } + + // Check distance if empty + if (this.items.length === 0 && !epsilonCompare(this.spacingToFirstItem, this.totalLength, 0.01)) { + return fail( + currentChange, + "Path is empty but spacing to first item (", + this.spacingToFirstItem, + ") does not equal total length (", + this.totalLength, + ")" + ); + } + + // Check items etc + let currentPos = this.spacingToFirstItem; + for (let i = 0; i < this.items.length; ++i) { + const item = this.items[i]; + + if (item[_nextDistance] < 0 || item[_nextDistance] > this.totalLength + 0.02) { + return fail( + "Item has invalid offset to next item: ", + item[_nextDistance], + "(total length:", + this.totalLength, + ")" + ); + } + + currentPos += item[_nextDistance]; + } + + // Check the total sum matches + if (!epsilonCompare(currentPos, this.totalLength, 0.01)) { + return fail( + "total sum (", + currentPos, + ") of first item spacing (", + this.spacingToFirstItem, + ") and items does not match total length (", + this.totalLength, + ") -> items: " + this.items.map(i => i[_nextDistance]).join("|") + ); + } + + // Check bounds + const actualBounds = this.computeBounds(); + if (!actualBounds.equalsEpsilon(this.worldBounds, 0.01)) { + return fail("Bounds are stale"); + } + } + + /* dev:end */ + + /** + * Extends the belt path by the given belt + * @param {Entity} entity + */ + extendOnEnd(entity) { + DEBUG && logger.log("Extending belt path by entity at", entity.components.StaticMapEntity.origin); + + const beltComp = entity.components.Belt; + + // If the last belt has something on its ejector, put that into the path first + const pendingItem = this.ejectorComp.takeSlotItem(0); + if (pendingItem) { + // Ok, so we have a pending item + DEBUG && logger.log("Taking pending item and putting it back on the path"); + this.items.push([0, pendingItem]); + } + + // Append the entity + this.entityPath.push(entity); + this.onPathChanged(); + + // Extend the path length + const additionalLength = beltComp.getEffectiveLengthTiles(entity.layer); + this.totalLength += additionalLength; + DEBUG && logger.log(" Extended total length by", additionalLength, "to", this.totalLength); + + // If we have no item, just update the distance to the first item + if (this.items.length === 0) { + this.spacingToFirstItem = this.totalLength; + DEBUG && logger.log(" Extended spacing to first to", this.totalLength, "(= total length)"); + } else { + // Otherwise, update the next-distance of the last item + const lastItem = this.items[this.items.length - 1]; + DEBUG && + logger.log( + " Extended spacing of last item from", + lastItem[_nextDistance], + "to", + lastItem[_nextDistance] + additionalLength + ); + lastItem[_nextDistance] += additionalLength; + } + + // Assign reference + beltComp.assignedPath = this; + + // Update bounds + this.worldBounds = this.computeBounds(); + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("extend-on-end"); + } + } + + /** + * Extends the path with the given entity on the beginning + * @param {Entity} entity + */ + extendOnBeginning(entity) { + const beltComp = entity.components.Belt; + + DEBUG && logger.log("Extending the path on the beginning"); + + // All items on that belt are simply lost (for now) + + const length = beltComp.getEffectiveLengthTiles(entity.layer); + + // Extend the length of this path + this.totalLength += length; + + // Simply adjust the first item spacing cuz we have no items contained + this.spacingToFirstItem += length; + + // Set handles and append entity + beltComp.assignedPath = this; + this.entityPath.unshift(entity); + this.onPathChanged(); + + // Update bounds + this.worldBounds = this.computeBounds(); + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("extend-on-begin"); + } + } + + /** + * Returns if the given entity is the end entity of the path + * @param {Entity} entity + * @returns {boolean} + */ + isEndEntity(entity) { + return this.entityPath[this.entityPath.length - 1] === entity; + } + + /** + * Returns if the given entity is the start entity of the path + * @param {Entity} entity + * @returns {boolean} + */ + isStartEntity(entity) { + return this.entityPath[0] === entity; + } + + /** + * Splits this path at the given entity by removing it, and + * returning the new secondary paht + * @param {Entity} entity + * @returns {BeltPath} + */ + deleteEntityOnPathSplitIntoTwo(entity) { + DEBUG && logger.log("Splitting path at entity", entity.components.StaticMapEntity.origin); + + // First, find where the current path ends + const beltComp = entity.components.Belt; + beltComp.assignedPath = null; + + const entityLength = beltComp.getEffectiveLengthTiles(entity.layer); + assert(this.entityPath.indexOf(entity) >= 0, "Entity not contained for split"); + assert(this.entityPath.indexOf(entity) !== 0, "Entity is first"); + assert(this.entityPath.indexOf(entity) !== this.entityPath.length - 1, "Entity is last"); + + let firstPathEntityCount = 0; + let firstPathLength = 0; + let firstPathEndEntity = null; + + for (let i = 0; i < this.entityPath.length; ++i) { + const otherEntity = this.entityPath[i]; + if (otherEntity === entity) { + DEBUG && logger.log("Found entity at", i, "of length", firstPathLength); + break; + } + + ++firstPathEntityCount; + firstPathEndEntity = otherEntity; + firstPathLength += otherEntity.components.Belt.getEffectiveLengthTiles(otherEntity.layer); + } + + DEBUG && + logger.log( + "First path ends at", + firstPathLength, + "and entity", + firstPathEndEntity.components.StaticMapEntity.origin, + "and has", + firstPathEntityCount, + "entities" + ); + + // Compute length of second path + const secondPathLength = this.totalLength - firstPathLength - entityLength; + const secondPathStart = firstPathLength + entityLength; + const secondEntities = this.entityPath.splice(firstPathEntityCount + 1); + DEBUG && + logger.log( + "Second path starts at", + secondPathStart, + "and has a length of ", + secondPathLength, + "with", + secondEntities.length, + "entities" + ); + + // Remove the last item + this.entityPath.pop(); + + DEBUG && logger.log("Splitting", this.items.length, "items"); + DEBUG && + logger.log( + "Old items are", + this.items.map(i => i[_nextDistance]) + ); + + // Create second path + const secondPath = new BeltPath(this.root, secondEntities); + + // Remove all items which are no longer relevant and transfer them to the second path + let itemPos = this.spacingToFirstItem; + for (let i = 0; i < this.items.length; ++i) { + const item = this.items[i]; + const distanceToNext = item[_nextDistance]; + + DEBUG && logger.log(" Checking item at", itemPos, "with distance of", distanceToNext, "to next"); + + // Check if this item is past the first path + if (itemPos >= firstPathLength) { + // Remove it from the first path + this.items.splice(i, 1); + i -= 1; + DEBUG && + logger.log(" Removed item from first path since its no longer contained @", itemPos); + + // Check if its on the second path (otherwise its on the removed belt and simply lost) + if (itemPos >= secondPathStart) { + // Put item on second path + secondPath.items.push([distanceToNext, item[_item]]); + DEBUG && + logger.log( + " Put item to second path @", + itemPos, + "with distance to next =", + distanceToNext + ); + + // If it was the first item, adjust the distance to the first item + if (secondPath.items.length === 1) { + DEBUG && logger.log(" Sinc it was the first, set sapcing of first to", itemPos); + secondPath.spacingToFirstItem = itemPos - secondPathStart; + } + } else { + DEBUG && logger.log(" Item was on the removed belt, so its gone - forever!"); + } + } else { + // Seems this item is on the first path (so all good), so just make sure it doesn't + // have a nextDistance which is bigger than the total path length + const clampedDistanceToNext = Math.min(itemPos + distanceToNext, firstPathLength) - itemPos; + if (clampedDistanceToNext < distanceToNext) { + DEBUG && + logger.log( + "Correcting next distance (first path) from", + distanceToNext, + "to", + clampedDistanceToNext + ); + item[_nextDistance] = clampedDistanceToNext; + } + } + + // Advance items + itemPos += distanceToNext; + } + + DEBUG && + logger.log( + "New items are", + this.items.map(i => i[_nextDistance]) + ); + + DEBUG && + logger.log( + "And second path items are", + secondPath.items.map(i => i[_nextDistance]) + ); + + // Adjust our total length + this.totalLength = firstPathLength; + + // Make sure that if we are empty, we set our first distance properly + if (this.items.length === 0) { + this.spacingToFirstItem = this.totalLength; + } + + this.onPathChanged(); + secondPath.onPathChanged(); + + // Update bounds + this.worldBounds = this.computeBounds(); + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("split-two-first"); + secondPath.debug_checkIntegrity("split-two-second"); + } + + return secondPath; + } + + /** + * Deletes the last entity + * @param {Entity} entity + */ + deleteEntityOnEnd(entity) { + assert( + this.entityPath[this.entityPath.length - 1] === entity, + "Not actually the last entity (instead " + this.entityPath.indexOf(entity) + ")" + ); + + // Ok, first remove the entity + const beltComp = entity.components.Belt; + const beltLength = beltComp.getEffectiveLengthTiles(entity.layer); + + DEBUG && + logger.log( + "Deleting last entity on path with length", + this.entityPath.length, + "(reducing", + this.totalLength, + " by", + beltLength, + ")" + ); + this.totalLength -= beltLength; + this.entityPath.pop(); + this.onPathChanged(); + + DEBUG && + logger.log( + " New path has length of", + this.totalLength, + "with", + this.entityPath.length, + "entities" + ); + + // This is just for sanity + beltComp.assignedPath = null; + + // Clean up items + if (this.items.length === 0) { + // Simple case with no items, just update the first item spacing + this.spacingToFirstItem = this.totalLength; + } else { + // Ok, make sure we simply drop all items which are no longer contained + let itemOffset = this.spacingToFirstItem; + let lastItemOffset = itemOffset; + + DEBUG && logger.log(" Adjusting", this.items.length, "items"); + + for (let i = 0; i < this.items.length; ++i) { + const item = this.items[i]; + + // Get rid of items past this path + if (itemOffset >= this.totalLength) { + DEBUG && logger.log("Dropping item (current index=", i, ")"); + this.items.splice(i, 1); + i -= 1; + continue; + } + + DEBUG && logger.log("Item", i, "is at", itemOffset, "with next offset", item[_nextDistance]); + lastItemOffset = itemOffset; + itemOffset += item[_nextDistance]; + } + + // If we still have an item, make sure the last item matches + if (this.items.length > 0) { + // We can easily compute the next distance since we know where the last item is now + const lastDistance = this.totalLength - lastItemOffset; + assert( + lastDistance >= 0.0, + "Last item distance mismatch: " + + lastDistance + + " -> Total length was " + + this.totalLength + + " and lastItemOffset was " + + lastItemOffset + ); + + DEBUG && + logger.log( + "Adjusted distance of last item: it is at", + lastItemOffset, + "so it has a distance of", + lastDistance, + "to the end (", + this.totalLength, + ")" + ); + this.items[this.items.length - 1][_nextDistance] = lastDistance; + } else { + DEBUG && logger.log(" Removed all items so we'll update spacing to total length"); + + // We removed all items so update our spacing + this.spacingToFirstItem = this.totalLength; + } + } + + // Update bounds + this.worldBounds = this.computeBounds(); + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("delete-on-end"); + } + } + + /** + * Deletes the entity of the start of the path + * @see deleteEntityOnEnd + * @param {Entity} entity + */ + deleteEntityOnStart(entity) { + assert( + entity === this.entityPath[0], + "Not actually the start entity (instead " + this.entityPath.indexOf(entity) + ")" + ); + + // Ok, first remove the entity + const beltComp = entity.components.Belt; + const beltLength = beltComp.getEffectiveLengthTiles(entity.layer); + + DEBUG && + logger.log( + "Deleting first entity on path with length", + this.entityPath.length, + "(reducing", + this.totalLength, + " by", + beltLength, + ")" + ); + this.totalLength -= beltLength; + this.entityPath.shift(); + this.onPathChanged(); + + DEBUG && + logger.log( + " New path has length of", + this.totalLength, + "with", + this.entityPath.length, + "entities" + ); + + // This is just for sanity + beltComp.assignedPath = null; + + // Clean up items + if (this.items.length === 0) { + // Simple case with no items, just update the first item spacing + this.spacingToFirstItem = this.totalLength; + } else { + // Simple case, we had no item on the beginning -> all good + if (this.spacingToFirstItem >= beltLength) { + DEBUG && + logger.log( + " No item on the first place, so we can just adjust the spacing (spacing=", + this.spacingToFirstItem, + ") removed =", + beltLength + ); + this.spacingToFirstItem -= beltLength; + } else { + // Welp, okay we need to drop all items which are < beltLength and adjust + // the other item offsets as well + + DEBUG && + logger.log( + " We have at least one item in the beginning, drop those and adjust spacing (first item @", + this.spacingToFirstItem, + ") since we removed", + beltLength, + "length from path" + ); + DEBUG && + logger.log( + " Items:", + this.items.map(i => i[_nextDistance]) + ); + + // Find offset to first item + let itemOffset = this.spacingToFirstItem; + for (let i = 0; i < this.items.length; ++i) { + const item = this.items[i]; + if (itemOffset <= beltLength) { + DEBUG && + logger.log( + " -> Dropping item with index", + i, + "at", + itemOffset, + "since it was on the removed belt" + ); + // This item must be dropped + this.items.splice(i, 1); + i -= 1; + itemOffset += item[_nextDistance]; + continue; + } else { + // This item can be kept, thus its the first we know + break; + } + } + + if (this.items.length > 0) { + DEBUG && + logger.log( + " Offset of first non-dropped item was at:", + itemOffset, + "-> setting spacing to it (total length=", + this.totalLength, + ")" + ); + + this.spacingToFirstItem = itemOffset - beltLength; + assert( + this.spacingToFirstItem >= 0.0, + "Invalid spacing after delete on start: " + this.spacingToFirstItem + ); + } else { + DEBUG && logger.log(" We dropped all items, simply set spacing to total length"); + // We dropped all items, simple one + this.spacingToFirstItem = this.totalLength; + } + } + } + + // Update bounds + this.worldBounds = this.computeBounds(); + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("delete-on-start"); + } + } + + /** + * Extends the path by the given other path + * @param {BeltPath} otherPath + */ + extendByPath(otherPath) { + assert(otherPath !== this, "Circular path dependency"); + + const entities = otherPath.entityPath; + DEBUG && logger.log("Extending path by other path, starting to add entities"); + + const oldLength = this.totalLength; + + DEBUG && logger.log(" Adding", entities.length, "new entities, current length =", this.totalLength); + + // First, append entities + for (let i = 0; i < entities.length; ++i) { + const entity = entities[i]; + const beltComp = entity.components.Belt; + + // Add to path and update references + this.entityPath.push(entity); + beltComp.assignedPath = this; + + // Update our length + const additionalLength = beltComp.getEffectiveLengthTiles(entity.layer); + this.totalLength += additionalLength; + } + + DEBUG && + logger.log( + " Path is now", + this.entityPath.length, + "entities and has a length of", + this.totalLength + ); + + // Now, update the distance of our last item + if (this.items.length !== 0) { + const lastItem = this.items[this.items.length - 1]; + lastItem[_nextDistance] += otherPath.spacingToFirstItem; + DEBUG && + logger.log(" Add distance to last item, effectively being", lastItem[_nextDistance], "now"); + } else { + // Seems we have no items, update our first item distance + this.spacingToFirstItem = oldLength + otherPath.spacingToFirstItem; + DEBUG && + logger.log( + " We had no items, so our new spacing to first is old length (", + oldLength, + ") plus others spacing to first (", + otherPath.spacingToFirstItem, + ") =", + this.spacingToFirstItem + ); + } + + DEBUG && logger.log(" Pushing", otherPath.items.length, "items from other path"); + + // Aaand push the other paths items + for (let i = 0; i < otherPath.items.length; ++i) { + const item = otherPath.items[i]; + this.items.push([item[_nextDistance], item[_item]]); + } + + // Update bounds + this.worldBounds = this.computeBounds(); + + this.onPathChanged(); + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("extend-by-path"); + } + } + + /** + * Computes the total length of the path + * @returns {number} + */ + computeTotalLength() { + let length = 0; + for (let i = 0; i < this.entityPath.length; ++i) { + const entity = this.entityPath[i]; + length += entity.components.Belt.getEffectiveLengthTiles(this.layer); + } + return length; + } + + /** + * Performs one tick + */ + update() { + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("pre-update"); + } + + // Divide by item spacing on belts since we use throughput and not speed + let beltSpeed = + this.root.hubGoals.getBeltBaseSpeed(this.layer) * + this.root.dynamicTickrate.deltaSeconds * + this.getItemSpacing(); + + if (G_IS_DEV && globalConfig.debug.instantBelts) { + beltSpeed *= 100; + } + + let minimumDistance = this.ejectorSlot.item ? this.getItemSpacing() : 0; + + // Try to reduce spacing + let remainingAmount = beltSpeed; + for (let i = this.items.length - 1; i >= 0; --i) { + const nextDistanceAndItem = this.items[i]; + const minimumSpacing = minimumDistance; + + const takeAway = Math.max( + 0, + Math.min(remainingAmount, nextDistanceAndItem[_nextDistance] - minimumSpacing) + ); + + remainingAmount -= takeAway; + nextDistanceAndItem[_nextDistance] -= takeAway; + + this.spacingToFirstItem += takeAway; + if (remainingAmount < 0.01) { + break; + } + + minimumDistance = this.getItemSpacing(); + } + + const lastItem = this.items[this.items.length - 1]; + if (lastItem && lastItem[_nextDistance] === 0) { + // Take over + if (this.ejectorComp.tryEject(0, lastItem[_item])) { + this.items.pop(); + } + } + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_checkIntegrity("post-update"); + } + } + + /** + * Computes a world space position from the given progress + * @param {number} progress + * @returns {Vector} + */ + computePositionFromProgress(progress) { + let currentLength = 0; + + // floating point issuses .. + assert(progress <= this.totalLength + 0.02, "Progress too big: " + progress); + + for (let i = 0; i < this.entityPath.length; ++i) { + const beltComp = this.entityPath[i].components.Belt; + const localLength = beltComp.getEffectiveLengthTiles(this.layer); + + if (currentLength + localLength >= progress || i === this.entityPath.length - 1) { + // Min required here due to floating point issues + const localProgress = Math.min(1.0, progress - currentLength); + + assert(localProgress >= 0.0, "Invalid local progress: " + localProgress); + const localSpace = beltComp.transformBeltToLocalSpace(localProgress, this.layer); + return this.entityPath[i].components.StaticMapEntity.localTileToWorld(localSpace); + } + currentLength += localLength; + } + + assert(false, "invalid progress: " + progress + " (max: " + this.totalLength + ")"); + } + + /** + * + * @param {DrawParameters} parameters + */ + drawDebug(parameters) { + if (!parameters.visibleRect.containsRect(this.worldBounds)) { + return; + } + + if (this.entityPath[0].layer !== this.root.currentLayer) { + // Don't draw + return; + } + + parameters.context.fillStyle = "#d79a25"; + parameters.context.strokeStyle = "#d79a25"; + parameters.context.beginPath(); + + for (let i = 0; i < this.entityPath.length; ++i) { + const entity = this.entityPath[i]; + const pos = entity.components.StaticMapEntity; + const worldPos = pos.origin.toWorldSpaceCenterOfTile(); + + if (i === 0) { + parameters.context.moveTo(worldPos.x, worldPos.y); + } else { + parameters.context.lineTo(worldPos.x, worldPos.y); + } + } + parameters.context.stroke(); + + // Items + let progress = this.spacingToFirstItem; + for (let i = 0; i < this.items.length; ++i) { + const nextDistanceAndItem = this.items[i]; + const worldPos = this.computePositionFromProgress(progress).toWorldSpaceCenterOfTile(); + parameters.context.fillStyle = "#268e4d"; + parameters.context.beginRoundedRect(worldPos.x - 5, worldPos.y - 5, 10, 10, 3); + parameters.context.fill(); + parameters.context.font = "6px GameFont"; + parameters.context.fillStyle = "#111"; + parameters.context.fillText( + "" + round4Digits(nextDistanceAndItem[_nextDistance]), + worldPos.x + 5, + worldPos.y + 2 + ); + progress += nextDistanceAndItem[_nextDistance]; + } + + for (let i = 0; i < this.entityPath.length; ++i) { + const entity = this.entityPath[i]; + parameters.context.fillStyle = "#d79a25"; + const pos = entity.components.StaticMapEntity; + const worldPos = pos.origin.toWorldSpaceCenterOfTile(); + parameters.context.beginCircle(worldPos.x, worldPos.y, i === 0 ? 5 : 3); + parameters.context.fill(); + } + + for (let progress = 0; progress <= this.totalLength + 0.01; progress += 0.2) { + const worldPos = this.computePositionFromProgress(progress).toWorldSpaceCenterOfTile(); + parameters.context.fillStyle = "red"; + parameters.context.beginCircle(worldPos.x, worldPos.y, 1); + parameters.context.fill(); + } + + const firstItemIndicator = this.computePositionFromProgress( + this.spacingToFirstItem + ).toWorldSpaceCenterOfTile(); + parameters.context.fillStyle = "purple"; + parameters.context.fillRect(firstItemIndicator.x - 3, firstItemIndicator.y - 1, 6, 2); + } + + /** + * Draws the path + * @param {DrawParameters} parameters + */ + draw(parameters) { + if (!parameters.visibleRect.containsRect(this.worldBounds)) { + return; + } + + if (this.items.length === 0) { + // Early out + return; + } + + let currentItemPos = this.spacingToFirstItem; + let currentItemIndex = 0; + + let trackPos = 0.0; + + // Iterate whole track and check items + for (let i = 0; i < this.entityPath.length; ++i) { + const entity = this.entityPath[i]; + const beltComp = entity.components.Belt; + const beltLength = beltComp.getEffectiveLengthTiles(this.layer); + + // Check if the current items are on the belt + while (trackPos + beltLength >= currentItemPos) { + // Its on the belt, render it now + const staticComp = entity.components.StaticMapEntity; + assert( + currentItemPos - trackPos >= 0, + "invalid track pos: " + currentItemPos + " vs " + trackPos + " (l =" + beltLength + ")" + ); + + const localPos = beltComp.transformBeltToLocalSpace(currentItemPos - trackPos, this.layer); + const worldPos = staticComp.localTileToWorld(localPos).toWorldSpaceCenterOfTile(); + + const distanceAndItem = this.items[currentItemIndex]; + if (parameters.visibleRect.containsCircle(worldPos.x, worldPos.y, 10)) { + distanceAndItem[_item].draw(worldPos.x, worldPos.y, parameters); + } + + // Check for the next item + currentItemPos += distanceAndItem[_nextDistance]; + ++currentItemIndex; + + if (currentItemIndex >= this.items.length) { + // We rendered all items + return; + } + } + + trackPos += beltLength; + } + } +} diff --git a/src/js/game/blueprint.js b/src/js/game/blueprint.js new file mode 100644 index 00000000..4e322eb0 --- /dev/null +++ b/src/js/game/blueprint.js @@ -0,0 +1,183 @@ +import { DrawParameters } from "../core/draw_parameters"; +import { Loader } from "../core/loader"; +import { createLogger } from "../core/logging"; +import { Vector } from "../core/vector"; +import { Entity } from "./entity"; +import { GameRoot, enumLayer } from "./root"; +import { findNiceIntegerValue } from "../core/utils"; +import { blueprintShape } from "./upgrades"; +import { globalConfig } from "../core/config"; + +const logger = createLogger("blueprint"); + +export class Blueprint { + /** + * @param {Array} entities + */ + constructor(entities) { + this.entities = entities; + } + + /** + * Returns the layer of this blueprint + * @returns {enumLayer} + */ + get layer() { + if (this.entities.length === 0) { + return enumLayer.regular; + } + return this.entities[0].layer; + } + + /** + * Creates a new blueprint from the given entity uids + * @param {GameRoot} root + * @param {Array} uids + */ + static fromUids(root, uids) { + const newEntities = []; + + let averagePosition = new Vector(); + + // First, create a copy + for (let i = 0; i < uids.length; ++i) { + const entity = root.entityMgr.findByUid(uids[i]); + assert(entity, "Entity for blueprint not found:" + uids[i]); + + const clone = entity.duplicateWithoutContents(); + newEntities.push(clone); + + const pos = entity.components.StaticMapEntity.getTileSpaceBounds().getCenter(); + averagePosition.addInplace(pos); + } + + averagePosition.divideScalarInplace(uids.length); + const blueprintOrigin = averagePosition.subScalars(0.5, 0.5).floor(); + + for (let i = 0; i < uids.length; ++i) { + newEntities[i].components.StaticMapEntity.origin.subInplace(blueprintOrigin); + } + + // Now, make sure the origin is 0,0 + return new Blueprint(newEntities); + } + + /** + * Returns the cost of this blueprint in shapes + */ + getCost() { + if (G_IS_DEV && globalConfig.debug.blueprintsNoCost) { + return 0; + } + return findNiceIntegerValue(4 * Math.pow(this.entities.length, 1.1)); + } + + /** + * Draws the blueprint at the given origin + * @param {DrawParameters} parameters + */ + draw(parameters, tile) { + parameters.context.globalAlpha = 0.8; + for (let i = 0; i < this.entities.length; ++i) { + const entity = this.entities[i]; + const staticComp = entity.components.StaticMapEntity; + if (!staticComp.blueprintSpriteKey) { + logger.warn("Blueprint entity without sprite!"); + return; + } + const newPos = staticComp.origin.add(tile); + + const rect = staticComp.getTileSpaceBounds(); + rect.moveBy(tile.x, tile.y); + + if (!parameters.root.logic.checkCanPlaceEntity(entity, tile)) { + parameters.context.globalAlpha = 0.3; + } else { + parameters.context.globalAlpha = 1; + } + + staticComp.drawSpriteOnFullEntityBounds( + parameters, + Loader.getSprite(staticComp.blueprintSpriteKey), + 0, + true, + newPos + ); + } + parameters.context.globalAlpha = 1; + } + + /** + * Rotates the blueprint clockwise + */ + rotateCw() { + for (let i = 0; i < this.entities.length; ++i) { + const entity = this.entities[i]; + const staticComp = entity.components.StaticMapEntity; + + staticComp.rotation = (staticComp.rotation + 90) % 360; + staticComp.originalRotation = (staticComp.originalRotation + 90) % 360; + staticComp.origin = staticComp.origin.rotateFastMultipleOf90(90); + } + } + + /** + * Rotates the blueprint counter clock wise + */ + rotateCcw() { + // Well ... + for (let i = 0; i < 3; ++i) { + this.rotateCw(); + } + } + + /** + * Checks if the blueprint can be placed at the given tile + * @param {GameRoot} root + * @param {Vector} tile + */ + canPlace(root, tile) { + let anyPlaceable = false; + + for (let i = 0; i < this.entities.length; ++i) { + const entity = this.entities[i]; + if (root.logic.checkCanPlaceEntity(entity, tile)) { + anyPlaceable = true; + } + } + + return anyPlaceable; + } + + /** + * @param {GameRoot} root + */ + canAfford(root) { + return root.hubGoals.getShapesStoredByKey(blueprintShape) >= this.getCost(); + } + + /** + * Attempts to place the blueprint at the given tile + * @param {GameRoot} root + * @param {Vector} tile + */ + tryPlace(root, tile) { + return root.logic.performBulkOperation(() => { + let anyPlaced = false; + for (let i = 0; i < this.entities.length; ++i) { + const entity = this.entities[i]; + if (!root.logic.checkCanPlaceEntity(entity, tile)) { + continue; + } + + const clone = entity.duplicateWithoutContents(); + clone.components.StaticMapEntity.origin.addInplace(tile); + root.logic.freeEntityAreaBeforeBuild(clone); + root.map.placeStaticEntity(clone); + root.entityMgr.registerEntity(clone); + anyPlaced = true; + } + return anyPlaced; + }); + } +} diff --git a/src/js/game/buildings/advanced_processor.js b/src/js/game/buildings/advanced_processor.js new file mode 100644 index 00000000..a688c878 --- /dev/null +++ b/src/js/game/buildings/advanced_processor.js @@ -0,0 +1,108 @@ +import { formatItemsPerSecond } from "../../core/utils"; +import { enumDirection, Vector } from "../../core/vector"; +import { T } from "../../translations"; +import { enumItemType } from "../base_item"; +import { EnergyConsumerComponent } from "../components/energy_consumer"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; +import { ItemEjectorComponent } from "../components/item_ejector"; +import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; +import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins"; +import { Entity } from "../entity"; +import { MetaBuilding } from "../meta_building"; +import { enumLayer, GameRoot } from "../root"; + +export class MetaAdvancedProcessorBuilding extends MetaBuilding { + constructor() { + super("advanced_processor"); + } + + getSilhouetteColor() { + return "#25d7b8"; + } + + getDimensions(variant) { + return new Vector(2, 2); + } + + /** + * @param {GameRoot} root + * @param {string} variant + * @returns {Array<[string, string]>} + */ + getAdditionalStatistics(root, variant) { + const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.advancedProcessor); + return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]]; + } + + /** + * @param {GameRoot} root + */ + getIsUnlocked(root) { + // TODO + return true; + // return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_cutter_and_trash); + } + + /** + * Creates the entity at the given location + * @param {Entity} entity + */ + setupEntityComponents(entity) { + entity.addComponent( + new ItemProcessorComponent({ + inputsPerCharge: 1, + processorType: enumItemProcessorTypes.advancedProcessor, + }) + ); + entity.addComponent( + new ItemEjectorComponent({ + slots: [ + { pos: new Vector(1, 0), direction: enumDirection.right }, + { pos: new Vector(1, 0), direction: enumDirection.top, layer: enumLayer.wires }, + ], + }) + ); + entity.addComponent( + new EnergyConsumerComponent({ + bufferSize: 3, + perCharge: 1, + batteryPosition: new Vector(0.63, 0.7), + acceptorSlotIndex: 1, + ejectorSlotIndex: 1, + }) + ); + + entity.addComponent( + new WiredPinsComponent({ + slots: [ + { + pos: new Vector(0, 0), + direction: enumDirection.top, + type: enumPinSlotType.positiveEnergyAcceptor, + }, + { + pos: new Vector(1, 0), + direction: enumDirection.top, + type: enumPinSlotType.negativeEnergyEjector, + }, + ], + }) + ); + entity.addComponent( + new ItemAcceptorComponent({ + slots: [ + { + pos: new Vector(0, 1), + directions: [enumDirection.left], + }, + { + pos: new Vector(0, 0), + directions: [enumDirection.top], + filter: enumItemType.positiveEnergy, + layer: enumLayer.wires, + }, + ], + }) + ); + } +} diff --git a/src/js/game/buildings/belt.js b/src/js/game/buildings/belt.js new file mode 100644 index 00000000..1fb80b88 --- /dev/null +++ b/src/js/game/buildings/belt.js @@ -0,0 +1,52 @@ +import { Loader } from "../../core/loader"; +import { enumDirection } from "../../core/vector"; +import { SOUNDS } from "../../platform/sound"; +import { arrayBeltVariantToRotation, MetaBeltBaseBuilding } from "./belt_base"; + +export class MetaBeltBuilding extends MetaBeltBaseBuilding { + constructor() { + super("belt"); + } + + getSilhouetteColor() { + return "#777"; + } + + getPlacementSound() { + return SOUNDS.placeBelt; + } + + getPreviewSprite(rotationVariant) { + switch (arrayBeltVariantToRotation[rotationVariant]) { + case enumDirection.top: { + return Loader.getSprite("sprites/buildings/belt_top.png"); + } + case enumDirection.left: { + return Loader.getSprite("sprites/buildings/belt_left.png"); + } + case enumDirection.right: { + return Loader.getSprite("sprites/buildings/belt_right.png"); + } + default: { + assertAlways(false, "Invalid belt rotation variant"); + } + } + } + + getBlueprintSprite(rotationVariant) { + switch (arrayBeltVariantToRotation[rotationVariant]) { + case enumDirection.top: { + return Loader.getSprite("sprites/blueprints/belt_top.png"); + } + case enumDirection.left: { + return Loader.getSprite("sprites/blueprints/belt_left.png"); + } + case enumDirection.right: { + return Loader.getSprite("sprites/blueprints/belt_right.png"); + } + default: { + assertAlways(false, "Invalid belt rotation variant"); + } + } + } +} diff --git a/src/js/game/buildings/belt_base.js b/src/js/game/buildings/belt_base.js index 10174943..b8e92150 100644 --- a/src/js/game/buildings/belt_base.js +++ b/src/js/game/buildings/belt_base.js @@ -9,19 +9,11 @@ import { ItemEjectorComponent } from "../components/item_ejector"; import { ReplaceableMapEntityComponent } from "../components/replaceable_map_entity"; import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; -import { GameRoot } from "../root"; +import { GameRoot, enumLayer } from "../root"; export const arrayBeltVariantToRotation = [enumDirection.top, enumDirection.left, enumDirection.right]; export class MetaBeltBaseBuilding extends MetaBuilding { - constructor() { - super("belt"); - } - - getSilhouetteColor() { - return "#777"; - } - getHasDirectionLockAvailable() { return true; } @@ -32,45 +24,10 @@ export class MetaBeltBaseBuilding extends MetaBuilding { * @returns {Array<[string, string]>} */ getAdditionalStatistics(root, variant) { - const beltSpeed = root.hubGoals.getBeltBaseSpeed(); - + const beltSpeed = root.hubGoals.getBeltBaseSpeed(enumLayer.regular); return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(beltSpeed)]]; } - getPreviewSprite(rotationVariant) { - switch (arrayBeltVariantToRotation[rotationVariant]) { - case enumDirection.top: { - return Loader.getSprite("sprites/buildings/belt_top.png"); - } - case enumDirection.left: { - return Loader.getSprite("sprites/buildings/belt_left.png"); - } - case enumDirection.right: { - return Loader.getSprite("sprites/buildings/belt_right.png"); - } - default: { - assertAlways(false, "Invalid belt rotation variant"); - } - } - } - - getBlueprintSprite(rotationVariant) { - switch (arrayBeltVariantToRotation[rotationVariant]) { - case enumDirection.top: { - return Loader.getSprite("sprites/blueprints/belt_top.png"); - } - case enumDirection.left: { - return Loader.getSprite("sprites/blueprints/belt_left.png"); - } - case enumDirection.right: { - return Loader.getSprite("sprites/blueprints/belt_right.png"); - } - default: { - assertAlways(false, "Invalid belt rotation variant"); - } - } - } - getStayInPlacementMode() { return true; } @@ -93,6 +50,8 @@ export class MetaBeltBaseBuilding extends MetaBuilding { direction: enumDirection.top, // updated later }) ); + // Make this entity replaceabel + entity.addComponent(new ReplaceableMapEntityComponent()); entity.addComponent( new ItemAcceptorComponent({ @@ -100,6 +59,7 @@ export class MetaBeltBaseBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], + layer: this.getLayer(), }, ], animated: false, @@ -112,13 +72,12 @@ export class MetaBeltBaseBuilding extends MetaBuilding { { pos: new Vector(0, 0), direction: enumDirection.top, // updated later + layer: this.getLayer(), }, ], instantEject: true, }) ); - // Make this entity replaceabel - entity.addComponent(new ReplaceableMapEntityComponent()); } /** @@ -129,25 +88,26 @@ export class MetaBeltBaseBuilding extends MetaBuilding { updateVariants(entity, rotationVariant) { entity.components.Belt.direction = arrayBeltVariantToRotation[rotationVariant]; entity.components.ItemEjector.slots[0].direction = arrayBeltVariantToRotation[rotationVariant]; - entity.components.StaticMapEntity.spriteKey = null; } /** - * Computes optimal belt rotation variant - * @param {GameRoot} root - * @param {Vector} tile - * @param {number} rotation - * @param {string} variant - * @return {{ rotation: number, rotationVariant: number }} + * Should compute the optimal rotation variant on the given tile + * @param {object} param0 + * @param {GameRoot} param0.root + * @param {Vector} param0.tile + * @param {number} param0.rotation + * @param {string} param0.variant + * @param {string} param0.layer + * @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array }} */ - computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation, variant) { + computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) { const topDirection = enumAngleToDirection[rotation]; const rightDirection = enumAngleToDirection[(rotation + 90) % 360]; const bottomDirection = enumAngleToDirection[(rotation + 180) % 360]; const leftDirection = enumAngleToDirection[(rotation + 270) % 360]; - const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile); + const { ejectors, acceptors } = root.logic.getEjectorsAndAcceptorsAtTile(tile, layer); let hasBottomEjector = false; let hasRightEjector = false; diff --git a/src/js/game/buildings/cutter.js b/src/js/game/buildings/cutter.js index a9433390..bfe142d5 100644 --- a/src/js/game/buildings/cutter.js +++ b/src/js/game/buildings/cutter.js @@ -1,14 +1,14 @@ -import { globalConfig } from "../../core/config"; +import { formatItemsPerSecond } from "../../core/utils"; import { enumDirection, Vector } from "../../core/vector"; -import { enumItemAcceptorItemFilter, ItemAcceptorComponent } from "../components/item_acceptor"; +import { T } from "../../translations"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; import { ItemEjectorComponent } from "../components/item_ejector"; import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; import { Entity } from "../entity"; -import { MetaBuilding, defaultBuildingVariant } from "../meta_building"; +import { defaultBuildingVariant, MetaBuilding } from "../meta_building"; import { GameRoot } from "../root"; import { enumHubGoalRewards } from "../tutorial_goals"; -import { T } from "../../translations"; -import { formatItemsPerSecond } from "../../core/utils"; +import { enumItemType } from "../base_item"; /** @enum {string} */ export const enumCutterVariants = { quad: "quad" }; @@ -82,7 +82,7 @@ export class MetaCutterBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, ], }) diff --git a/src/js/game/buildings/energy_generator.js b/src/js/game/buildings/energy_generator.js index 47502ce6..1d7ac18b 100644 --- a/src/js/game/buildings/energy_generator.js +++ b/src/js/game/buildings/energy_generator.js @@ -1,21 +1,19 @@ import { enumDirection, Vector } from "../../core/vector"; -import { ItemAcceptorComponent, enumItemAcceptorItemFilter } from "../components/item_acceptor"; +import { enumItemType } from "../base_item"; +import { EnergyGeneratorComponent } from "../components/energy_generator"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; +import { ItemEjectorComponent } from "../components/item_ejector"; +import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins"; import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; -import { GameRoot } from "../root"; +import { enumLayer, GameRoot } from "../root"; import { enumHubGoalRewards } from "../tutorial_goals"; -import { EnergyGeneratorComponent } from "../components/energy_generator"; -import { WiredPinsComponent, enumPinSlotType } from "../components/wired_pins"; export class MetaEnergyGenerator extends MetaBuilding { constructor() { super("energy_generator"); } - isRotateable(variant) { - return false; - } - getSilhouetteColor() { return "#c425d7"; } @@ -38,7 +36,8 @@ export class MetaEnergyGenerator extends MetaBuilding { * @param {GameRoot} root */ getIsUnlocked(root) { - return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_cutter_and_trash); + return true; + // return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_cutter_and_trash); } /** @@ -49,35 +48,44 @@ export class MetaEnergyGenerator extends MetaBuilding { entity.addComponent( new ItemAcceptorComponent({ slots: [ - { - pos: new Vector(0, 0), - directions: [enumDirection.top], - filter: enumItemAcceptorItemFilter.shape, - }, - - { - pos: new Vector(1, 0), - directions: [enumDirection.top], - filter: enumItemAcceptorItemFilter.shape, - }, { pos: new Vector(0, 1), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(1, 1), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, + }, + { + pos: new Vector(1, 0), + directions: [enumDirection.top], + layer: enumLayer.wires, + filter: enumItemType.negativeEnergy, }, ], }) ); + entity.addComponent( + new ItemEjectorComponent({ + slots: [ + { + pos: new Vector(0, 0), + direction: enumDirection.top, + layer: enumLayer.wires, + }, + ], + instantEject: true, + }) + ); + entity.addComponent( new EnergyGeneratorComponent({ // Set by the energy generator system later requiredKey: null, + wasteAcceptorSlotIndex: 2, }) ); @@ -86,19 +94,13 @@ export class MetaEnergyGenerator extends MetaBuilding { slots: [ { pos: new Vector(0, 0), - type: enumPinSlotType.energyEjector, + type: enumPinSlotType.positiveEnergyEjector, + direction: enumDirection.top, }, { pos: new Vector(1, 0), - type: enumPinSlotType.energyEjector, - }, - { - pos: new Vector(0, 1), - type: enumPinSlotType.energyEjector, - }, - { - pos: new Vector(1, 1), - type: enumPinSlotType.energyEjector, + type: enumPinSlotType.negativeEnergyAcceptor, + direction: enumDirection.top, }, ], }) diff --git a/src/js/game/buildings/hub.js b/src/js/game/buildings/hub.js index 49d95005..61a61f27 100644 --- a/src/js/game/buildings/hub.js +++ b/src/js/game/buildings/hub.js @@ -1,11 +1,11 @@ import { enumDirection, Vector } from "../../core/vector"; -import { enumItemAcceptorItemFilter, ItemAcceptorComponent } from "../components/item_acceptor"; +import { enumItemType } from "../base_item"; +import { HubComponent } from "../components/hub"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; +import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; +import { UnremovableComponent } from "../components/unremovable"; import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; -import { ItemProcessorComponent, enumItemProcessorTypes } from "../components/item_processor"; -import { globalConfig } from "../../core/config"; -import { UnremovableComponent } from "../components/unremovable"; -import { HubComponent } from "../components/hub"; export class MetaHubBuilding extends MetaBuilding { constructor() { @@ -51,72 +51,72 @@ export class MetaHubBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.top, enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(1, 0), directions: [enumDirection.top], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(2, 0), directions: [enumDirection.top], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(3, 0), directions: [enumDirection.top, enumDirection.right], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(0, 3), directions: [enumDirection.bottom, enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(1, 3), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(2, 3), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(3, 3), directions: [enumDirection.bottom, enumDirection.right], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(0, 1), directions: [enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(0, 2), directions: [enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(0, 3), directions: [enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(3, 1), directions: [enumDirection.right], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(3, 2), directions: [enumDirection.right], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(3, 3), directions: [enumDirection.right], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, ], }) diff --git a/src/js/game/buildings/mixer.js b/src/js/game/buildings/mixer.js index a20bff82..a2b35280 100644 --- a/src/js/game/buildings/mixer.js +++ b/src/js/game/buildings/mixer.js @@ -1,14 +1,14 @@ -import { globalConfig } from "../../core/config"; +import { formatItemsPerSecond } from "../../core/utils"; import { enumDirection, Vector } from "../../core/vector"; -import { ItemAcceptorComponent, enumItemAcceptorItemFilter } from "../components/item_acceptor"; +import { T } from "../../translations"; +import { enumItemType } from "../base_item"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; import { ItemEjectorComponent } from "../components/item_ejector"; import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; import { GameRoot } from "../root"; import { enumHubGoalRewards } from "../tutorial_goals"; -import { T } from "../../translations"; -import { formatItemsPerSecond } from "../../core/utils"; export class MetaMixerBuilding extends MetaBuilding { constructor() { @@ -63,12 +63,12 @@ export class MetaMixerBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.color, + filter: enumItemType.color, }, { pos: new Vector(1, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.color, + filter: enumItemType.color, }, ], }) diff --git a/src/js/game/buildings/painter.js b/src/js/game/buildings/painter.js index 835dde1e..61e77a7c 100644 --- a/src/js/game/buildings/painter.js +++ b/src/js/game/buildings/painter.js @@ -1,14 +1,14 @@ -import { globalConfig } from "../../core/config"; +import { formatItemsPerSecond } from "../../core/utils"; import { enumDirection, Vector } from "../../core/vector"; -import { enumItemAcceptorItemFilter, ItemAcceptorComponent } from "../components/item_acceptor"; +import { T } from "../../translations"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; import { ItemEjectorComponent } from "../components/item_ejector"; import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; import { Entity } from "../entity"; -import { MetaBuilding, defaultBuildingVariant } from "../meta_building"; -import { enumHubGoalRewards } from "../tutorial_goals"; +import { defaultBuildingVariant, MetaBuilding } from "../meta_building"; import { GameRoot } from "../root"; -import { T } from "../../translations"; -import { formatItemsPerSecond } from "../../core/utils"; +import { enumHubGoalRewards } from "../tutorial_goals"; +import { enumItemType } from "../base_item"; /** @enum {string} */ export const enumPainterVariants = { mirrored: "mirrored", double: "double", quad: "quad" }; @@ -98,12 +98,12 @@ export class MetaPainterBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(1, 0), directions: [enumDirection.top], - filter: enumItemAcceptorItemFilter.color, + filter: enumItemType.color, }, ], }) @@ -124,14 +124,14 @@ export class MetaPainterBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(1, 0), directions: [ variant === defaultBuildingVariant ? enumDirection.top : enumDirection.bottom, ], - filter: enumItemAcceptorItemFilter.color, + filter: enumItemType.color, }, ]); @@ -147,17 +147,17 @@ export class MetaPainterBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(0, 1), directions: [enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(1, 0), directions: [enumDirection.top], - filter: enumItemAcceptorItemFilter.color, + filter: enumItemType.color, }, ]); @@ -174,27 +174,27 @@ export class MetaPainterBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.left], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(0, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.color, + filter: enumItemType.color, }, { pos: new Vector(1, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.color, + filter: enumItemType.color, }, { pos: new Vector(2, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.color, + filter: enumItemType.color, }, { pos: new Vector(3, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.color, + filter: enumItemType.color, }, ]); diff --git a/src/js/game/buildings/rotater.js b/src/js/game/buildings/rotater.js index abd3f2c2..56c0c87d 100644 --- a/src/js/game/buildings/rotater.js +++ b/src/js/game/buildings/rotater.js @@ -1,14 +1,14 @@ -import { globalConfig } from "../../core/config"; +import { formatItemsPerSecond } from "../../core/utils"; import { enumDirection, Vector } from "../../core/vector"; -import { ItemAcceptorComponent, enumItemAcceptorItemFilter } from "../components/item_acceptor"; +import { T } from "../../translations"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; import { ItemEjectorComponent } from "../components/item_ejector"; import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; import { Entity } from "../entity"; -import { MetaBuilding, defaultBuildingVariant } from "../meta_building"; -import { enumHubGoalRewards } from "../tutorial_goals"; +import { defaultBuildingVariant, MetaBuilding } from "../meta_building"; import { GameRoot } from "../root"; -import { T } from "../../translations"; -import { formatItemsPerSecond } from "../../core/utils"; +import { enumHubGoalRewards } from "../tutorial_goals"; +import { enumItemType } from "../base_item"; /** @enum {string} */ export const enumRotaterVariants = { ccw: "ccw" }; @@ -77,7 +77,7 @@ export class MetaRotaterBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, ], }) diff --git a/src/js/game/buildings/splitter.js b/src/js/game/buildings/splitter.js index d3c125df..12f0e6e7 100644 --- a/src/js/game/buildings/splitter.js +++ b/src/js/game/buildings/splitter.js @@ -5,7 +5,7 @@ import { ItemEjectorComponent } from "../components/item_ejector"; import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; import { Entity } from "../entity"; import { MetaBuilding, defaultBuildingVariant } from "../meta_building"; -import { GameRoot } from "../root"; +import { GameRoot, enumLayer } from "../root"; import { enumHubGoalRewards } from "../tutorial_goals"; import { T } from "../../translations"; import { formatItemsPerSecond } from "../../core/utils"; @@ -72,16 +72,7 @@ export class MetaSplitterBuilding extends MetaBuilding { setupEntityComponents(entity) { entity.addComponent( new ItemAcceptorComponent({ - slots: [ - { - pos: new Vector(0, 0), - directions: [enumDirection.bottom], - }, - { - pos: new Vector(1, 0), - directions: [enumDirection.bottom], - }, - ], + slots: [], // set later }) ); @@ -94,10 +85,7 @@ export class MetaSplitterBuilding extends MetaBuilding { entity.addComponent( new ItemEjectorComponent({ - slots: [ - { pos: new Vector(0, 0), direction: enumDirection.top }, - { pos: new Vector(1, 0), direction: enumDirection.top }, - ], + slots: [], // set later }) ); } @@ -128,8 +116,8 @@ export class MetaSplitterBuilding extends MetaBuilding { ]); entity.components.ItemAcceptor.beltUnderlays = [ - { pos: new Vector(0, 0), direction: enumDirection.top }, - { pos: new Vector(1, 0), direction: enumDirection.top }, + { pos: new Vector(0, 0), direction: enumDirection.top, layer: enumLayer.regular }, + { pos: new Vector(1, 0), direction: enumDirection.top, layer: enumLayer.regular }, ]; break; @@ -156,7 +144,7 @@ export class MetaSplitterBuilding extends MetaBuilding { ]); entity.components.ItemAcceptor.beltUnderlays = [ - { pos: new Vector(0, 0), direction: enumDirection.top }, + { pos: new Vector(0, 0), direction: enumDirection.top, layer: enumLayer.regular }, ]; break; diff --git a/src/js/game/buildings/stacker.js b/src/js/game/buildings/stacker.js index 9b6f5ef3..91ac3f62 100644 --- a/src/js/game/buildings/stacker.js +++ b/src/js/game/buildings/stacker.js @@ -1,14 +1,14 @@ -import { globalConfig } from "../../core/config"; +import { formatItemsPerSecond } from "../../core/utils"; import { enumDirection, Vector } from "../../core/vector"; -import { ItemAcceptorComponent, enumItemAcceptorItemFilter } from "../components/item_acceptor"; +import { T } from "../../translations"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; import { ItemEjectorComponent } from "../components/item_ejector"; import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; import { Entity } from "../entity"; import { MetaBuilding } from "../meta_building"; import { GameRoot } from "../root"; import { enumHubGoalRewards } from "../tutorial_goals"; -import { formatItemsPerSecond } from "../../core/utils"; -import { T } from "../../translations"; +import { enumItemType } from "../base_item"; export class MetaStackerBuilding extends MetaBuilding { constructor() { @@ -63,12 +63,12 @@ export class MetaStackerBuilding extends MetaBuilding { { pos: new Vector(0, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, { pos: new Vector(1, 0), directions: [enumDirection.bottom], - filter: enumItemAcceptorItemFilter.shape, + filter: enumItemType.shape, }, ], }) diff --git a/src/js/game/buildings/underground_belt.js b/src/js/game/buildings/underground_belt.js index 6d24267b..99004b99 100644 --- a/src/js/game/buildings/underground_belt.js +++ b/src/js/game/buildings/underground_belt.js @@ -5,7 +5,7 @@ import { ItemEjectorComponent } from "../components/item_ejector"; import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt"; import { Entity } from "../entity"; import { MetaBuilding, defaultBuildingVariant } from "../meta_building"; -import { GameRoot } from "../root"; +import { GameRoot, enumLayer } from "../root"; import { globalConfig } from "../../core/config"; import { enumHubGoalRewards } from "../tutorial_goals"; import { formatItemsPerSecond } from "../../core/utils"; @@ -131,13 +131,16 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding { } /** - * @param {GameRoot} root - * @param {Vector} tile - * @param {number} rotation - * @param {string} variant + * Should compute the optimal rotation variant on the given tile + * @param {object} param0 + * @param {GameRoot} param0.root + * @param {Vector} param0.tile + * @param {number} param0.rotation + * @param {string} param0.variant + * @param {string} param0.layer * @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array }} */ - computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation, variant) { + computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) { const searchDirection = enumAngleToDirection[rotation]; const searchVector = enumDirectionToVector[searchDirection]; const tier = enumUndergroundBeltVariantToTier[variant]; @@ -152,7 +155,8 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding { ) { tile = tile.addScalars(searchVector.x, searchVector.y); - const contents = root.map.getTileContent(tile); + /* WIRES: FIXME */ + const contents = root.map.getTileContent(tile, enumLayer.regular); if (contents) { const undergroundComp = contents.components.UndergroundBelt; if (undergroundComp && undergroundComp.tier === tier) { diff --git a/src/js/game/buildings/wire_base.js b/src/js/game/buildings/wire_base.js new file mode 100644 index 00000000..6f3ffec8 --- /dev/null +++ b/src/js/game/buildings/wire_base.js @@ -0,0 +1,52 @@ +import { Loader } from "../../core/loader"; +import { enumDirection } from "../../core/vector"; +import { enumLayer } from "../root"; +import { arrayBeltVariantToRotation, MetaBeltBaseBuilding } from "./belt_base"; + +export class MetaWireBaseBuilding extends MetaBeltBaseBuilding { + constructor() { + super("wire"); + } + + getSilhouetteColor() { + return "#c425d7"; + } + + getLayer() { + return enumLayer.wires; + } + + getPreviewSprite(rotationVariant) { + switch (arrayBeltVariantToRotation[rotationVariant]) { + case enumDirection.top: { + return Loader.getSprite("sprites/buildings/wire_top.png"); + } + case enumDirection.left: { + return Loader.getSprite("sprites/buildings/wire_left.png"); + } + case enumDirection.right: { + return Loader.getSprite("sprites/buildings/wire_right.png"); + } + default: { + assertAlways(false, "Invalid belt rotation variant"); + } + } + } + + getBlueprintSprite(rotationVariant) { + switch (arrayBeltVariantToRotation[rotationVariant]) { + case enumDirection.top: { + return Loader.getSprite("sprites/blueprints/wire_top.png"); + } + case enumDirection.left: { + return Loader.getSprite("sprites/blueprints/wire_left.png"); + } + case enumDirection.right: { + return Loader.getSprite("sprites/blueprints/wire_right.png"); + } + default: { + assertAlways(false, "Invalid belt rotation variant"); + } + } + } +} diff --git a/src/js/game/buildings/wire_crossings.js b/src/js/game/buildings/wire_crossings.js new file mode 100644 index 00000000..111d7ce4 --- /dev/null +++ b/src/js/game/buildings/wire_crossings.js @@ -0,0 +1,120 @@ +import { enumDirection, Vector } from "../../core/vector"; +import { enumItemType } from "../base_item"; +import { ItemAcceptorComponent } from "../components/item_acceptor"; +import { ItemEjectorComponent } from "../components/item_ejector"; +import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; +import { Entity } from "../entity"; +import { defaultBuildingVariant, MetaBuilding } from "../meta_building"; +import { enumLayer, GameRoot } from "../root"; + +/** @enum {string} */ +export const enumWireCrossingVariants = { + // Default = splitter + merger: "merger", +}; + +export class MetaWireCrossingsBuilding extends MetaBuilding { + constructor() { + super("wire_crossings"); + } + + getDimensions(variant) { + return new Vector(1, 1); + } + + getSilhouetteColor() { + return "#c425d7"; + } + + getLayer() { + return enumLayer.wires; + } + + /** + * @param {GameRoot} root + */ + getAvailableVariants(root) { + return [defaultBuildingVariant, enumWireCrossingVariants.merger]; + } + + /** + * @param {GameRoot} root + */ + getIsUnlocked(root) { + return true; + } + + /** + * Creates the entity at the given location + * @param {Entity} entity + */ + setupEntityComponents(entity) { + entity.addComponent( + new ItemAcceptorComponent({ + slots: [], // set later + }) + ); + + entity.addComponent( + new ItemProcessorComponent({ + inputsPerCharge: 1, + processorType: enumItemProcessorTypes.splitterWires, + }) + ); + + entity.addComponent( + new ItemEjectorComponent({ + slots: [], // set later + instantEject: true, + }) + ); + } + + /** + * + * @param {Entity} entity + * @param {number} rotationVariant + * @param {string} variant + */ + updateVariants(entity, rotationVariant, variant) { + switch (variant) { + case defaultBuildingVariant: { + entity.components.ItemAcceptor.setSlots([ + { + pos: new Vector(0, 0), + directions: [enumDirection.bottom], + layer: enumLayer.wires, + }, + ]); + + entity.components.ItemEjector.setSlots([ + { pos: new Vector(0, 0), direction: enumDirection.left, layer: enumLayer.wires }, + { pos: new Vector(0, 0), direction: enumDirection.right, layer: enumLayer.wires }, + ]); + + break; + } + case enumWireCrossingVariants.merger: { + entity.components.ItemAcceptor.setSlots([ + { + pos: new Vector(0, 0), + directions: [enumDirection.left], + layer: enumLayer.wires, + }, + { + pos: new Vector(0, 0), + directions: [enumDirection.right], + layer: enumLayer.wires, + }, + ]); + + entity.components.ItemEjector.setSlots([ + { pos: new Vector(0, 0), direction: enumDirection.top, layer: enumLayer.wires }, + ]); + break; + } + default: + assertAlways(false, "Unknown painter variant: " + variant); + } + } +} diff --git a/src/js/game/camera.js b/src/js/game/camera.js index d2c468c9..ab73fc83 100644 --- a/src/js/game/camera.js +++ b/src/js/game/camera.js @@ -1,12 +1,3 @@ -import { - Math_abs, - Math_ceil, - Math_floor, - Math_max, - Math_min, - Math_random, - performanceNow, -} from "../core/builtins"; import { clickDetectorGlobals } from "../core/click_detector"; import { globalConfig, SUPPORT_TOUCH } from "../core/config"; import { createLogger } from "../core/logging"; @@ -137,8 +128,8 @@ export class Camera extends BasicSerializableObject { addScreenShake(amount) { const currentShakeAmount = this.currentShake.length(); const scale = 1 / (1 + 3 * currentShakeAmount); - this.currentShake.x = this.currentShake.x + 2 * (Math_random() - 0.5) * scale * amount; - this.currentShake.y = this.currentShake.y + 2 * (Math_random() - 0.5) * scale * amount; + this.currentShake.x = this.currentShake.x + 2 * (Math.random() - 0.5) * scale * amount; + this.currentShake.y = this.currentShake.y + 2 * (Math.random() - 0.5) * scale * amount; } /** @@ -181,7 +172,7 @@ export class Camera extends BasicSerializableObject { const zoomLevelX = this.root.gameWidth / desiredWorldSpaceWidth; const zoomLevelY = this.root.gameHeight / desiredWorldSpaceWidth; - const finalLevel = Math_min(zoomLevelX, zoomLevelY); + const finalLevel = Math.min(zoomLevelX, zoomLevelY); assert( Number.isFinite(finalLevel) && finalLevel > 0, "Invalid zoom level computed for initial zoom: " + finalLevel @@ -292,10 +283,10 @@ export class Camera extends BasicSerializableObject { */ getVisibleRect() { return Rectangle.fromTRBL( - Math_floor(this.getViewportTop()), - Math_ceil(this.getViewportRight()), - Math_ceil(this.getViewportBottom()), - Math_floor(this.getViewportLeft()) + Math.floor(this.getViewportTop()), + Math.ceil(this.getViewportRight()), + Math.ceil(this.getViewportBottom()), + Math.floor(this.getViewportLeft()) ); } @@ -426,7 +417,7 @@ export class Camera extends BasicSerializableObject { * should get ignored */ checkPreventDoubleMouse() { - if (performanceNow() - clickDetectorGlobals.lastTouchTime < 1000.0) { + if (performance.now() - clickDetectorGlobals.lastTouchTime < 1000.0) { return false; } return true; @@ -509,6 +500,7 @@ export class Camera extends BasicSerializableObject { event.preventDefault(); // event.stopPropagation(); } + const prevZoom = this.zoomLevel; const delta = Math.sign(event.deltaY) * -0.15 * this.root.app.settings.getScrollWheelSensitivity(); assert(Number.isFinite(delta), "Got invalid delta in mouse wheel event: " + event.deltaY); @@ -518,6 +510,16 @@ export class Camera extends BasicSerializableObject { this.clampZoomLevel(); this.desiredZoom = null; + + const mousePosition = this.root.app.mousePosition; + if (mousePosition) { + const worldPos = this.root.camera.screenToWorld(mousePosition); + const worldDelta = worldPos.sub(this.center); + const actualDelta = this.zoomLevel / prevZoom - 1; + this.center = this.center.add(worldDelta.multiplyScalar(actualDelta)); + this.desiredCenter = null; + } + return false; } @@ -531,7 +533,7 @@ export class Camera extends BasicSerializableObject { // event.stopPropagation(); } - clickDetectorGlobals.lastTouchTime = performanceNow(); + clickDetectorGlobals.lastTouchTime = performance.now(); this.touchPostMoveVelocity = new Vector(0, 0); if (event.touches.length === 1) { @@ -565,7 +567,7 @@ export class Camera extends BasicSerializableObject { // event.stopPropagation(); } - clickDetectorGlobals.lastTouchTime = performanceNow(); + clickDetectorGlobals.lastTouchTime = performance.now(); if (event.touches.length === 1) { const touch = event.touches[0]; @@ -585,7 +587,7 @@ export class Camera extends BasicSerializableObject { const thisDistance = newPinchPositions[0].distance(newPinchPositions[1]); // IMPORTANT to do math max here to avoid NaN and causing an invalid zoom level - const difference = thisDistance / Math_max(0.001, lastDistance); + const difference = thisDistance / Math.max(0.001, lastDistance); // Find old center of zoom let oldCenter = this.lastPinchPositions[0].centerPoint(this.lastPinchPositions[1]); @@ -645,7 +647,7 @@ export class Camera extends BasicSerializableObject { } } - clickDetectorGlobals.lastTouchTime = performanceNow(); + clickDetectorGlobals.lastTouchTime = performance.now(); if (event.changedTouches.length === 0) { logger.warn("Touch end without changed touches"); } @@ -753,7 +755,7 @@ export class Camera extends BasicSerializableObject { * @param {number} dt Delta time in milliseconds */ update(dt) { - dt = Math_min(dt, 33); + dt = Math.min(dt, 33); this.cameraUpdateTimeBucket += dt; // Simulate movement of N FPS @@ -861,7 +863,7 @@ export class Camera extends BasicSerializableObject { internalUpdateZooming(now, dt) { if (!this.currentlyPinching && this.desiredZoom !== null) { const diff = this.zoomLevel - this.desiredZoom; - if (Math_abs(diff) > 0.0001) { + if (Math.abs(diff) > 0.0001) { let fade = 0.94; if (diff > 0) { // Zoom out faster than in @@ -889,7 +891,7 @@ export class Camera extends BasicSerializableObject { const length = diff.length(); const tolerance = 1 / this.zoomLevel; if (length > tolerance) { - const movement = diff.multiplyScalar(Math_min(1, dt * 0.008)); + const movement = diff.multiplyScalar(Math.min(1, dt * 0.008)); this.center.x += movement.x; this.center.y += movement.y; } else { @@ -905,7 +907,7 @@ export class Camera extends BasicSerializableObject { */ internalUpdateKeyboardForce(now, dt) { if (!this.currentlyMoving && this.desiredCenter == null) { - const limitingDimension = Math_min(this.root.gameWidth, this.root.gameHeight); + const limitingDimension = Math.min(this.root.gameWidth, this.root.gameHeight); const moveAmount = ((limitingDimension / 2048) * dt) / this.zoomLevel; diff --git a/src/js/game/colors.js b/src/js/game/colors.js index 6d483771..9c7d0d2d 100644 --- a/src/js/game/colors.js +++ b/src/js/game/colors.js @@ -10,6 +10,8 @@ export const enumColors = { white: "white", uncolored: "uncolored", + + black: "black", }; /** @enum {string} */ @@ -24,6 +26,8 @@ export const enumColorToShortcode = { [enumColors.white]: "w", [enumColors.uncolored]: "u", + + [enumColors.black]: "0", }; /** @enum {enumColors} */ @@ -50,9 +54,27 @@ export const enumColorsToHexCode = { // blue + green + red [enumColors.white]: "#ffffff", + [enumColors.black]: "#31383a", + [enumColors.uncolored]: "#aaaaaa", }; +/** @enum {enumColors} */ +export const enumInvertedColors = { + [enumColors.red]: enumColors.cyan, + [enumColors.green]: enumColors.purple, + [enumColors.blue]: enumColors.yellow, + + [enumColors.yellow]: enumColors.blue, + [enumColors.purple]: enumColors.green, + [enumColors.cyan]: enumColors.red, + + [enumColors.white]: enumColors.black, + [enumColors.black]: enumColors.white, + + [enumColors.uncolored]: enumColors.uncolored, +}; + const c = enumColors; /** @enum {Object.} */ export const enumColorMixingResults = { @@ -66,6 +88,7 @@ export const enumColorMixingResults = { [c.cyan]: c.white, [c.white]: c.white, + [c.black]: c.red, }, // 0, 255, 0 @@ -77,6 +100,7 @@ export const enumColorMixingResults = { [c.cyan]: c.cyan, [c.white]: c.white, + [c.black]: c.green, }, // 0, 255, 0 @@ -86,17 +110,20 @@ export const enumColorMixingResults = { [c.cyan]: c.cyan, [c.white]: c.white, + [c.black]: c.blue, }, // 255, 255, 0 [c.yellow]: { [c.purple]: c.white, [c.cyan]: c.white, + [c.black]: c.yellow, }, // 255, 0, 255 [c.purple]: { [c.cyan]: c.white, + [c.black]: c.purple, }, // 0, 255, 255 @@ -113,14 +140,23 @@ export const enumColorMixingResults = { [c.uncolored]: { // auto }, + + [c.black]: { + // auto + [c.white]: c.uncolored, + [c.cyan]: c.cyan, + [c.uncolored]: c.uncolored, + }, }; // Create same color lookups for (const color in enumColors) { enumColorMixingResults[color][color] = color; - // Anything with white is white again - enumColorMixingResults[color][c.white] = c.white; + // Anything with white is white again, except for black which creates gray + if (color !== enumColors.black) { + enumColorMixingResults[color][c.white] = c.white; + } // Anything with uncolored is the same color enumColorMixingResults[color][c.uncolored] = color; diff --git a/src/js/game/component_registry.js b/src/js/game/component_registry.js index c0077a5a..d3398937 100644 --- a/src/js/game/component_registry.js +++ b/src/js/game/component_registry.js @@ -12,6 +12,7 @@ import { HubComponent } from "./components/hub"; import { StorageComponent } from "./components/storage"; import { EnergyGeneratorComponent } from "./components/energy_generator"; import { WiredPinsComponent } from "./components/wired_pins"; +import { EnergyConsumerComponent } from "./components/energy_consumer"; export function initComponentRegistry() { gComponentRegistry.register(StaticMapEntityComponent); @@ -27,6 +28,7 @@ export function initComponentRegistry() { gComponentRegistry.register(StorageComponent); gComponentRegistry.register(EnergyGeneratorComponent); gComponentRegistry.register(WiredPinsComponent); + gComponentRegistry.register(EnergyConsumerComponent); // IMPORTANT ^^^^^ UPDATE ENTITY COMPONENT STORAGE AFTERWARDS diff --git a/src/js/game/components/belt.js b/src/js/game/components/belt.js index a9be5c99..e9a0cd80 100644 --- a/src/js/game/components/belt.js +++ b/src/js/game/components/belt.js @@ -1,11 +1,11 @@ -import { Component } from "../component"; +import { enumDirection, Vector } from "../../core/vector"; import { types } from "../../savegame/serialization"; -import { gItemRegistry } from "../../core/global_registries"; -import { BaseItem } from "../base_item"; -import { Vector, enumDirection } from "../../core/vector"; -import { Math_PI, Math_sin, Math_cos } from "../../core/builtins"; -import { globalConfig } from "../../core/config"; +import { BeltPath } from "../belt_path"; +import { Component } from "../component"; import { Entity } from "../entity"; +import { enumLayer } from "../root"; + +export const curvedBeltLength = /* Math.PI / 4 */ 0.78; export class BeltComponent extends Component { static getId() { @@ -16,7 +16,6 @@ export class BeltComponent extends Component { // The followUpCache field is not serialized. return { direction: types.string, - sortedItems: types.array(types.pair(types.float, types.obj(gItemRegistry))), }; } @@ -34,77 +33,89 @@ export class BeltComponent extends Component { this.direction = direction; - /** @type {Array<[number, BaseItem]>} */ - this.sortedItems = []; - /** @type {Entity} */ this.followUpCache = null; + + /** + * The path this belt is contained in, not serialized + * @type {BeltPath} + */ + this.assignedPath = null; + } + + /** + * Returns the effective length of this belt in tile space + * @param {enumLayer} layer + * @returns {number} + */ + getEffectiveLengthTiles(layer) { + assert(layer, "no layer given"); + if (layer === enumLayer.wires) { + return 1.0; + } + return this.direction === enumDirection.top ? 1.0 : curvedBeltLength; } /** * Converts from belt space (0 = start of belt ... 1 = end of belt) to the local * belt coordinates (-0.5|-0.5 to 0.5|0.5) * @param {number} progress + * @param {enumLayer} layer * @returns {Vector} */ - transformBeltToLocalSpace(progress) { - switch (this.direction) { - case enumDirection.top: - return new Vector(0, 0.5 - progress); + transformBeltToLocalSpace(progress, layer) { + assert(progress >= 0.0, "Invalid progress ( < 0): " + progress); - case enumDirection.right: { - const arcProgress = progress * 0.5 * Math_PI; - return new Vector(0.5 - 0.5 * Math_cos(arcProgress), 0.5 - 0.5 * Math_sin(arcProgress)); + switch (layer) { + case enumLayer.regular: { + switch (this.direction) { + case enumDirection.top: + assert(progress <= 1.02, "Invalid progress: " + progress); + return new Vector(0, 0.5 - progress); + + case enumDirection.right: { + assert(progress <= curvedBeltLength + 0.02, "Invalid progress 2: " + progress); + const arcProgress = (progress / curvedBeltLength) * 0.5 * Math.PI; + return new Vector( + 0.5 - 0.5 * Math.cos(arcProgress), + 0.5 - 0.5 * Math.sin(arcProgress) + ); + } + case enumDirection.left: { + assert(progress <= curvedBeltLength + 0.02, "Invalid progress 3: " + progress); + const arcProgress = (progress / curvedBeltLength) * 0.5 * Math.PI; + return new Vector( + -0.5 + 0.5 * Math.cos(arcProgress), + 0.5 - 0.5 * Math.sin(arcProgress) + ); + } + default: + assertAlways(false, "Invalid belt direction: " + this.direction); + return new Vector(0, 0); + } } - case enumDirection.left: { - const arcProgress = progress * 0.5 * Math_PI; - return new Vector(-0.5 + 0.5 * Math_cos(arcProgress), 0.5 - 0.5 * Math_sin(arcProgress)); + case enumLayer.wires: { + const pow = 0.5; + switch (this.direction) { + case enumDirection.top: + assert(progress <= 1.02, "Invalid progress: " + progress); + return new Vector(0, 0.5 - progress); + + case enumDirection.right: { + assert(progress <= 1.02, "Invalid progress 2: " + progress); + return progress > 0.5 ? new Vector(progress - 0.5, 0) : new Vector(0, 0.5 - progress); + } + case enumDirection.left: { + assert(progress <= 1.02, "Invalid progress 3: " + progress); + return progress > 0.5 + ? new Vector(-progress + 0.5, 0) + : new Vector(0, 0.5 - progress); + } + default: + assertAlways(false, "Invalid belt direction: " + this.direction); + return new Vector(0, 0); + } } - default: - assertAlways(false, "Invalid belt direction: " + this.direction); - return new Vector(0, 0); } } - - /** - * Returns if the belt can currently accept an item from the given direction - */ - canAcceptItem() { - const firstItem = this.sortedItems[0]; - if (!firstItem) { - return true; - } - - return firstItem[0] > globalConfig.itemSpacingOnBelts; - } - - /** - * Pushes a new item to the belt - * @param {BaseItem} item - */ - takeItem(item, leftoverProgress = 0.0) { - if (G_IS_DEV) { - assert( - this.sortedItems.length === 0 || - leftoverProgress <= this.sortedItems[0][0] - globalConfig.itemSpacingOnBelts + 0.001, - "Invalid leftover: " + - leftoverProgress + - " items are " + - this.sortedItems.map(item => item[0]) - ); - assert(leftoverProgress < 1.0, "Invalid leftover: " + leftoverProgress); - } - this.sortedItems.unshift([leftoverProgress, item]); - } - - /** - * Returns how much space there is to the first item - */ - getDistanceToFirstItemCenter() { - const firstItem = this.sortedItems[0]; - if (!firstItem) { - return 1; - } - return firstItem[0]; - } } diff --git a/src/js/game/components/energy_consumer.js b/src/js/game/components/energy_consumer.js new file mode 100644 index 00000000..6e54af86 --- /dev/null +++ b/src/js/game/components/energy_consumer.js @@ -0,0 +1,133 @@ +import { Component } from "../component"; +import { types } from "../../savegame/serialization"; +import { Vector } from "../../core/vector"; +import { BaseItem, enumItemTypeToLayer, enumItemType } from "../base_item"; + +export class EnergyConsumerComponent extends Component { + static getId() { + return "EnergyConsumer"; + } + + static getSchema() { + return { + bufferSize: types.float, + perCharge: types.float, + batteryPosition: types.vector, + energyType: types.enum(enumItemType), + wasteType: types.enum(enumItemType), + acceptorSlotIndex: types.uint, + ejectorSlotIndex: types.uint, + + stored: types.float, + piledOutput: types.float, + }; + } + + duplicateWithoutContents() { + return new EnergyConsumerComponent({ + bufferSize: this.bufferSize, + perCharge: this.perCharge, + batteryPosition: this.batteryPosition.copy(), + acceptorSlotIndex: this.acceptorSlotIndex, + ejectorSlotIndex: this.ejectorSlotIndex, + }); + } + + /** + * + * @param {object} param0 + * @param {number} param0.bufferSize How much energy this consumer can store + * @param {number} param0.perCharge How much energy this consumer needs per charge + * @param {Vector} param0.batteryPosition world space render offset of the battery icon + * @param {number} param0.acceptorSlotIndex Which slot to accept energy on + * @param {number} param0.ejectorSlotIndex Which slot to eject energy off + * + */ + constructor({ + bufferSize = 3, + perCharge = 1, + batteryPosition = new Vector(), + acceptorSlotIndex = 0, + ejectorSlotIndex = 0, + }) { + super(); + this.bufferSize = bufferSize; + this.perCharge = perCharge; + this.batteryPosition = batteryPosition; + this.energyType = enumItemType.positiveEnergy; + this.wasteType = enumItemType.negativeEnergy; + this.acceptorSlotIndex = acceptorSlotIndex; + this.ejectorSlotIndex = ejectorSlotIndex; + + /** + * How much energy we have stored right now + */ + this.stored = 0; + + /** + * How much waste we have piled up so far + */ + this.piledOutput = 0; + } + + /** + * Tries to accept a given item + * @param {BaseItem} item + * @param {number} slotIndex + */ + tryAcceptItem(item, slotIndex) { + if (slotIndex !== this.acceptorSlotIndex) { + // Wrong slot + return false; + } + + if (item.getItemType() !== this.energyType) { + // Not the right type + return false; + } + + if (this.stored >= this.bufferSize) { + // We are full + return false; + } + + // All good, consume + this.stored = Math.min(this.stored + 1, this.bufferSize); + + return true; + } + + /** + * Tries to start the next charge + */ + tryStartNextCharge() { + if (this.hasTooMuchWastePiled()) { + // Too much waste remaining + return false; + } + + if (this.stored < this.perCharge) { + // Not enough energy stored + return false; + } + + this.stored -= this.perCharge; + this.piledOutput += this.perCharge; + return true; + } + + /** + * Returns if there is too much waste piled + */ + hasTooMuchWastePiled() { + return this.piledOutput >= 1.0; + } + + /** + * Reduces the waste by the given amount + * @param {number} amount + */ + reduceWaste(amount) { + this.piledOutput = Math.max(0, this.piledOutput - amount); + } +} diff --git a/src/js/game/components/energy_generator.js b/src/js/game/components/energy_generator.js index 37e5dd6a..a45492d7 100644 --- a/src/js/game/components/energy_generator.js +++ b/src/js/game/components/energy_generator.js @@ -1,9 +1,9 @@ import { types } from "../../savegame/serialization"; -import { BaseItem } from "../base_item"; +import { BaseItem, enumItemType } from "../base_item"; import { Component } from "../component"; import { ShapeItem } from "../items/shape_item"; -const maxQueueSize = 10; +const maxQueueSize = 4; export class EnergyGeneratorComponent extends Component { static getId() { @@ -12,16 +12,26 @@ export class EnergyGeneratorComponent extends Component { static getSchema() { return { - requiredKey: types.string, + requiredKey: types.nullable(types.string), + itemsInQueue: types.uint, + wasteAcceptorSlotIndex: types.uint, }; } + duplicateWithoutContents() { + return new EnergyGeneratorComponent({ + requiredKey: null, + wasteAcceptorSlotIndex: this.wasteAcceptorSlotIndex, + }); + } + /** * * @param {object} param0 - * @param {string} param0.requiredKey Which shape this generator needs, can be null if not computed yet + * @param {string=} param0.requiredKey Which shape this generator needs, can be null if not computed yet + * @param {number} param0.wasteAcceptorSlotIndex Which slot accepts the waste */ - constructor({ requiredKey }) { + constructor({ requiredKey, wasteAcceptorSlotIndex = 0 }) { super(); this.requiredKey = requiredKey; @@ -30,30 +40,54 @@ export class EnergyGeneratorComponent extends Component { * @type {number} */ this.itemsInQueue = 0; + + /** + * Stores which slot accepts the waste + * @type {number} + */ + this.wasteAcceptorSlotIndex = wasteAcceptorSlotIndex; } /** * * @param {BaseItem} item + * @param {number} slot */ - tryTakeItem(item) { - if (!(item instanceof ShapeItem)) { - // Not a shape - return false; - } + tryTakeItem(item, slot) { + if (slot === this.wasteAcceptorSlotIndex) { + // this is the acceptor slot on the wires layer + // just destroy it + return true; + } else { + if (item.getItemType() !== enumItemType.shape) { + // This shouldn't happen since we have a filter - still, it doesn't hurt + // to check either + assertAlways( + false, + "Energy generator took wrong item: " + + item.getItemType() + + " on slot " + + slot + + " (waste slot = " + + this.wasteAcceptorSlotIndex + + ")" + ); + return false; + } - if (item.definition.getHash() !== this.requiredKey) { - // Not our shape - return false; - } + if (/** @type {ShapeItem} */ (item).definition.getHash() !== this.requiredKey) { + // Not our shape + return false; + } - if (this.itemsInQueue >= maxQueueSize) { - // Queue is full - return false; - } + if (this.itemsInQueue >= maxQueueSize) { + // Queue is full + return false; + } - // Take item and put it into the queue - ++this.itemsInQueue; - return true; + // Take item and put it into the queue + ++this.itemsInQueue; + return true; + } } } diff --git a/src/js/game/components/item_acceptor.js b/src/js/game/components/item_acceptor.js index 6f3895aa..a5676119 100644 --- a/src/js/game/components/item_acceptor.js +++ b/src/js/game/components/item_acceptor.js @@ -1,23 +1,14 @@ -import { Component } from "../component"; -import { Vector, enumDirection, enumInvertedDirections } from "../../core/vector"; -import { BaseItem } from "../base_item"; -import { ShapeItem } from "../items/shape_item"; -import { ColorItem } from "../items/color_item"; +import { enumDirection, enumInvertedDirections, Vector } from "../../core/vector"; import { types } from "../../savegame/serialization"; - -/** - * @enum {string?} - */ -export const enumItemAcceptorItemFilter = { - shape: "shape", - color: "color", - none: null, -}; +import { BaseItem, enumItemType } from "../base_item"; +import { Component } from "../component"; +import { enumLayer } from "../root"; /** @typedef {{ * pos: Vector, * directions: enumDirection[], - * filter?: enumItemAcceptorItemFilter + * layer: enumLayer, + * filter?: enumItemType * }} ItemAcceptorSlot */ /** @@ -28,6 +19,13 @@ export const enumItemAcceptorItemFilter = { * acceptedDirection: enumDirection * }} ItemAcceptorLocatedSlot */ +/** @typedef {{ + * pos: Vector, + * directions: enumDirection[], + * layer?: enumLayer, + * filter?: enumItemType + * }} ItemAcceptorSlotConfig */ + export class ItemAcceptorComponent extends Component { static getId() { return "ItemAcceptor"; @@ -39,7 +37,10 @@ export class ItemAcceptorComponent extends Component { types.structured({ pos: types.vector, directions: types.array(types.enum(enumDirection)), - filter: types.nullable(types.enum(enumItemAcceptorItemFilter)), + filter: types.nullable(types.enum(enumItemType)), + + // TODO: MIGRATE + layer: types.enum(enumLayer), }) ), animated: types.bool, @@ -47,18 +48,11 @@ export class ItemAcceptorComponent extends Component { types.structured({ pos: types.vector, direction: types.enum(enumDirection), + + // TODO: MIGRATE + layer: types.enum(enumLayer), }) ), - - // We don't actually need to store the animations - // itemConsumptionAnimations: types.array( - // types.structured({ - // item: types.obj(gItemRegistry), - // slotIndex: types.uint, - // animProgress: types.float, - // direction: types.enum(enumDirection), - // }) - // ), }; } @@ -70,6 +64,7 @@ export class ItemAcceptorComponent extends Component { pos: slot.pos.copy(), directions: slot.directions.slice(), filter: slot.filter, + layer: slot.layer, }); } @@ -79,6 +74,7 @@ export class ItemAcceptorComponent extends Component { beltUnderlaysCopy.push({ pos: underlay.pos.copy(), direction: underlay.direction, + layer: underlay.layer, }); } @@ -92,9 +88,9 @@ export class ItemAcceptorComponent extends Component { /** * * @param {object} param0 - * @param {Array<{pos: Vector, directions: enumDirection[], filter?: enumItemAcceptorItemFilter}>} param0.slots The slots from which we accept items + * @param {Array} param0.slots The slots from which we accept items * @param {boolean=} param0.animated Whether to animate item consumption - * @param {Array<{pos: Vector, direction: enumDirection}>=} param0.beltUnderlays Where to render belt underlays + * @param {Array<{pos: Vector, direction: enumDirection, layer: enumLayer}>=} param0.beltUnderlays Where to render belt underlays */ constructor({ slots = [], beltUnderlays = [], animated = true }) { super(); @@ -103,7 +99,7 @@ export class ItemAcceptorComponent extends Component { /** * Fixes belt animations - * @type {Array<{ item: BaseItem, slotIndex: number, animProgress: number, direction: enumDirection}>} + * @type {Array<{ item: BaseItem, slotIndex: number, animProgress: number, direction: enumDirection }>} */ this.itemConsumptionAnimations = []; @@ -115,18 +111,19 @@ export class ItemAcceptorComponent extends Component { /** * - * @param {Array<{pos: Vector, directions: enumDirection[], filter?: enumItemAcceptorItemFilter}>} slots + * @param {Array} slots */ setSlots(slots) { - /** @type {Array<{pos: Vector, directions: enumDirection[], filter?: enumItemAcceptorItemFilter}>} */ + /** @type {Array} */ this.slots = []; for (let i = 0; i < slots.length; ++i) { const slot = slots[i]; this.slots.push({ pos: slot.pos, directions: slot.directions, + layer: slot.layer || enumLayer.regular, - // Which type of item to accept (shape | color | all) @see enumItemAcceptorItemFilter + // Which type of item to accept (shape | color | all) @see enumItemType filter: slot.filter, }); } @@ -139,16 +136,25 @@ export class ItemAcceptorComponent extends Component { */ canAcceptItem(slotIndex, item) { const slot = this.slots[slotIndex]; - switch (slot.filter) { - case enumItemAcceptorItemFilter.shape: { - return item instanceof ShapeItem; - } - case enumItemAcceptorItemFilter.color: { - return item instanceof ColorItem; - } - default: - return true; + return this.filterMatches(slot.filter, item); + } + + /** + * Returns if the given filter matches + * @param {enumItemType|null} filter + * @param {BaseItem} item + */ + filterMatches(filter, item) { + if (!filter) { + return true; } + + const itemType = item.getItemType(); + if (filter === enumItemType.genericEnergy) { + return itemType === enumItemType.positiveEnergy || itemType === enumItemType.negativeEnergy; + } + + return itemType === filter; } /** @@ -172,9 +178,10 @@ export class ItemAcceptorComponent extends Component { * Tries to find a slot which accepts the current item * @param {Vector} targetLocalTile * @param {enumDirection} fromLocalDirection + * @param {enumLayer} layer * @returns {ItemAcceptorLocatedSlot|null} */ - findMatchingSlot(targetLocalTile, fromLocalDirection) { + findMatchingSlot(targetLocalTile, fromLocalDirection, layer) { // We need to invert our direction since the acceptor specifies *from* which direction // it accepts items, but the ejector specifies *into* which direction it ejects items. // E.g.: Ejector ejects into "right" direction but acceptor accepts from "left" direction. @@ -189,6 +196,11 @@ export class ItemAcceptorComponent extends Component { continue; } + // Make sure the layer matches + if (slot.layer !== layer) { + continue; + } + // Check if the acceptor slot accepts items from our direction for (let i = 0; i < slot.directions.length; ++i) { // const localDirection = targetStaticComp.localDirectionToWorld(slot.directions[l]); diff --git a/src/js/game/components/item_ejector.js b/src/js/game/components/item_ejector.js index e78faa36..ee661078 100644 --- a/src/js/game/components/item_ejector.js +++ b/src/js/game/components/item_ejector.js @@ -4,12 +4,14 @@ import { Component } from "../component"; import { types } from "../../savegame/serialization"; import { gItemRegistry } from "../../core/global_registries"; import { Entity } from "../entity"; +import { enumLayer } from "../root"; /** * @typedef {{ * pos: Vector, * direction: enumDirection, * item: BaseItem, + * layer: enumLayer, * progress: number?, * cachedDestSlot?: import("./item_acceptor").ItemAcceptorLocatedSlot, * cachedTargetEntity?: Entity @@ -32,6 +34,9 @@ export class ItemEjectorComponent extends Component { direction: types.enum(enumDirection), item: types.nullable(types.obj(gItemRegistry)), progress: types.float, + + // TODO: Migrate + layer: types.enum(enumLayer), }) ), }; @@ -44,6 +49,7 @@ export class ItemEjectorComponent extends Component { slotsCopy.push({ pos: slot.pos.copy(), direction: slot.direction, + layer: slot.layer, }); } @@ -56,7 +62,7 @@ export class ItemEjectorComponent extends Component { /** * * @param {object} param0 - * @param {Array<{pos: Vector, direction: enumDirection}>=} param0.slots The slots to eject on + * @param {Array<{pos: Vector, direction: enumDirection, layer?: enumLayer}>=} param0.slots The slots to eject on * @param {boolean=} param0.instantEject If the ejection is instant */ constructor({ slots = [], instantEject = false }) { @@ -69,10 +75,15 @@ export class ItemEjectorComponent extends Component { /** @type {ItemEjectorSlot[]} */ this.cachedConnectedSlots = null; + + /** + * Whether this ejector slot is enabled + */ + this.enabled = true; } /** - * @param {Array<{pos: Vector, direction: enumDirection}>} slots The slots to eject on + * @param {Array<{pos: Vector, direction: enumDirection, layer?: enumLayer}>} slots The slots to eject on */ setSlots(slots) { /** @type {Array} */ @@ -84,19 +95,13 @@ export class ItemEjectorComponent extends Component { direction: slot.direction, item: null, progress: 0, + layer: slot.layer || enumLayer.regular, cachedDestSlot: null, cachedTargetEntity: null, }); } } - /** - * Returns the amount of slots - */ - getNumSlots() { - return this.slots.length; - } - /** * Returns where this slot ejects to * @param {number} index @@ -111,26 +116,17 @@ export class ItemEjectorComponent extends Component { /** * Returns whether any slot ejects to the given local tile * @param {Vector} tile + * @param {enumLayer} layer */ - anySlotEjectsToLocalTile(tile) { + anySlotEjectsToLocalTile(tile, layer) { for (let i = 0; i < this.slots.length; ++i) { - if (this.getSlotTargetLocalTile(i).equals(tile)) { + if (this.getSlotTargetLocalTile(i).equals(tile) && this.slots[i].layer === layer) { return true; } } return false; } - /** - * Returns if slot # is currently ejecting - * @param {number} slotIndex - * @returns {boolean} - */ - isSlotEjecting(slotIndex) { - assert(slotIndex >= 0 && slotIndex < this.slots.length, "Invalid ejector slot: " + slotIndex); - return !!this.slots[slotIndex].item; - } - /** * Returns if we can eject on a given slot * @param {number} slotIndex @@ -143,43 +139,18 @@ export class ItemEjectorComponent extends Component { /** * Returns the first free slot on this ejector or null if there is none + * @param {enumLayer} layer * @returns {number?} */ - getFirstFreeSlot() { + getFirstFreeSlot(layer) { for (let i = 0; i < this.slots.length; ++i) { - if (this.canEjectOnSlot(i)) { + if (this.canEjectOnSlot(i) && this.slots[i].layer === layer) { return i; } } return null; } - /** - * Returns if any slot is ejecting - * @returns {boolean} - */ - isAnySlotEjecting() { - for (let i = 0; i < this.slots.length; ++i) { - if (this.slots[i].item) { - return true; - } - } - return false; - } - - /** - * Returns if any slot is free - * @returns {boolean} - */ - hasAnySlotFree() { - for (let i = 0; i < this.slots.length; ++i) { - if (this.canEjectOnSlot(i)) { - return true; - } - } - return false; - } - /** * Tries to eject a given item * @param {number} slotIndex @@ -194,4 +165,17 @@ export class ItemEjectorComponent extends Component { this.slots[slotIndex].progress = this.instantEject ? 1 : 0; return true; } + + /** + * Clears the given slot and returns the item it had + * @param {number} slotIndex + * @returns {BaseItem|null} + */ + takeSlotItem(slotIndex) { + const slot = this.slots[slotIndex]; + const item = slot.item; + slot.item = null; + slot.progress = 0.0; + return item; + } } diff --git a/src/js/game/components/item_processor.js b/src/js/game/components/item_processor.js index eab51ae2..72422faf 100644 --- a/src/js/game/components/item_processor.js +++ b/src/js/game/components/item_processor.js @@ -1,12 +1,12 @@ +import { gItemRegistry } from "../../core/global_registries"; +import { types } from "../../savegame/serialization"; import { BaseItem } from "../base_item"; import { Component } from "../component"; -import { enumDirection, Vector } from "../../core/vector"; -import { types } from "../../savegame/serialization"; -import { gItemRegistry } from "../../core/global_registries"; /** @enum {string} */ export const enumItemProcessorTypes = { splitter: "splitter", + splitterWires: "splitterWires", cutter: "cutter", cutterQuad: "cutterQuad", rotater: "rotater", @@ -17,6 +17,7 @@ export const enumItemProcessorTypes = { painter: "painter", painterDouble: "painterDouble", painterQuad: "painterQuad", + advancedProcessor: "advancedProcessor", hub: "hub", }; @@ -102,6 +103,12 @@ export class ItemProcessorComponent extends Component { * @param {number} sourceSlot */ tryTakeItem(item, sourceSlot) { + if (this.type === enumItemProcessorTypes.hub || this.type === enumItemProcessorTypes.trash) { + // Hub has special logic .. not really nice but efficient. + this.inputSlots.push({ item, sourceSlot }); + return true; + } + // Check that we only take one item per slot for (let i = 0; i < this.inputSlots.length; ++i) { const slot = this.inputSlots[i]; diff --git a/src/js/game/components/static_map_entity.js b/src/js/game/components/static_map_entity.js index ed616213..3f0794a4 100644 --- a/src/js/game/components/static_map_entity.js +++ b/src/js/game/components/static_map_entity.js @@ -1,4 +1,3 @@ -import { Math_radians } from "../../core/builtins"; import { globalConfig } from "../../core/config"; import { DrawParameters } from "../../core/draw_parameters"; import { Rectangle } from "../../core/rectangle"; @@ -253,7 +252,7 @@ export class StaticMapEntityComponent extends Component { const rotationCenterY = worldY + globalConfig.halfTileSize; parameters.context.translate(rotationCenterX, rotationCenterY); - parameters.context.rotate(Math_radians(this.rotation)); + parameters.context.rotate(Math.radians(this.rotation)); sprite.drawCached( parameters, @@ -264,7 +263,7 @@ export class StaticMapEntityComponent extends Component { false ); - parameters.context.rotate(-Math_radians(this.rotation)); + parameters.context.rotate(-Math.radians(this.rotation)); parameters.context.translate(-rotationCenterX, -rotationCenterY); } } diff --git a/src/js/game/components/storage.js b/src/js/game/components/storage.js index 69f4e367..e7b40a77 100644 --- a/src/js/game/components/storage.js +++ b/src/js/game/components/storage.js @@ -1,7 +1,7 @@ import { Component } from "../component"; import { types } from "../../savegame/serialization"; import { gItemRegistry } from "../../core/global_registries"; -import { BaseItem } from "../base_item"; +import { BaseItem, enumItemType } from "../base_item"; import { ColorItem } from "../items/color_item"; import { ShapeItem } from "../items/shape_item"; @@ -60,17 +60,23 @@ export class StorageComponent extends Component { return true; } - if (item instanceof ColorItem) { - return this.storedItem instanceof ColorItem && this.storedItem.color === item.color; + const itemType = item.getItemType(); + + // Check type matches + if (itemType !== this.storedItem.getItemType()) { + return false; } - if (item instanceof ShapeItem) { + if (itemType === enumItemType.color) { + return /** @type {ColorItem} */ (this.storedItem).color === /** @type {ColorItem} */ (item).color; + } + + if (itemType === enumItemType.shape) { return ( - this.storedItem instanceof ShapeItem && - this.storedItem.definition.getHash() === item.definition.getHash() + /** @type {ShapeItem} */ (this.storedItem).definition.getHash() === + /** @type {ShapeItem} */ (item).definition.getHash() ); } - return false; } diff --git a/src/js/game/components/underground_belt.js b/src/js/game/components/underground_belt.js index 4fcbbb48..e94b7cb1 100644 --- a/src/js/game/components/underground_belt.js +++ b/src/js/game/components/underground_belt.js @@ -3,6 +3,8 @@ import { Component } from "../component"; import { globalConfig } from "../../core/config"; import { types } from "../../savegame/serialization"; import { gItemRegistry } from "../../core/global_registries"; +import { Entity } from "../entity"; +import { enumLayer } from "../root"; /** @enum {string} */ export const enumUndergroundBeltMode = { @@ -10,6 +12,13 @@ export const enumUndergroundBeltMode = { receiver: "receiver", }; +/** + * @typedef {{ + * entity: Entity, + * distance: number + * }} LinkedUndergroundBelt + */ + export class UndergroundBeltComponent extends Component { static getId() { return "UndergroundBelt"; @@ -52,6 +61,13 @@ export class UndergroundBeltComponent extends Component { * @type {Array<[BaseItem, number]>} Format is [Item, remaining seconds until transfer/ejection] */ this.pendingItems = []; + + /** + * The linked entity, used to speed up performance. This contains either + * the entrance or exit depending on the tunnel type + * @type {LinkedUndergroundBelt} + */ + this.cachedLinkedEntity = null; } /** @@ -87,7 +103,8 @@ export class UndergroundBeltComponent extends Component { } // Notice: We assume that for all items the travel distance is the same - const maxItemsInTunnel = (2 + travelDistance) / globalConfig.itemSpacingOnBelts; + const maxItemsInTunnel = + (2 + travelDistance) / globalConfig.beltItemSpacingByLayer[enumLayer.regular]; if (this.pendingItems.length >= maxItemsInTunnel) { // Simulate a real belt which gets full at some point return false; @@ -97,7 +114,8 @@ export class UndergroundBeltComponent extends Component { // This corresponds to the item ejector - it needs 0.5 additional tiles to eject the item. // So instead of adding 1 we add 0.5 only. // Additionally it takes 1 tile for the acceptor which we just add on top. - const travelDuration = (travelDistance + 1.5) / beltSpeed / globalConfig.itemSpacingOnBelts; + const travelDuration = + (travelDistance + 1.5) / beltSpeed / globalConfig.beltItemSpacingByLayer[enumLayer.regular]; this.pendingItems.push([item, travelDuration]); diff --git a/src/js/game/components/wired_pins.js b/src/js/game/components/wired_pins.js index 8157de5a..0d331a68 100644 --- a/src/js/game/components/wired_pins.js +++ b/src/js/game/components/wired_pins.js @@ -1,21 +1,25 @@ import { Component } from "../component"; -import { Vector } from "../../core/vector"; +import { Vector, enumDirection } from "../../core/vector"; import { types } from "../../savegame/serialization"; /** @enum {string} */ export const enumPinSlotType = { - energyEjector: "energyEjector", + positiveEnergyEjector: "positiveEnergyEjector", + negativeEnergyEjector: "negativeEnergyEjector", + positiveEnergyAcceptor: "positiveEnergyAcceptor", + negativeEnergyAcceptor: "negativeEnergyAcceptor", }; /** @typedef {{ * pos: Vector, - * type: enumPinSlotType + * type: enumPinSlotType, + * direction: enumDirection * }} WirePinSlotDefinition */ /** @typedef {{ * pos: Vector, * type: enumPinSlotType, - * value: number + * direction: enumDirection * }} WirePinSlot */ export class WiredPinsComponent extends Component { @@ -29,7 +33,6 @@ export class WiredPinsComponent extends Component { types.structured({ pos: types.vector, type: types.enum(enumPinSlotType), - value: types.float, }) ), }; @@ -40,11 +43,25 @@ export class WiredPinsComponent extends Component { * @param {object} param0 * @param {Array} param0.slots */ - constructor({ slots }) { + constructor({ slots = [] }) { super(); this.setSlots(slots); } + duplicateWithoutContents() { + const slots = []; + for (let i = 0; i < this.slots.length; ++i) { + const slot = this.slots[i]; + slots.push({ + pos: slot.pos.copy(), + type: slot.type, + direction: slot.direction, + }); + } + + return new WiredPinsComponent({ slots }); + } + /** * Sets the slots of this building * @param {Array} slots @@ -58,7 +75,7 @@ export class WiredPinsComponent extends Component { this.slots.push({ pos: slotData.pos, type: slotData.type, - value: 0.0, + direction: slotData.direction, }); } } diff --git a/src/js/game/core.js b/src/js/game/core.js index 203e005b..960a83e3 100644 --- a/src/js/game/core.js +++ b/src/js/game/core.js @@ -5,7 +5,6 @@ import { Application } from "../application"; import { BufferMaintainer } from "../core/buffer_maintainer"; import { disableImageSmoothing, enableImageSmoothing, registerCanvas } from "../core/buffer_utils"; -import { Math_random } from "../core/builtins"; import { globalConfig } from "../core/config"; import { getDeviceDPI, resizeHighDPICanvas } from "../core/dpi_manager"; import { DrawParameters } from "../core/draw_parameters"; @@ -24,7 +23,7 @@ import { GameHUD } from "./hud/hud"; import { KeyActionMapper } from "./key_action_mapper"; import { GameLogic } from "./logic"; import { MapView } from "./map_view"; -import { GameRoot, enumEditMode } from "./root"; +import { GameRoot, enumLayer } from "./root"; import { ShapeDefinitionManager } from "./shape_definition_manager"; import { SoundProxy } from "./sound_proxy"; import { GameTime } from "./time/game_time"; @@ -131,7 +130,8 @@ export class GameCore { this.root.gameIsFresh = true; this.root.map.seed = randomInt(0, 100000); - gMetaBuildingRegistry.findByClass(MetaHubBuilding).createAndPlaceEntity({ + // Place the hub + const hub = gMetaBuildingRegistry.findByClass(MetaHubBuilding).createEntity({ root: this.root, origin: new Vector(-2, -2), rotation: 0, @@ -139,6 +139,8 @@ export class GameCore { rotationVariant: 0, variant: defaultBuildingVariant, }); + this.root.map.placeStaticEntity(hub); + this.root.entityMgr.registerEntity(hub); } /** @@ -391,33 +393,64 @@ export class GameCore { // Main rendering order // ----- + // BG / Map Resources / Belt Backgrounds root.map.drawBackground(params); if (!this.root.camera.getIsMapOverlayActive()) { - systems.itemAcceptor.drawUnderlays(params); - systems.belt.draw(params); - systems.itemEjector.draw(params); - systems.itemAcceptor.draw(params); + // Underlays for splitters / balancers + systems.itemAcceptor.drawUnderlays(params, enumLayer.regular); + + // Belt items + systems.belt.drawLayerBeltItems(params, enumLayer.regular); + + // Items being ejected / accepted currently (animations) + systems.itemEjector.drawLayer(params, enumLayer.regular); + systems.itemAcceptor.drawLayer(params, enumLayer.regular); } + // Miner & Static map entities root.map.drawForeground(params); + if (!this.root.camera.getIsMapOverlayActive()) { + // HUB Overlay systems.hub.draw(params); + + // Energy generator overlay systems.energyGenerator.draw(params); + + // Storage items systems.storage.draw(params); + + // Energy consumer (Battery icons) + systems.energyConsumer.draw(params); } - // WIRES LAYER + // Green wires overlay (not within the if because it can fade) root.hud.parts.wiresOverlay.draw(params); - if (this.root.editMode === enumEditMode.wires) { - systems.wiredPins.drawWiresLayer(params); + if (this.root.currentLayer === enumLayer.wires && !this.root.camera.getIsMapOverlayActive()) { + // Belt sprites & Static map entities + root.map.drawWiresLayer(params); + + // Belt items as well as accepted / ejected items + systems.belt.drawLayerBeltItems(params, enumLayer.wires); + systems.itemEjector.drawLayer(params, enumLayer.wires); + systems.itemAcceptor.drawLayer(params, enumLayer.wires); + + root.map.drawWiresForegroundLayer(params); + + // pins + systems.wiredPins.draw(params); } if (G_IS_DEV) { root.map.drawStaticEntityDebugOverlays(params); } + if (G_IS_DEV && globalConfig.debug.renderBeltPaths) { + systems.belt.drawBeltPathDebug(params); + } + // END OF GAME CONTENT // ----- @@ -439,7 +472,7 @@ export class GameCore { for (let i = 0; i < 1e8; ++i) { sum += i; } - if (Math_random() > 0.95) { + if (Math.random() > 0.95) { console.log(sum); } } diff --git a/src/js/game/dynamic_tickrate.js b/src/js/game/dynamic_tickrate.js index 076532d5..f289e2c1 100644 --- a/src/js/game/dynamic_tickrate.js +++ b/src/js/game/dynamic_tickrate.js @@ -1,7 +1,6 @@ import { GameRoot } from "./root"; import { createLogger } from "../core/logging"; import { globalConfig } from "../core/config"; -import { performanceNow, Math_min, Math_round, Math_max } from "../core/builtins"; import { round3Digits } from "../core/utils"; const logger = createLogger("dynamic_tickrate"); @@ -35,7 +34,7 @@ export class DynamicTickrate { onFrameRendered() { ++this.accumulatedFps; - const now = performanceNow(); + const now = performance.now(); const timeDuration = now - this.accumulatedFpsLastUpdate; if (timeDuration > fpsAccumulationTime) { const avgFps = (this.accumulatedFps / fpsAccumulationTime) * 1000; @@ -65,7 +64,7 @@ export class DynamicTickrate { } const desiredFps = this.root.app.settings.getDesiredFps(); - this.setTickRate(Math_round(Math_min(desiredFps, this.currentTickRate * 1.2))); + this.setTickRate(Math.round(Math.min(desiredFps, this.currentTickRate * 1.2))); } /** @@ -77,7 +76,7 @@ export class DynamicTickrate { } const desiredFps = this.root.app.settings.getDesiredFps(); - this.setTickRate(Math_round(Math_max(desiredFps / 2, this.currentTickRate * 0.8))); + this.setTickRate(Math.round(Math.max(desiredFps / 2, this.currentTickRate * 0.8))); } /** @@ -85,7 +84,7 @@ export class DynamicTickrate { */ beginTick() { assert(this.currentTickStart === null, "BeginTick called twice"); - this.currentTickStart = performanceNow(); + this.currentTickStart = performance.now(); if (this.capturedTicks.length > this.currentTickRate * 2) { // Take only a portion of the ticks @@ -119,7 +118,7 @@ export class DynamicTickrate { */ endTick() { assert(this.currentTickStart !== null, "EndTick called without BeginTick"); - const duration = performanceNow() - this.currentTickStart; + const duration = performance.now() - this.currentTickStart; this.capturedTicks.push(duration); this.currentTickStart = null; } diff --git a/src/js/game/entity.js b/src/js/game/entity.js index 9dea1c2b..c86aa3b7 100644 --- a/src/js/game/entity.js +++ b/src/js/game/entity.js @@ -1,16 +1,15 @@ /* typehints:start */ -import { GameRoot } from "./root"; import { DrawParameters } from "../core/draw_parameters"; import { Component } from "./component"; /* typehints:end */ +import { GameRoot, enumLayer } from "./root"; import { globalConfig } from "../core/config"; import { enumDirectionToVector, enumDirectionToAngle } from "../core/vector"; import { BasicSerializableObject, types } from "../savegame/serialization"; import { EntityComponentStorage } from "./entity_components"; import { Loader } from "../core/loader"; import { drawRotatedSprite } from "../core/draw_utils"; -import { Math_radians } from "../core/builtins"; import { gComponentRegistry } from "../core/global_registries"; export class Entity extends BasicSerializableObject { @@ -35,6 +34,11 @@ export class Entity extends BasicSerializableObject { */ this.registered = false; + /** + * On which layer this entity is + */ + this.layer = enumLayer.regular; + /** * Internal entity unique id, set by the @see EntityManager */ @@ -73,6 +77,7 @@ export class Entity extends BasicSerializableObject { return { uid: types.uint, components: types.keyValueMap(types.objData(gComponentRegistry)), + layer: types.enum(enumLayer), }; } @@ -84,6 +89,7 @@ export class Entity extends BasicSerializableObject { for (const key in this.components) { clone.components[key] = this.components[key].duplicateWithoutContents(); } + clone.layer = this.layer; return clone; } @@ -163,10 +169,13 @@ export class Entity extends BasicSerializableObject { const ejectorSprite = Loader.getSprite("sprites/debug/ejector_slot.png"); for (let i = 0; i < ejectorComp.slots.length; ++i) { const slot = ejectorComp.slots[i]; + if (slot.layer !== this.root.currentLayer) { + continue; + } const slotTile = staticComp.localTileToWorld(slot.pos); const direction = staticComp.localDirectionToWorld(slot.direction); const directionVector = enumDirectionToVector[direction]; - const angle = Math_radians(enumDirectionToAngle[direction]); + const angle = Math.radians(enumDirectionToAngle[direction]); context.globalAlpha = slot.item ? 1 : 0.2; drawRotatedSprite({ @@ -185,11 +194,14 @@ export class Entity extends BasicSerializableObject { const acceptorSprite = Loader.getSprite("sprites/debug/acceptor_slot.png"); for (let i = 0; i < acceptorComp.slots.length; ++i) { const slot = acceptorComp.slots[i]; + if (slot.layer !== this.root.currentLayer) { + continue; + } const slotTile = staticComp.localTileToWorld(slot.pos); for (let k = 0; k < slot.directions.length; ++k) { const direction = staticComp.localDirectionToWorld(slot.directions[k]); const directionVector = enumDirectionToVector[direction]; - const angle = Math_radians(enumDirectionToAngle[direction] + 180); + const angle = Math.radians(enumDirectionToAngle[direction] + 180); context.globalAlpha = 0.4; drawRotatedSprite({ parameters, diff --git a/src/js/game/entity_components.js b/src/js/game/entity_components.js index fc29ce80..24430dd2 100644 --- a/src/js/game/entity_components.js +++ b/src/js/game/entity_components.js @@ -12,6 +12,7 @@ import { HubComponent } from "./components/hub"; import { StorageComponent } from "./components/storage"; import { EnergyGeneratorComponent } from "./components/energy_generator"; import { WiredPinsComponent } from "./components/wired_pins"; +import { EnergyConsumerComponent } from "./components/energy_consumer"; /* typehints:end */ /** @@ -20,9 +21,6 @@ import { WiredPinsComponent } from "./components/wired_pins"; */ export class EntityComponentStorage { constructor() { - // TODO: Figure out if its faster to declare all components here and not - // compile them out (In theory, should make it a fast object in V8 engine) - /* typehints:start */ /** @type {StaticMapEntityComponent} */ @@ -64,6 +62,9 @@ export class EntityComponentStorage { /** @type {WiredPinsComponent} */ this.WiredPins; + /** @type {EnergyConsumerComponent} */ + this.EnergyConsumer; + /* typehints:end */ } } diff --git a/src/js/game/entity_manager.js b/src/js/game/entity_manager.js index c3c94fbc..11bc709c 100644 --- a/src/js/game/entity_manager.js +++ b/src/js/game/entity_manager.js @@ -9,7 +9,7 @@ const logger = createLogger("entity_manager"); // Manages all entities -// TODO & NOTICE: We use arrayDeleteValue instead of fastArrayDeleteValue since that does not preserve the order +// NOTICE: We use arrayDeleteValue instead of fastArrayDeleteValue since that does not preserve the order // This is slower but we need it for the street path generation export class EntityManager extends BasicSerializableObject { diff --git a/src/js/game/game_system_manager.js b/src/js/game/game_system_manager.js index 144380b2..ed9d1155 100644 --- a/src/js/game/game_system_manager.js +++ b/src/js/game/game_system_manager.js @@ -15,6 +15,7 @@ import { ItemAcceptorSystem } from "./systems/item_acceptor"; import { StorageSystem } from "./systems/storage"; import { EnergyGeneratorSystem } from "./systems/energy_generator"; import { WiredPinsSystem } from "./systems/wired_pins"; +import { EnergyConsumerSystem } from "./systems/energy_consumer"; const logger = createLogger("game_system_manager"); @@ -64,6 +65,9 @@ export class GameSystemManager { /** @type {WiredPinsSystem} */ wiredPins: null, + /** @type {EnergyConsumerSystem} */ + energyConsumer: null, + /* typehints:end */ }; this.systemUpdateOrder = []; @@ -104,6 +108,8 @@ export class GameSystemManager { add("wiredPins", WiredPinsSystem); + add("energyConsumer", EnergyConsumerSystem); + // IMPORTANT: Must be after belt system since belt system can change the // orientation of an entity after it is placed -> the item acceptor cache // then would be invalid diff --git a/src/js/game/game_system_with_filter.js b/src/js/game/game_system_with_filter.js index d1fddc7f..82ab4c22 100644 --- a/src/js/game/game_system_with_filter.js +++ b/src/js/game/game_system_with_filter.js @@ -1,15 +1,13 @@ /* typehints:start */ import { Component } from "./component"; -import { GameRoot } from "./root"; import { Entity } from "./entity"; /* typehints:end */ +import { GameRoot, enumLayer } from "./root"; import { GameSystem } from "./game_system"; import { arrayDelete, arrayDeleteValue } from "../core/utils"; import { DrawParameters } from "../core/draw_parameters"; import { globalConfig } from "../core/config"; -import { Math_floor, Math_ceil } from "../core/builtins"; - export class GameSystemWithFilter extends GameSystem { /** * Constructs a new game system with the given component filter. It will process @@ -41,8 +39,9 @@ export class GameSystemWithFilter extends GameSystem { * Calls a function for each matching entity on the screen, useful for drawing them * @param {DrawParameters} parameters * @param {function} callback + * @param {enumLayer=} layerFilter Can be null for no filter */ - forEachMatchingEntityOnScreen(parameters, callback) { + forEachMatchingEntityOnScreen(parameters, callback, layerFilter = null) { const cullRange = parameters.visibleRect.toTileCullRectangle(); if (this.allEntities.length < 100) { // So, its much quicker to simply perform per-entity checking @@ -50,7 +49,9 @@ export class GameSystemWithFilter extends GameSystem { for (let i = 0; i < this.allEntities.length; ++i) { const entity = this.allEntities[i]; if (cullRange.containsRect(entity.components.StaticMapEntity.getTileSpaceBounds())) { - callback(parameters, entity); + if (!layerFilter || entity.layer === layerFilter) { + callback(parameters, entity); + } } } return; @@ -71,11 +72,11 @@ export class GameSystemWithFilter extends GameSystem { let seenUids = new Set(); - const chunkStartX = Math_floor(minX / globalConfig.mapChunkSize); - const chunkStartY = Math_floor(minY / globalConfig.mapChunkSize); + const chunkStartX = Math.floor(minX / globalConfig.mapChunkSize); + const chunkStartY = Math.floor(minY / globalConfig.mapChunkSize); - const chunkEndX = Math_ceil(maxX / globalConfig.mapChunkSize); - const chunkEndY = Math_ceil(maxY / globalConfig.mapChunkSize); + const chunkEndX = Math.ceil(maxX / globalConfig.mapChunkSize); + const chunkEndY = Math.ceil(maxY / globalConfig.mapChunkSize); const requiredComponents = this.requiredComponentIds; @@ -93,10 +94,16 @@ export class GameSystemWithFilter extends GameSystem { entityLoop: for (let i = 0; i < entities.length; ++i) { const entity = entities[i]; + // Avoid drawing non-layer contents + if (layerFilter && entity.layer !== layerFilter) { + continue; + } + // Avoid drawing twice if (seenUids.has(entity.uid)) { continue; } + seenUids.add(entity.uid); for (let i = 0; i < requiredComponents.length; ++i) { diff --git a/src/js/game/hub_goals.js b/src/js/game/hub_goals.js index 9f65dc4c..612bc124 100644 --- a/src/js/game/hub_goals.js +++ b/src/js/game/hub_goals.js @@ -1,11 +1,10 @@ -import { Math_random } from "../core/builtins"; import { globalConfig } from "../core/config"; import { queryParamOptions } from "../core/query_parameters"; import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils"; import { BasicSerializableObject, types } from "../savegame/serialization"; import { enumColors } from "./colors"; import { enumItemProcessorTypes } from "./components/item_processor"; -import { GameRoot } from "./root"; +import { GameRoot, enumLayer } from "./root"; import { enumSubShape, ShapeDefinition } from "./shape_definition"; import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals"; import { UPGRADES, blueprintShape } from "./upgrades"; @@ -53,6 +52,17 @@ export class HubGoals extends BasicSerializableObject { } this.upgradeImprovements[upgradeId] = totalImprovement; } + + // Compute current goal + const goal = tutorialGoals[this.level - 1]; + if (goal) { + this.currentGoal = { + /** @type {ShapeDefinition} */ + definition: this.root.shapeDefinitionMgr.getShapeFromShortKey(goal.shape), + required: goal.required, + reward: goal.reward, + }; + } } /** @@ -96,13 +106,14 @@ export class HubGoals extends BasicSerializableObject { // Allow quickly switching goals in dev mode if (G_IS_DEV) { - if (G_IS_DEV) { - window.addEventListener("keydown", ev => { - if (ev.key === "b") { + window.addEventListener("keydown", ev => { + if (ev.key === "b") { + // root is not guaranteed to exist within ~0.5s after loading in + if (this.root && this.root.app && this.root.app.gameAnalytics) { this.onGoalCompleted(); } - }); - } + } + }); } } @@ -202,7 +213,7 @@ export class HubGoals extends BasicSerializableObject { this.currentGoal = { /** @type {ShapeDefinition} */ definition: this.createRandomShape(), - required: 1000 + findNiceIntegerValue(this.level * 47.5), + required: 10000 + findNiceIntegerValue(this.level * 2000), reward: enumHubGoalRewards.no_reward_freeplay, }; } @@ -313,7 +324,7 @@ export class HubGoals extends BasicSerializableObject { * @returns {ShapeDefinition} */ createRandomShape() { - const layerCount = clamp(this.level / 50, 2, 4); + const layerCount = clamp(this.level / 25, 2, 4); /** @type {Array} */ let layers = []; @@ -336,14 +347,14 @@ export class HubGoals extends BasicSerializableObject { } // Sometimes shapes are missing - if (Math_random() > 0.85) { + if (Math.random() > 0.85) { layer[randomInt(0, 3)] = null; } // Sometimes they actually are missing *two* ones! // Make sure at max only one layer is missing it though, otherwise we could // create an uncreateable shape - if (Math_random() > 0.95 && !anyIsMissingTwo) { + if (Math.random() > 0.95 && !anyIsMissingTwo) { layer[randomInt(0, 3)] = null; anyIsMissingTwo = true; } @@ -359,9 +370,13 @@ export class HubGoals extends BasicSerializableObject { /** * Belt speed + * @param {enumLayer} layer * @returns {number} items / sec */ - getBeltBaseSpeed() { + getBeltBaseSpeed(layer) { + if (layer === enumLayer.wires) { + return globalConfig.wiresSpeedItemsPerSecond; + } return globalConfig.beltSpeedItemsPerSecond * this.upgradeImprovements.belt; } @@ -388,6 +403,9 @@ export class HubGoals extends BasicSerializableObject { */ getProcessorBaseSpeed(processorType) { switch (processorType) { + case enumItemProcessorTypes.splitterWires: + return globalConfig.wiresSpeedItemsPerSecond * 2; + case enumItemProcessorTypes.trash: case enumItemProcessorTypes.hub: return 1e30; @@ -424,6 +442,9 @@ export class HubGoals extends BasicSerializableObject { globalConfig.buildingSpeeds[processorType] ); } + case enumItemProcessorTypes.advancedProcessor: { + return globalConfig.beltSpeedItemsPerSecond * globalConfig.buildingSpeeds[processorType]; + } default: assertAlways(false, "invalid processor type: " + processorType); } diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js index f9c28d93..1d72deb5 100644 --- a/src/js/game/hud/hud.js +++ b/src/js/game/hud/hud.js @@ -38,6 +38,9 @@ import { HUDColorBlindHelper } from "./parts/color_blind_helper"; import { HUDShapeViewer } from "./parts/shape_viewer"; import { HUDWiresOverlay } from "./parts/wires_overlay"; import { HUDChangesDebugger } from "./parts/debug_changes"; +import { queryParamOptions } from "../../core/query_parameters"; +import { HUDSandboxController } from "./parts/sandbox_controller"; +import { HUDWiresToolbar } from "./parts/wires_toolbar"; export class GameHUD { /** @@ -54,6 +57,7 @@ export class GameHUD { this.parts = { processingOverlay: new HUDProcessingOverlay(this.root), buildingsToolbar: new HUDBuildingsToolbar(this.root), + wiresToolbar: new HUDWiresToolbar(this.root), blueprintPlacer: new HUDBlueprintPlacer(this.root), buildingPlacer: new HUDBuildingPlacer(this.root), unlockNotification: new HUDUnlockNotification(this.root), @@ -72,13 +76,18 @@ export class GameHUD { dialogs: new HUDModalDialogs(this.root), screenshotExporter: new HUDScreenshotExporter(this.root), shapeViewer: new HUDShapeViewer(this.root), + wiresOverlay: new HUDWiresOverlay(this.root), + // Typing hints + /* typehints:start */ /** @type {HUDChangesDebugger} */ changesDebugger: null, + /* typehints:end */ }; this.signals = { + buildingSelectedForPlacement: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()), selectedPlacementBuildingChanged: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()), shapePinRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()), shapeUnpinRequested: /** @type {TypedSignal<[string]>} */ (new Signal()), @@ -117,6 +126,10 @@ export class GameHUD { this.parts.colorBlindHelper = new HUDColorBlindHelper(this.root); } + if (queryParamOptions.sandboxMode || G_IS_DEV) { + this.parts.sandboxController = new HUDSandboxController(this.root); + } + const frag = document.createDocumentFragment(); for (const key in this.parts) { this.parts[key].createElements(frag); @@ -127,7 +140,6 @@ export class GameHUD { for (const key in this.parts) { this.parts[key].initialize(); } - this.internalInitSignalConnections(); this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this); @@ -193,14 +205,6 @@ export class GameHUD { document.body.classList.toggle("uiHidden"); } - /** - * Initializes connections between parts - */ - internalInitSignalConnections() { - const p = this.parts; - p.buildingsToolbar.sigBuildingSelected.add(p.buildingPlacer.startSelection, p.buildingPlacer); - } - /** * Updates all parts */ diff --git a/src/js/game/hud/parts/base_toolbar.js b/src/js/game/hud/parts/base_toolbar.js index c5abf8a3..f5ec24c6 100644 --- a/src/js/game/hud/parts/base_toolbar.js +++ b/src/js/game/hud/parts/base_toolbar.js @@ -1,23 +1,26 @@ import { gMetaBuildingRegistry } from "../../../core/global_registries"; -import { Signal } from "../../../core/signal"; -import { TrackedState } from "../../../core/tracked_state"; +import { Signal, STOP_PROPAGATION } from "../../../core/signal"; import { makeDiv } from "../../../core/utils"; import { KEYMAPPINGS } from "../../key_action_mapper"; import { MetaBuilding } from "../../meta_building"; -import { BaseHUDPart } from "../base_hud_part"; import { GameRoot } from "../../root"; +import { BaseHUDPart } from "../base_hud_part"; +import { DynamicDomAttach } from "../dynamic_dom_attach"; export class HUDBaseToolbar extends BaseHUDPart { /** * @param {GameRoot} root - * @param {Array} supportedBuildings - * @param {function} visibilityCondition + * @param {object} param0 + * @param {Array} param0.supportedBuildings + * @param {function} param0.visibilityCondition + * @param {string} param0.htmlElementId */ - constructor(root, supportedBuildings, visibilityCondition) { + constructor(root, { supportedBuildings, visibilityCondition, htmlElementId }) { super(root); this.supportedBuildings = supportedBuildings; this.visibilityCondition = visibilityCondition; + this.htmlElementId = htmlElementId; /** @type {Object.} */ this.buildingHandles = {}; - - this.sigBuildingSelected = new Signal(); - this.trackedIsVisisible = new TrackedState(this.onVisibilityChanged, this); - } - - /** - * Called when the visibility of the toolbar changed - * @param {boolean} visible - */ - onVisibilityChanged(visible) { - this.element.classList.toggle("visible", visible); } /** @@ -45,7 +37,7 @@ export class HUDBaseToolbar extends BaseHUDPart { * @param {HTMLElement} parent */ createElements(parent) { - this.element = makeDiv(parent, "ingame_HUD_buildings_toolbar", ["ingame_buildingsToolbar"], ""); + this.element = makeDiv(parent, this.htmlElementId, ["ingame_buildingsToolbar"], ""); } initialize() { @@ -80,6 +72,10 @@ export class HUDBaseToolbar extends BaseHUDPart { this ); + this.domAttach = new DynamicDomAttach(this.root, this.element, { + timeToKeepSeconds: 0.12, + attachClass: "visible", + }); this.lastSelectedIndex = 0; actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this); } @@ -88,11 +84,10 @@ export class HUDBaseToolbar extends BaseHUDPart { * Updates the toolbar */ update() { - this.trackedIsVisisible.set(this.visibilityCondition()); + const visible = this.visibilityCondition(); + this.domAttach.update(visible); - if (!this.trackedIsVisisible.get()) { - // Currently not active - } else { + if (visible) { for (const buildingId in this.buildingHandles) { const handle = this.buildingHandles[buildingId]; const newStatus = handle.metaBuilding.getIsUnlocked(this.root); @@ -108,15 +103,25 @@ export class HUDBaseToolbar extends BaseHUDPart { * Cycles through all buildings */ cycleBuildings() { + const visible = this.visibilityCondition(); + if (!visible) { + return; + } + + let newBuildingFound = false; let newIndex = this.lastSelectedIndex; for (let i = 0; i < this.supportedBuildings.length; ++i, ++newIndex) { newIndex %= this.supportedBuildings.length; const metaBuilding = gMetaBuildingRegistry.findByClass(this.supportedBuildings[newIndex]); const handle = this.buildingHandles[metaBuilding.id]; if (!handle.selected && handle.unlocked) { + newBuildingFound = true; break; } } + if (!newBuildingFound) { + return; + } const metaBuildingClass = this.supportedBuildings[newIndex]; const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass); this.selectBuildingForPlacement(metaBuilding); @@ -166,7 +171,7 @@ export class HUDBaseToolbar extends BaseHUDPart { } this.root.soundProxy.playUiClick(); - this.sigBuildingSelected.dispatch(metaBuilding); + this.root.hud.signals.buildingSelectedForPlacement.dispatch(metaBuilding); this.onSelectedPlacementBuildingChanged(metaBuilding); } } diff --git a/src/js/game/hud/parts/blueprint.js b/src/js/game/hud/parts/blueprint.js deleted file mode 100644 index c53163d9..00000000 --- a/src/js/game/hud/parts/blueprint.js +++ /dev/null @@ -1,238 +0,0 @@ -import { DrawParameters } from "../../../core/draw_parameters"; -import { Loader } from "../../../core/loader"; -import { createLogger } from "../../../core/logging"; -import { Vector } from "../../../core/vector"; -import { Entity } from "../../entity"; -import { GameRoot } from "../../root"; -import { findNiceIntegerValue } from "../../../core/utils"; -import { Math_pow } from "../../../core/builtins"; -import { blueprintShape } from "../../upgrades"; -import { globalConfig } from "../../../core/config"; - -const logger = createLogger("blueprint"); - -export class Blueprint { - /** - * @param {Array} entities - */ - constructor(entities) { - this.entities = entities; - } - - /** - * Creates a new blueprint from the given entity uids - * @param {GameRoot} root - * @param {Array} uids - */ - static fromUids(root, uids) { - const newEntities = []; - - let averagePosition = new Vector(); - - // First, create a copy - for (let i = 0; i < uids.length; ++i) { - const entity = root.entityMgr.findByUid(uids[i]); - assert(entity, "Entity for blueprint not found:" + uids[i]); - - const clone = entity.duplicateWithoutContents(); - newEntities.push(clone); - - const pos = entity.components.StaticMapEntity.getTileSpaceBounds().getCenter(); - averagePosition.addInplace(pos); - } - - averagePosition.divideScalarInplace(uids.length); - const blueprintOrigin = averagePosition.floor(); - for (let i = 0; i < uids.length; ++i) { - newEntities[i].components.StaticMapEntity.origin.subInplace(blueprintOrigin); - } - - // Now, make sure the origin is 0,0 - return new Blueprint(newEntities); - } - - /** - * Returns the cost of this blueprint in shapes - */ - getCost() { - if (G_IS_DEV && globalConfig.debug.blueprintsNoCost) { - return 0; - } - return findNiceIntegerValue(4 * Math_pow(this.entities.length, 1.1)); - } - - /** - * Draws the blueprint at the given origin - * @param {DrawParameters} parameters - */ - draw(parameters, tile) { - parameters.context.globalAlpha = 0.8; - for (let i = 0; i < this.entities.length; ++i) { - const entity = this.entities[i]; - const staticComp = entity.components.StaticMapEntity; - if (!staticComp.blueprintSpriteKey) { - logger.warn("Blueprint entity without sprite!"); - return; - } - const newPos = staticComp.origin.add(tile); - - const rect = staticComp.getTileSpaceBounds(); - rect.moveBy(tile.x, tile.y); - - let placeable = true; - placementCheck: for (let x = rect.x; x < rect.right(); ++x) { - for (let y = rect.y; y < rect.bottom(); ++y) { - if (parameters.root.map.isTileUsedXY(x, y)) { - placeable = false; - break placementCheck; - } - } - } - - if (!placeable) { - parameters.context.globalAlpha = 0.3; - } else { - parameters.context.globalAlpha = 1; - } - - staticComp.drawSpriteOnFullEntityBounds( - parameters, - Loader.getSprite(staticComp.blueprintSpriteKey), - 0, - true, - newPos - ); - } - parameters.context.globalAlpha = 1; - } - - /** - * Rotates the blueprint clockwise - */ - rotateCw() { - for (let i = 0; i < this.entities.length; ++i) { - const entity = this.entities[i]; - const staticComp = entity.components.StaticMapEntity; - - staticComp.rotation = (staticComp.rotation + 90) % 360; - staticComp.originalRotation = (staticComp.originalRotation + 90) % 360; - staticComp.origin = staticComp.origin.rotateFastMultipleOf90(90); - } - } - - /** - * Rotates the blueprint counter clock wise - */ - rotateCcw() { - // Well ... - for (let i = 0; i < 3; ++i) { - this.rotateCw(); - } - } - - /** - * Checks if the blueprint can be placed at the given tile - * @param {GameRoot} root - * @param {Vector} tile - */ - canPlace(root, tile) { - let anyPlaceable = false; - - for (let i = 0; i < this.entities.length; ++i) { - let placeable = true; - const entity = this.entities[i]; - const staticComp = entity.components.StaticMapEntity; - const rect = staticComp.getTileSpaceBounds(); - rect.moveBy(tile.x, tile.y); - placementCheck: for (let x = rect.x; x < rect.right(); ++x) { - for (let y = rect.y; y < rect.bottom(); ++y) { - if (root.map.isTileUsedXY(x, y)) { - placeable = false; - break placementCheck; - } - } - } - - if (placeable) { - anyPlaceable = true; - } - } - - return anyPlaceable; - } - - /** - * @param {GameRoot} root - */ - canAfford(root) { - return root.hubGoals.getShapesStoredByKey(blueprintShape) >= this.getCost(); - } - - /** - * Attempts to place the blueprint at the given tile - * @param {GameRoot} root - * @param {Vector} tile - */ - tryPlace(root, tile) { - return root.logic.performBulkOperation(() => { - let anyPlaced = false; - const beltsToRegisterLater = []; - for (let i = 0; i < this.entities.length; ++i) { - let placeable = true; - const entity = this.entities[i]; - const staticComp = entity.components.StaticMapEntity; - const rect = staticComp.getTileSpaceBounds(); - rect.moveBy(tile.x, tile.y); - placementCheck: for (let x = rect.x; x < rect.right(); ++x) { - for (let y = rect.y; y < rect.bottom(); ++y) { - const contents = root.map.getTileContentXY(x, y); - if (contents && !contents.components.ReplaceableMapEntity) { - placeable = false; - break placementCheck; - } - } - } - - if (placeable) { - for (let x = rect.x; x < rect.right(); ++x) { - for (let y = rect.y; y < rect.bottom(); ++y) { - const contents = root.map.getTileContentXY(x, y); - if (contents) { - assert( - contents.components.ReplaceableMapEntity, - "Can not delete entity for blueprint" - ); - if (!root.logic.tryDeleteBuilding(contents)) { - assertAlways( - false, - "Building has replaceable component but is also unremovable in blueprint" - ); - } - } - } - } - - const clone = entity.duplicateWithoutContents(); - clone.components.StaticMapEntity.origin.addInplace(tile); - - root.map.placeStaticEntity(clone); - - // Registering a belt immediately triggers a recalculation of surrounding belt - // directions, which is no good when not all belts have been placed. To resolve - // this, only register belts after all entities have been placed. - if (!clone.components.Belt) { - root.entityMgr.registerEntity(clone); - } else { - beltsToRegisterLater.push(clone); - } - anyPlaced = true; - } - } - - for (let i = 0; i < beltsToRegisterLater.length; i++) { - root.entityMgr.registerEntity(beltsToRegisterLater[i]); - } - return anyPlaced; - }); - } -} diff --git a/src/js/game/hud/parts/blueprint_placer.js b/src/js/game/hud/parts/blueprint_placer.js index c98fbf2d..38341395 100644 --- a/src/js/game/hud/parts/blueprint_placer.js +++ b/src/js/game/hud/parts/blueprint_placer.js @@ -9,8 +9,9 @@ import { KEYMAPPINGS } from "../../key_action_mapper"; import { blueprintShape } from "../../upgrades"; import { BaseHUDPart } from "../base_hud_part"; import { DynamicDomAttach } from "../dynamic_dom_attach"; -import { Blueprint } from "./blueprint"; +import { Blueprint } from "../../blueprint"; import { SOUNDS } from "../../../platform/sound"; +import { enumLayer } from "../../root"; export class HUDBlueprintPlacer extends BaseHUDPart { createElements(parent) { @@ -26,7 +27,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart { } initialize() { - this.root.hud.signals.buildingsSelectedForCopy.add(this.onBuildingsSelected, this); + this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this); /** @type {TypedTrackedState} */ this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this); @@ -43,6 +44,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart { this.root.camera.movePreHandler.add(this.onMouseMove, this); this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this); + this.root.signals.editModeChanged.add(this.onEditModeChanged, this); this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent); this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this); @@ -56,6 +58,24 @@ export class HUDBlueprintPlacer extends BaseHUDPart { } } + /** + * Called when the layer was changed + * @param {enumLayer} layer + */ + onEditModeChanged(layer) { + // Check if the layer of the blueprint differs and thus we have to deselect it + const blueprint = this.currentBlueprint.get(); + if (blueprint) { + if (blueprint.layer !== layer) { + this.currentBlueprint.set(null); + } + } + } + + /** + * Called when the blueprint is now affordable or not + * @param {boolean} canAfford + */ onCanAffordChanged(canAfford) { this.costDisplayParent.classList.toggle("canAfford", canAfford); } @@ -67,6 +87,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart { } /** + * Called when the blueprint was changed * @param {Blueprint} blueprint */ onBlueprintChanged(blueprint) { @@ -105,13 +126,12 @@ export class HUDBlueprintPlacer extends BaseHUDPart { const cost = blueprint.getCost(); this.root.hubGoals.takeShapeByKey(blueprintShape, cost); this.root.soundProxy.playUi(SOUNDS.placeBuilding); - // This actually feels weird - // if (!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).pressed) { - // this.currentBlueprint.set(null); - // } } } + /** + * Mose move handler + */ onMouseMove() { // Prevent movement while blueprint is selected if (this.currentBlueprint.get()) { @@ -120,15 +140,19 @@ export class HUDBlueprintPlacer extends BaseHUDPart { } /** + * Called when an array of bulidings was selected * @param {Array} uids */ - onBuildingsSelected(uids) { + createBlueprintFromBuildings(uids) { if (uids.length === 0) { return; } this.currentBlueprint.set(Blueprint.fromUids(this.root, uids)); } + /** + * Attempts to rotate the current blueprint + */ rotateBlueprint() { if (this.currentBlueprint.get()) { if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) { @@ -139,8 +163,17 @@ export class HUDBlueprintPlacer extends BaseHUDPart { } } + /** + * Attempts to paste the last blueprint + */ pasteBlueprint() { if (this.lastBlueprintUsed !== null) { + if (this.lastBlueprintUsed.layer !== this.root.currentLayer) { + // Not compatible + this.root.soundProxy.playUiError(); + return; + } + this.root.hud.signals.pasteBlueprintRequested.dispatch(); this.currentBlueprint.set(this.lastBlueprintUsed); } else { diff --git a/src/js/game/hud/parts/building_placer.js b/src/js/game/hud/parts/building_placer.js index 0e9752ef..d3a3c7ac 100644 --- a/src/js/game/hud/parts/building_placer.js +++ b/src/js/game/hud/parts/building_placer.js @@ -1,9 +1,9 @@ -import { Math_radians } from "../../../core/builtins"; -import { globalConfig } from "../../../core/config"; +import { ClickDetector } from "../../../core/click_detector"; +import { globalConfig, THIRDPARTY_URLS } from "../../../core/config"; import { DrawParameters } from "../../../core/draw_parameters"; -import { drawRotatedSprite } from "../../../core/draw_utils"; +import { drawRotatedSprite, rotateTrapezRightFaced } from "../../../core/draw_utils"; import { Loader } from "../../../core/loader"; -import { makeDiv, removeAllChildren, pulseAnimation, clamp } from "../../../core/utils"; +import { clamp, makeDiv, removeAllChildren } from "../../../core/utils"; import { enumDirectionToAngle, enumDirectionToVector, @@ -16,7 +16,8 @@ import { defaultBuildingVariant } from "../../meta_building"; import { THEME } from "../../theme"; import { DynamicDomAttach } from "../dynamic_dom_attach"; import { HUDBuildingPlacerLogic } from "./building_placer_logic"; -import { ClickDetector } from "../../../core/click_detector"; +import { makeOffscreenBuffer } from "../../../core/buffer_utils"; +import { enumLayer } from "../../root"; export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { /** @@ -50,13 +51,19 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { // Bind to signals this.signals.variantChanged.add(this.rerenderVariants, this); + this.root.hud.signals.buildingSelectedForPlacement.add(this.startSelection, this); this.domAttach = new DynamicDomAttach(this.root, this.element, {}); this.variantsAttach = new DynamicDomAttach(this.root, this.variantsElement, {}); this.currentInterpolatedCornerTile = new Vector(); - this.lockIndicatorSprite = Loader.getSprite("sprites/misc/lock_direction_indicator.png"); + this.lockIndicatorSprites = {}; + for (const layerId in enumLayer) { + this.lockIndicatorSprites[layerId] = this.makeLockIndicatorSprite(layerId); + } + + // /** * Stores the click detectors for the variants so we can clean them up later @@ -65,6 +72,37 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { this.variantClickDetectors = []; } + /** + * Makes the lock indicator sprite for the given layer + * @param {enumLayer} layer + */ + makeLockIndicatorSprite(layer) { + const dims = 48; + const [canvas, context] = makeOffscreenBuffer(dims, dims, { + smooth: true, + reusable: false, + label: "lock-direction-indicator", + }); + + // Loader.getSprite("sprites/misc/lock_direction_indicator.png").draw(context, 0, 0, 48, 48); + context.fillStyle = THEME.map.directionLock[enumLayer.wires].color; + context.strokeStyle = THEME.map.directionLock[enumLayer.wires].color; + context.lineWidth = 2; + + const padding = 5; + const height = dims * 0.5; + const bottom = (dims + height) / 2; + + context.moveTo(padding, bottom); + context.lineTo(dims / 2, bottom - height); + context.lineTo(dims - padding, bottom); + context.closePath(); + context.stroke(); + context.fill(); + + return canvas; + } + /** * Rerenders the building info dialog */ @@ -178,7 +216,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { consumeEvents: true, targetOnly: true, }); - detector.click.add(() => this.currentVariant.set(variant)); + detector.click.add(() => this.setVariant(variant)); } } @@ -230,12 +268,13 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { rotation, rotationVariant, connectedEntities, - } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile( - this.root, - mouseTile, - this.currentBaseRotation, - this.currentVariant.get() - ); + } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile({ + root: this.root, + tile: mouseTile, + rotation: this.currentBaseRotation, + variant: this.currentVariant.get(), + layer: metaBuilding.getLayer(), + }); // Check if there are connected entities if (connectedEntities) { @@ -275,14 +314,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { staticComp.tileSize = metaBuilding.getDimensions(this.currentVariant.get()); metaBuilding.updateVariants(this.fakeEntity, rotationVariant, this.currentVariant.get()); - // Check if we could place the buildnig - const canBuild = this.root.logic.checkCanPlaceBuilding({ - origin: mouseTile, - rotation, - rotationVariant, - building: metaBuilding, - variant: this.currentVariant.get(), - }); + const canBuild = this.root.logic.checkCanPlaceEntity(this.fakeEntity); // Fade in / out parameters.context.lineWidth = 1; @@ -334,8 +366,8 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { const mouseWorld = this.root.camera.screenToWorld(mousePosition); const mouseTile = mouseWorld.toTileSpace(); - parameters.context.fillStyle = THEME.map.directionLock; - parameters.context.strokeStyle = THEME.map.directionLockTrack; + parameters.context.fillStyle = THEME.map.directionLock[this.root.currentLayer].color; + parameters.context.strokeStyle = THEME.map.directionLock[this.root.currentLayer].background; parameters.context.lineWidth = 10; parameters.context.beginCircle(mouseWorld.x, mouseWorld.y, 4); @@ -358,23 +390,28 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { parameters.context.beginCircle(endLine.x, endLine.y, 5); parameters.context.fill(); - // Draw arrows + // Draw arrow + const arrowSprite = this.lockIndicatorSprites[this.root.currentLayer]; const path = this.computeDirectionLockPath(); for (let i = 0; i < path.length - 1; i += 1) { const { rotation, tile } = path[i]; const worldPos = tile.toWorldSpaceCenterOfTile(); - drawRotatedSprite({ - parameters, - sprite: this.lockIndicatorSprite, - x: worldPos.x, - y: worldPos.y, - angle: Math_radians(rotation), - size: 12, - offsetY: - -globalConfig.halfTileSize - + const angle = Math.radians(rotation); + + parameters.context.translate(worldPos.x, worldPos.y); + parameters.context.rotate(angle); + parameters.context.drawImage( + arrowSprite, + -6, + -globalConfig.halfTileSize - clamp((this.root.time.realtimeNow() * 1.5) % 1.0, 0, 1) * 1 * globalConfig.tileSize + - globalConfig.halfTileSize, - }); + globalConfig.halfTileSize - + 6, + 12, + 12 + ); + parameters.context.rotate(-angle); + parameters.context.translate(-worldPos.x, -worldPos.y); } } } @@ -390,7 +427,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { const goodArrowSprite = Loader.getSprite("sprites/misc/slot_good_arrow.png"); const badArrowSprite = Loader.getSprite("sprites/misc/slot_bad_arrow.png"); - // Just ignore this code ... + // Just ignore the following code please ... thanks! const offsetShift = 10; @@ -398,9 +435,16 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { const slots = acceptorComp.slots; for (let acceptorSlotIndex = 0; acceptorSlotIndex < slots.length; ++acceptorSlotIndex) { const slot = slots[acceptorSlotIndex]; + + // Only draw same layer slots + if (slot.layer !== this.root.currentLayer) { + continue; + } + const acceptorSlotWsTile = staticComp.localTileToWorld(slot.pos); const acceptorSlotWsPos = acceptorSlotWsTile.toWorldSpaceCenterOfTile(); + // Go over all slots for ( let acceptorDirectionIndex = 0; acceptorDirectionIndex < slot.directions.length; @@ -409,30 +453,54 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { const direction = slot.directions[acceptorDirectionIndex]; const worldDirection = staticComp.localDirectionToWorld(direction); + // Figure out which tile ejects to this slot const sourceTile = acceptorSlotWsTile.add(enumDirectionToVector[worldDirection]); - const sourceEntity = this.root.map.getTileContent(sourceTile); - let sprite = goodArrowSprite; - let alpha = 0.5; + let isBlocked = false; + let isConnected = false; - if (sourceEntity) { - sprite = badArrowSprite; + // Find all entities which are on that tile + const sourceEntities = this.root.map.getLayersContentsMultipleXY( + sourceTile.x, + sourceTile.y + ); + + // Check for every entity: + for (let i = 0; i < sourceEntities.length; ++i) { + const sourceEntity = sourceEntities[i]; const sourceEjector = sourceEntity.components.ItemEjector; const sourceStaticComp = sourceEntity.components.StaticMapEntity; const ejectorAcceptLocalTile = sourceStaticComp.worldToLocalTile(acceptorSlotWsTile); - if (sourceEjector && sourceEjector.anySlotEjectsToLocalTile(ejectorAcceptLocalTile)) { - sprite = goodArrowSprite; + + // If this entity is on the same layer as the slot - if so, it can either be + // connected, or it can not be connected and thus block the input + if (sourceEntity.layer === slot.layer) { + if ( + sourceEjector && + sourceEjector.anySlotEjectsToLocalTile( + ejectorAcceptLocalTile, + this.root.currentLayer + ) + ) { + // This one is connected, all good + isConnected = true; + } else { + // This one is blocked + isBlocked = true; + } } - alpha = 1.0; } + const alpha = isConnected || isBlocked ? 1.0 : 0.3; + const sprite = isBlocked ? badArrowSprite : goodArrowSprite; + parameters.context.globalAlpha = alpha; drawRotatedSprite({ parameters, sprite, x: acceptorSlotWsPos.x, y: acceptorSlotWsPos.y, - angle: Math_radians(enumDirectionToAngle[enumInvertedDirections[worldDirection]]), + angle: Math.radians(enumDirectionToAngle[enumInvertedDirections[worldDirection]]), size: 13, offsetY: offsetShift + 13, }); @@ -443,8 +511,15 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { if (ejectorComp) { const slots = ejectorComp.slots; + + // Go over all slots for (let ejectorSlotIndex = 0; ejectorSlotIndex < slots.length; ++ejectorSlotIndex) { - const slot = ejectorComp.slots[ejectorSlotIndex]; + const slot = slots[ejectorSlotIndex]; + + // Only draw same layer slots + if (slot.layer !== this.root.currentLayer) { + continue; + } const ejectorSlotWsTile = staticComp.localTileToWorld( ejectorComp.getSlotTargetLocalTile(ejectorSlotIndex) @@ -452,33 +527,49 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic { const ejectorSLotWsPos = ejectorSlotWsTile.toWorldSpaceCenterOfTile(); const ejectorSlotWsDirection = staticComp.localDirectionToWorld(slot.direction); - const destEntity = this.root.map.getTileContent(ejectorSlotWsTile); + let isBlocked = false; + let isConnected = false; - let sprite = goodArrowSprite; - let alpha = 0.5; - if (destEntity) { - alpha = 1; + // Find all entities which are on that tile + const destEntities = this.root.map.getLayersContentsMultipleXY( + ejectorSlotWsTile.x, + ejectorSlotWsTile.y + ); + + // Check for every entity: + for (let i = 0; i < destEntities.length; ++i) { + const destEntity = destEntities[i]; const destAcceptor = destEntity.components.ItemAcceptor; const destStaticComp = destEntity.components.StaticMapEntity; - if (destAcceptor) { + // If this entity is on the same layer as the slot - if so, it can either be + // connected, or it can not be connected and thus block the input + if (destEntity.layer === slot.layer) { const destLocalTile = destStaticComp.worldToLocalTile(ejectorSlotWsTile); const destLocalDir = destStaticComp.worldDirectionToLocal(ejectorSlotWsDirection); - if (destAcceptor.findMatchingSlot(destLocalTile, destLocalDir)) { - sprite = goodArrowSprite; + if ( + destAcceptor && + destAcceptor.findMatchingSlot(destLocalTile, destLocalDir, this.root.currentLayer) + ) { + // This one is connected, all good + isConnected = true; } else { - sprite = badArrowSprite; + // This one is blocked + isBlocked = true; } } } + const alpha = isConnected || isBlocked ? 1.0 : 0.3; + const sprite = isBlocked ? badArrowSprite : goodArrowSprite; + parameters.context.globalAlpha = alpha; drawRotatedSprite({ parameters, sprite, x: ejectorSLotWsPos.x, y: ejectorSLotWsPos.y, - angle: Math_radians(enumDirectionToAngle[ejectorSlotWsDirection]), + angle: Math.radians(enumDirectionToAngle[ejectorSlotWsDirection]), size: 13, offsetY: offsetShift, }); diff --git a/src/js/game/hud/parts/building_placer_logic.js b/src/js/game/hud/parts/building_placer_logic.js index 337e43f7..f0266b77 100644 --- a/src/js/game/hud/parts/building_placer_logic.js +++ b/src/js/game/hud/parts/building_placer_logic.js @@ -1,4 +1,3 @@ -import { Math_abs, Math_degrees, Math_round } from "../../../core/builtins"; import { globalConfig } from "../../../core/config"; import { gMetaBuildingRegistry } from "../../../core/global_registries"; import { Signal, STOP_PROPAGATION } from "../../../core/signal"; @@ -13,7 +12,7 @@ import { BaseHUDPart } from "../base_hud_part"; import { SOUNDS } from "../../../platform/sound"; import { MetaMinerBuilding, enumMinerVariants } from "../../buildings/miner"; import { enumHubGoalRewards } from "../../tutorial_goals"; -import { enumEditMode } from "../../root"; +import { enumLayer } from "../../root"; /** * Contains all logic for the building placer - this doesn't include the rendering @@ -93,6 +92,12 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { */ this.currentDirectionLockSide = 0; + /** + * Whether the side for direction lock has not yet been determined. + * @type {boolean} + */ + this.currentDirectionLockSideIndeterminate = true; + this.initializeBindings(); } @@ -126,12 +131,12 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { /** * Called when the edit mode got changed - * @param {enumEditMode} editMode + * @param {enumLayer} editMode */ onEditModeChanged(editMode) { const metaBuilding = this.currentMetaBuilding.get(); if (metaBuilding) { - if (metaBuilding.getEditLayer() !== editMode) { + if (metaBuilding.getLayer() !== editMode) { // This layer doesn't fit the edit mode anymore this.currentMetaBuilding.set(null); } @@ -205,6 +210,17 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { const worldPos = this.root.camera.screenToWorld(mousePosition); const mouseTile = worldPos.toTileSpace(); + // Figure initial direction + const dx = Math.abs(this.lastDragTile.x - mouseTile.x); + const dy = Math.abs(this.lastDragTile.y - mouseTile.y); + if (dx === 0 && dy === 0) { + // Back at the start. Try a new direction. + this.currentDirectionLockSideIndeterminate = true; + } else if (this.currentDirectionLockSideIndeterminate) { + this.currentDirectionLockSideIndeterminate = false; + this.currentDirectionLockSide = dx <= dy ? 0 : 1; + } + if (this.currentDirectionLockSide === 0) { return new Vector(this.lastDragTile.x, mouseTile.y); } else { @@ -277,7 +293,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { const worldPos = this.root.camera.screenToWorld(mousePosition); const tile = worldPos.toTileSpace(); - const contents = this.root.map.getTileContent(tile); + const contents = this.root.map.getTileContent(tile, this.root.currentLayer); if (contents) { if (this.root.logic.tryDeleteBuilding(contents)) { this.root.soundProxy.playUi(SOUNDS.destroyBuilding); @@ -303,7 +319,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { const worldPos = this.root.camera.screenToWorld(mousePosition); const tile = worldPos.toTileSpace(); - const contents = this.root.map.getTileContent(tile); + const contents = this.root.map.getTileContent(tile, this.root.currentLayer); if (!contents) { const tileBelow = this.root.map.getLowerLayerContentXY(tile.x, tile.y); @@ -323,7 +339,13 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { // Try to extract the building const extracted = this.hack_reconstructMetaBuildingAndVariantFromBuilding(contents); - if (!extracted) { + + // If the building we are picking is the same as the one we have, clear the cursor. + if ( + !extracted || + (extracted.metaBuilding === this.currentMetaBuilding.get() && + extracted.variant === this.currentVariant.get()) + ) { this.currentMetaBuilding.set(null); return; } @@ -331,11 +353,6 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { this.currentMetaBuilding.set(extracted.metaBuilding); this.currentVariant.set(extracted.variant); this.currentBaseRotation = contents.components.StaticMapEntity.rotation; - - // Make sure we selected something, and also make sure it's not a special entity - // if (contents && !contents.components.Unremovable) { - - // } } /** @@ -444,12 +461,13 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { } const metaBuilding = this.currentMetaBuilding.get(); - const { rotation, rotationVariant } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile( - this.root, + const { rotation, rotationVariant } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile({ + root: this.root, tile, - this.currentBaseRotation, - this.currentVariant.get() - ); + rotation: this.currentBaseRotation, + variant: this.currentVariant.get(), + layer: metaBuilding.getLayer(), + }); const entity = this.root.logic.tryPlaceBuilding({ origin: tile, @@ -505,12 +523,21 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { ); const newIndex = (index + 1) % availableVariants.length; const newVariant = availableVariants[newIndex]; - this.currentVariant.set(newVariant); - - this.preferredVariants[metaBuilding.getId()] = newVariant; + this.setVariant(newVariant); } } + /** + * Sets the current variant to the given variant + * @param {string} variant + */ + setVariant(variant) { + const metaBuilding = this.currentMetaBuilding.get(); + this.currentVariant.set(variant); + + this.preferredVariants[metaBuilding.getId()] = variant; + } + /** * Performs the direction locked placement between two points after * releasing the mouse @@ -559,16 +586,23 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { // Figure which points the line visits const worldPos = this.root.camera.screenToWorld(mousePosition); - const mouseTile = worldPos.toTileSpace(); - const startTile = this.lastDragTile; + let endTile = worldPos.toTileSpace(); + let startTile = this.lastDragTile; + + // if the alt key is pressed, reverse belt planner direction by switching start and end tile + if (this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeInverse).pressed) { + let tmp = startTile; + startTile = endTile; + endTile = tmp; + } // Place from start to corner const pathToCorner = this.currentDirectionLockCorner.sub(startTile); const deltaToCorner = pathToCorner.normalize().round(); - const lengthToCorner = Math_round(pathToCorner.length()); + const lengthToCorner = Math.round(pathToCorner.length()); let currentPos = startTile.copy(); - let rotation = (Math.round(Math_degrees(deltaToCorner.angle()) / 90) * 90 + 360) % 360; + let rotation = (Math.round(Math.degrees(deltaToCorner.angle()) / 90) * 90 + 360) % 360; if (lengthToCorner > 0) { for (let i = 0; i < lengthToCorner; ++i) { @@ -581,12 +615,12 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { } // Place from corner to end - const pathFromCorner = mouseTile.sub(this.currentDirectionLockCorner); + const pathFromCorner = endTile.sub(this.currentDirectionLockCorner); const deltaFromCorner = pathFromCorner.normalize().round(); - const lengthFromCorner = Math_round(pathFromCorner.length()); + const lengthFromCorner = Math.round(pathFromCorner.length()); if (lengthFromCorner > 0) { - rotation = (Math.round(Math_degrees(deltaFromCorner.angle()) / 90) * 90 + 360) % 360; + rotation = (Math.round(Math.degrees(deltaFromCorner.angle()) / 90) * 90 + 360) % 360; for (let i = 0; i < lengthFromCorner + 1; ++i) { result.push({ tile: currentPos.copy(), @@ -722,7 +756,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { ).pressed ) { const delta = newPos.sub(oldPos); - const angleDeg = Math_degrees(delta.angle()); + const angleDeg = Math.degrees(delta.angle()); this.currentBaseRotation = (Math.round(angleDeg / 90) * 90 + 360) % 360; // Holding alt inverts the placement @@ -737,8 +771,8 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { let x1 = newPos.x; let y1 = newPos.y; - var dx = Math_abs(x1 - x0); - var dy = Math_abs(y1 - y0); + var dx = Math.abs(x1 - x0); + var dy = Math.abs(y1 - y0); var sx = x0 < x1 ? 1 : -1; var sy = y0 < y1 ? 1 : -1; var err = dx - dy; @@ -749,7 +783,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart { while (this.currentlyDeleting || this.currentMetaBuilding.get()) { if (this.currentlyDeleting) { // Deletion - const contents = this.root.map.getTileContentXY(x0, y0); + const contents = this.root.map.getLayerContentXY(x0, y0, this.root.currentLayer); if (contents && !contents.queuedForDestroy && !contents.destroyed) { if (this.root.logic.tryDeleteBuilding(contents)) { anythingDeleted = true; diff --git a/src/js/game/hud/parts/buildings_toolbar.js b/src/js/game/hud/parts/buildings_toolbar.js index d8b56943..c46a5c98 100644 --- a/src/js/game/hud/parts/buildings_toolbar.js +++ b/src/js/game/hud/parts/buildings_toolbar.js @@ -9,10 +9,11 @@ import { MetaSplitterBuilding } from "../../buildings/splitter"; import { MetaStackerBuilding } from "../../buildings/stacker"; import { MetaTrashBuilding } from "../../buildings/trash"; import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt"; -import { enumEditMode } from "../../root"; +import { enumLayer } from "../../root"; import { HUDBaseToolbar } from "./base_toolbar"; +import { MetaAdvancedProcessorBuilding } from "../../buildings/advanced_processor"; -const toolbarBuildings = [ +const supportedBuildings = [ MetaBeltBaseBuilding, MetaSplitterBuilding, MetaUndergroundBeltBuilding, @@ -23,15 +24,18 @@ const toolbarBuildings = [ MetaMixerBuilding, MetaPainterBuilding, MetaTrashBuilding, + MetaEnergyGenerator, + MetaAdvancedProcessorBuilding, ]; export class HUDBuildingsToolbar extends HUDBaseToolbar { constructor(root) { - super( - root, - toolbarBuildings, - () => !this.root.camera.getIsMapOverlayActive() && this.root.editMode === enumEditMode.regular - ); + super(root, { + supportedBuildings, + visibilityCondition: () => + !this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === enumLayer.regular, + htmlElementId: "ingame_HUD_buildings_toolbar", + }); } } diff --git a/src/js/game/hud/parts/color_blind_helper.js b/src/js/game/hud/parts/color_blind_helper.js index 4e6a0229..c7dd6288 100644 --- a/src/js/game/hud/parts/color_blind_helper.js +++ b/src/js/game/hud/parts/color_blind_helper.js @@ -7,6 +7,8 @@ import { DrawParameters } from "../../../core/draw_parameters"; import { THEME } from "../../theme"; import { globalConfig } from "../../../core/config"; import { T } from "../../../translations"; +import { enumItemType } from "../../base_item"; +import { enumLayer } from "../../root"; export class HUDColorBlindHelper extends BaseHUDPart { createElements(parent) { @@ -39,18 +41,23 @@ export class HUDColorBlindHelper extends BaseHUDPart { return null; } + if (this.root.currentLayer !== enumLayer.regular) { + // Not in regular mode + return null; + } + const worldPos = this.root.camera.screenToWorld(mousePosition); const tile = worldPos.toTileSpace(); - const contents = this.root.map.getTileContent(tile); + const contents = this.root.map.getTileContent(tile, this.root.currentLayer); if (contents && !contents.components.Miner) { const beltComp = contents.components.Belt; // Check if the belt has a color item if (beltComp) { - const firstItem = beltComp.sortedItems[0]; - if (firstItem && firstItem[1] instanceof ColorItem) { - return firstItem[1].color; + const item = beltComp.assignedPath.findItemAtTile(tile); + if (item && item.getItemType() === enumItemType.color) { + return /** @type {ColorItem} */ (item).color; } } @@ -59,16 +66,19 @@ export class HUDColorBlindHelper extends BaseHUDPart { if (ejectorComp) { for (let i = 0; i < ejectorComp.slots.length; ++i) { const slot = ejectorComp.slots[i]; - if (slot.item && slot.item instanceof ColorItem) { - return slot.item.color; + if (slot.layer !== this.root.currentLayer) { + continue; + } + if (slot.item && slot.item.getItemType() === enumItemType.color) { + return /** @type {ColorItem} */ (slot.item).color; } } } } else { // We hovered a lower layer, show the color there const lowerLayer = this.root.map.getLowerLayerContentXY(tile.x, tile.y); - if (lowerLayer && lowerLayer instanceof ColorItem) { - return lowerLayer.color; + if (lowerLayer && lowerLayer.getItemType() === enumItemType.color) { + return /** @type {ColorItem} */ (lowerLayer).color; } } diff --git a/src/js/game/hud/parts/debug_changes.js b/src/js/game/hud/parts/debug_changes.js index 46ad5234..1502afa2 100644 --- a/src/js/game/hud/parts/debug_changes.js +++ b/src/js/game/hud/parts/debug_changes.js @@ -27,7 +27,7 @@ export class HUDChangesDebugger extends BaseHUDPart { * @param {string} fillColor Color to display (Hex) * @param {number=} timeToDisplay How long to display the change */ - renderChange(label, area, fillColor, timeToDisplay = 2) { + renderChange(label, area, fillColor, timeToDisplay = 0.3) { this.changes.push({ label, area: area.clone(), diff --git a/src/js/game/hud/parts/debug_info.js b/src/js/game/hud/parts/debug_info.js index 4f4c052e..cdd00540 100644 --- a/src/js/game/hud/parts/debug_info.js +++ b/src/js/game/hud/parts/debug_info.js @@ -1,45 +1,122 @@ import { BaseHUDPart } from "../base_hud_part"; import { makeDiv, round3Digits, round2Digits } from "../../../core/utils"; -import { Math_round } from "../../../core/builtins"; import { DynamicDomAttach } from "../dynamic_dom_attach"; import { KEYMAPPINGS } from "../../key_action_mapper"; +import { Vector } from "../../../core/vector"; +import { TrackedState } from "../../../core/tracked_state"; + +/** @enum {string} */ +const enumDebugOverlayMode = { disabled: "disabled", regular: "regular", detailed: "detailed" }; + +/** + * Specifies which mode follows after which mode + * @enum {enumDebugOverlayMode} + */ +const enumDebugOverlayModeNext = { + [enumDebugOverlayMode.disabled]: enumDebugOverlayMode.regular, + [enumDebugOverlayMode.regular]: enumDebugOverlayMode.detailed, + [enumDebugOverlayMode.detailed]: enumDebugOverlayMode.disabled, +}; + +const UPDATE_INTERVAL_SECONDS = 0.25; export class HUDDebugInfo extends BaseHUDPart { createElements(parent) { this.element = makeDiv(parent, "ingame_HUD_DebugInfo", []); - this.tickRateElement = makeDiv(this.element, null, ["tickRate"], "Ticks /s: 120"); - this.fpsElement = makeDiv(this.element, null, ["fps"], "FPS: 60"); - this.tickDurationElement = makeDiv(this.element, null, ["tickDuration"], "Update time: 0.5ms"); + const tickRateElement = makeDiv(this.element, null, ["tickRate"]); + this.trackedTickRate = new TrackedState(str => (tickRateElement.innerText = str)); + + const tickDurationElement = makeDiv(this.element, null, ["tickDuration"]); + this.trackedTickDuration = new TrackedState(str => (tickDurationElement.innerText = str)); + + const fpsElement = makeDiv(this.element, null, ["fps"]); + this.trackedFPS = new TrackedState(str => (fpsElement.innerText = str)); + + const mousePositionElement = makeDiv(this.element, null, ["mousePosition"]); + this.trackedMousePosition = new TrackedState(str => (mousePositionElement.innerHTML = str)); + + const cameraPositionElement = makeDiv(this.element, null, ["cameraPosition"]); + this.trackedCameraPosition = new TrackedState(str => (cameraPositionElement.innerHTML = str)); + + this.versionElement = makeDiv(this.element, null, ["version"], "version unknown"); } initialize() { this.lastTick = 0; - this.visible = false; + this.trackedMode = new TrackedState(this.onModeChanged, this); this.domAttach = new DynamicDomAttach(this.root, this.element); - this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleFPSInfo).add(() => this.toggle()); + this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleFPSInfo).add(() => this.cycleModes()); + + // Set initial mode + this.trackedMode.set(enumDebugOverlayMode.disabled); } - toggle() { - this.visible = !this.visible; - this.domAttach.update(this.visible); + /** + * Called when the mode changed + * @param {enumDebugOverlayMode} mode + */ + onModeChanged(mode) { + this.element.setAttribute("data-mode", mode); + this.versionElement.innerText = `${G_BUILD_VERSION} @ ${G_APP_ENVIRONMENT} @ ${G_BUILD_COMMIT_HASH}`; + } + + /** + * Updates the labels + */ + updateLabels() { + this.trackedTickRate.set("Tickrate: " + this.root.dynamicTickrate.currentTickRate); + this.trackedFPS.set( + "FPS: " + + Math.round(this.root.dynamicTickrate.averageFps) + + " (" + + round2Digits(1000 / this.root.dynamicTickrate.averageFps) + + " ms)" + ); + this.trackedTickDuration.set( + "Tick: " + round3Digits(this.root.dynamicTickrate.averageTickDuration) + "ms" + ); + } + + /** + * Updates the detailed information + */ + updateDetailedInformation() { + const mousePos = this.root.app.mousePosition || new Vector(0, 0); + const mouseTile = this.root.camera.screenToWorld(mousePos).toTileSpace(); + const cameraTile = this.root.camera.center.toTileSpace(); + + this.trackedMousePosition.set(`Pos: ${mouseTile.x} / ${mouseTile.y}`); + this.trackedCameraPosition.set(`Center: ${cameraTile.x} / ${cameraTile.y}`); + } + + /** + * Cycles through the different modes + */ + cycleModes() { + this.trackedMode.set(enumDebugOverlayModeNext[this.trackedMode.get()]); } update() { + const visible = this.trackedMode.get() !== enumDebugOverlayMode.disabled; + this.domAttach.update(visible); + + if (!visible) { + return; + } + + // Periodically update the text const now = this.root.time.realtimeNow(); - if (now - this.lastTick > 0.25 && this.visible) { + if (now - this.lastTick > UPDATE_INTERVAL_SECONDS) { this.lastTick = now; - this.tickRateElement.innerText = "Tickrate: " + this.root.dynamicTickrate.currentTickRate; - this.fpsElement.innerText = - "FPS: " + - Math_round(this.root.dynamicTickrate.averageFps) + - " (" + - round2Digits(1000 / this.root.dynamicTickrate.averageFps) + - " ms)"; - this.tickDurationElement.innerText = - "Tick Dur: " + round3Digits(this.root.dynamicTickrate.averageTickDuration) + "ms"; + this.updateLabels(); + } + + // Also update detailed information if required + if (this.trackedMode.get() === enumDebugOverlayMode.detailed) { + this.updateDetailedInformation(); } } } diff --git a/src/js/game/hud/parts/entity_debugger.js b/src/js/game/hud/parts/entity_debugger.js index 1293d79b..9fe1bd7c 100644 --- a/src/js/game/hud/parts/entity_debugger.js +++ b/src/js/game/hud/parts/entity_debugger.js @@ -36,7 +36,7 @@ export class HUDEntityDebugger extends BaseHUDPart { this.mousePosElem.innerText = worldTile.x + " / " + worldTile.y; this.chunkPosElem.innerText = chunk.x + " / " + chunk.y; - const entity = this.root.map.getTileContent(worldTile); + const entity = this.root.map.getTileContent(worldTile, this.root.currentLayer); if (entity) { removeAllChildren(this.entityInfoElem); let html = "Entity"; diff --git a/src/js/game/hud/parts/mass_selector.js b/src/js/game/hud/parts/mass_selector.js index a3505e2d..68d480e4 100644 --- a/src/js/game/hud/parts/mass_selector.js +++ b/src/js/game/hud/parts/mass_selector.js @@ -13,6 +13,7 @@ import { T } from "../../../translations"; import { KEYMAPPINGS } from "../../key_action_mapper"; import { THEME } from "../../theme"; import { enumHubGoalRewards } from "../../tutorial_goals"; +import { Blueprint } from "../../blueprint"; const logger = createLogger("hud/mass_selector"); @@ -41,6 +42,7 @@ export class HUDMassSelector extends BaseHUDPart { this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectCopy).add(this.startCopy, this); this.root.hud.signals.selectedPlacementBuildingChanged.add(this.clearSelection, this); + this.root.signals.editModeChanged.add(this.clearSelection, this); } /** @@ -145,16 +147,30 @@ export class HUDMassSelector extends BaseHUDPart { if (this.selectedUids.size > 0) { const entityUids = Array.from(this.selectedUids); - // copy code relies on entities still existing, so must copy before deleting. - this.root.hud.signals.buildingsSelectedForCopy.dispatch(entityUids); + const cutAction = () => { + // copy code relies on entities still existing, so must copy before deleting. + this.root.hud.signals.buildingsSelectedForCopy.dispatch(entityUids); - for (let i = 0; i < entityUids.length; ++i) { - const uid = entityUids[i]; - const entity = this.root.entityMgr.findByUid(uid); - if (!this.root.logic.tryDeleteBuilding(entity)) { - logger.error("Error in mass cut, could not remove building"); - this.selectedUids.delete(uid); + for (let i = 0; i < entityUids.length; ++i) { + const uid = entityUids[i]; + const entity = this.root.entityMgr.findByUid(uid); + if (!this.root.logic.tryDeleteBuilding(entity)) { + logger.error("Error in mass cut, could not remove building"); + this.selectedUids.delete(uid); + } } + }; + + const blueprint = Blueprint.fromUids(this.root, entityUids); + if (blueprint.canAfford(this.root)) { + cutAction(); + } else { + const { cancel, ok } = this.root.hud.parts.dialogs.showWarning( + T.dialogs.massCutInsufficientConfirm.title, + T.dialogs.massCutInsufficientConfirm.desc, + ["cancel:good:escape", "ok:bad:enter"] + ); + ok.add(cutAction); } this.root.soundProxy.playUiClick(); @@ -210,7 +226,7 @@ export class HUDMassSelector extends BaseHUDPart { for (let x = realTileStart.x; x <= realTileEnd.x; ++x) { for (let y = realTileStart.y; y <= realTileEnd.y; ++y) { - const contents = this.root.map.getTileContentXY(x, y); + const contents = this.root.map.getLayerContentXY(x, y, this.root.currentLayer); if (contents && this.root.logic.canDeleteBuilding(contents)) { this.selectedUids.add(contents.uid); } @@ -259,7 +275,7 @@ export class HUDMassSelector extends BaseHUDPart { for (let x = realTileStart.x; x <= realTileEnd.x; ++x) { for (let y = realTileStart.y; y <= realTileEnd.y; ++y) { - const contents = this.root.map.getTileContentXY(x, y); + const contents = this.root.map.getLayerContentXY(x, y, this.root.currentLayer); if (contents && this.root.logic.canDeleteBuilding(contents)) { const staticComp = contents.components.StaticMapEntity; const bounds = staticComp.getTileSpaceBounds(); diff --git a/src/js/game/hud/parts/pinned_shapes.js b/src/js/game/hud/parts/pinned_shapes.js index 3f935a0b..bda49f1e 100644 --- a/src/js/game/hud/parts/pinned_shapes.js +++ b/src/js/game/hud/parts/pinned_shapes.js @@ -1,4 +1,3 @@ -import { Math_max } from "../../../core/builtins"; import { ClickDetector } from "../../../core/click_detector"; import { formatBigNumber, makeDiv, arrayDelete, arrayDeleteValue } from "../../../core/utils"; import { ShapeDefinition } from "../../shape_definition"; diff --git a/src/js/game/hud/parts/processing_overlay.js b/src/js/game/hud/parts/processing_overlay.js index 3354966a..95383dfd 100644 --- a/src/js/game/hud/parts/processing_overlay.js +++ b/src/js/game/hud/parts/processing_overlay.js @@ -1,6 +1,5 @@ import { DynamicDomAttach } from "../dynamic_dom_attach"; import { BaseHUDPart } from "../base_hud_part"; -import { performanceNow } from "../../../core/builtins"; import { makeDiv } from "../../../core/utils"; import { Signal } from "../../../core/signal"; import { InputReceiver } from "../../../core/input_receiver"; @@ -62,15 +61,15 @@ export class HUDProcessingOverlay extends BaseHUDPart { } processSync() { - const now = performanceNow(); + const now = performance.now(); while (this.tasks.length > 0) { const workload = this.tasks[0]; workload.call(); this.tasks.shift(); } - const duration = performanceNow() - now; + const duration = performance.now() - now; if (duration > 100) { - logger.log("Tasks done slow (SYNC!) within", (performanceNow() - now).toFixed(2), "ms"); + logger.log("Tasks done slow (SYNC!) within", (performance.now() - now).toFixed(2), "ms"); } } @@ -89,15 +88,15 @@ export class HUDProcessingOverlay extends BaseHUDPart { } this.computeTimeout = setTimeout(() => { - const now = performanceNow(); + const now = performance.now(); while (this.tasks.length > 0) { const workload = this.tasks[0]; workload.call(); this.tasks.shift(); } - const duration = performanceNow() - now; + const duration = performance.now() - now; if (duration > 100) { - logger.log("Tasks done slow within", (performanceNow() - now).toFixed(2), "ms"); + logger.log("Tasks done slow within", (performance.now() - now).toFixed(2), "ms"); } this.domWatcher.update(false); diff --git a/src/js/game/hud/parts/sandbox_controller.js b/src/js/game/hud/parts/sandbox_controller.js new file mode 100644 index 00000000..6bf277bb --- /dev/null +++ b/src/js/game/hud/parts/sandbox_controller.js @@ -0,0 +1,158 @@ +import { BaseHUDPart } from "../base_hud_part"; +import { makeDiv } from "../../../core/utils"; +import { DynamicDomAttach } from "../dynamic_dom_attach"; +import { blueprintShape, UPGRADES } from "../../upgrades"; +import { enumNotificationType } from "./notifications"; +import { tutorialGoals } from "../../tutorial_goals"; + +export class HUDSandboxController extends BaseHUDPart { + createElements(parent) { + this.element = makeDiv( + parent, + "ingame_HUD_SandboxController", + [], + ` + + Use F6 to toggle this overlay + +
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + +
+
+ ` + ); + + const bind = (selector, handler) => this.trackClicks(this.element.querySelector(selector), handler); + + bind(".giveBlueprints", this.giveBlueprints); + bind(".maxOutAll", this.maxOutAll); + bind(".levelToggle .minus", () => this.modifyLevel(-1)); + bind(".levelToggle .plus", () => this.modifyLevel(1)); + + bind(".upgradesBelt .minus", () => this.modifyUpgrade("belt", -1)); + bind(".upgradesBelt .plus", () => this.modifyUpgrade("belt", 1)); + + bind(".upgradesExtraction .minus", () => this.modifyUpgrade("miner", -1)); + bind(".upgradesExtraction .plus", () => this.modifyUpgrade("miner", 1)); + + bind(".upgradesProcessing .minus", () => this.modifyUpgrade("processors", -1)); + bind(".upgradesProcessing .plus", () => this.modifyUpgrade("processors", 1)); + + bind(".upgradesPainting .minus", () => this.modifyUpgrade("painting", -1)); + bind(".upgradesPainting .plus", () => this.modifyUpgrade("painting", 1)); + } + + giveBlueprints() { + if (!this.root.hubGoals.storedShapes[blueprintShape]) { + this.root.hubGoals.storedShapes[blueprintShape] = 0; + } + this.root.hubGoals.storedShapes[blueprintShape] += 1e4; + } + + maxOutAll() { + this.modifyUpgrade("belt", 100); + this.modifyUpgrade("miner", 100); + this.modifyUpgrade("processors", 100); + this.modifyUpgrade("painting", 100); + } + + modifyUpgrade(id, amount) { + const handle = UPGRADES[id]; + const maxLevel = handle.tiers.length; + + this.root.hubGoals.upgradeLevels[id] = Math.max( + 0, + Math.min(maxLevel, (this.root.hubGoals.upgradeLevels[id] || 0) + amount) + ); + + // Compute improvement + let improvement = 1; + for (let i = 0; i < this.root.hubGoals.upgradeLevels[id]; ++i) { + improvement += handle.tiers[i].improvement; + } + this.root.hubGoals.upgradeImprovements[id] = improvement; + this.root.signals.upgradePurchased.dispatch(id); + this.root.hud.signals.notification.dispatch( + "Upgrade '" + id + "' is now at level " + this.root.hubGoals.upgradeLevels[id], + enumNotificationType.upgrade + ); + } + + modifyLevel(amount) { + const hubGoals = this.root.hubGoals; + hubGoals.level = Math.max(1, hubGoals.level + amount); + hubGoals.createNextGoal(); + + // Clear all shapes of this level + hubGoals.storedShapes[hubGoals.currentGoal.definition.getHash()] = 0; + + this.root.hud.parts.pinnedShapes.rerenderFull(); + + // Compute gained rewards + hubGoals.gainedRewards = {}; + for (let i = 0; i < hubGoals.level - 1; ++i) { + if (i < tutorialGoals.length) { + const reward = tutorialGoals[i].reward; + hubGoals.gainedRewards[reward] = (hubGoals.gainedRewards[reward] || 0) + 1; + } + } + + this.root.hud.signals.notification.dispatch( + "Changed level to " + hubGoals.level, + enumNotificationType.upgrade + ); + } + + initialize() { + // Allow toggling the controller overlay + this.root.gameState.inputReciever.keydown.add(key => { + if (key.keyCode === 117) { + // F6 + this.toggle(); + } + }); + + this.visible = !G_IS_DEV; + this.domAttach = new DynamicDomAttach(this.root, this.element); + } + + toggle() { + this.visible = !this.visible; + } + + update() { + this.domAttach.update(this.visible); + } +} diff --git a/src/js/game/hud/parts/screenshot_exporter.js b/src/js/game/hud/parts/screenshot_exporter.js index 8623f902..19c644e9 100644 --- a/src/js/game/hud/parts/screenshot_exporter.js +++ b/src/js/game/hud/parts/screenshot_exporter.js @@ -5,7 +5,6 @@ import { T } from "../../../translations"; import { createLogger } from "../../../core/logging"; import { StaticMapEntityComponent } from "../../components/static_map_entity"; import { Vector } from "../../../core/vector"; -import { Math_max, Math_min, Math_floor } from "../../../core/builtins"; import { makeOffscreenBuffer } from "../../../core/buffer_utils"; import { DrawParameters } from "../../../core/draw_parameters"; import { Rectangle } from "../../../core/rectangle"; @@ -43,11 +42,11 @@ export class HUDScreenshotExporter extends BaseHUDPart { const maxTile = new Vector(0, 0); for (let i = 0; i < staticEntities.length; ++i) { const bounds = staticEntities[i].components.StaticMapEntity.getTileSpaceBounds(); - minTile.x = Math_min(minTile.x, bounds.x); - minTile.y = Math_min(minTile.y, bounds.y); + minTile.x = Math.min(minTile.x, bounds.x); + minTile.y = Math.min(minTile.y, bounds.y); - maxTile.x = Math_max(maxTile.x, bounds.x + bounds.w); - maxTile.y = Math_max(maxTile.y, bounds.y + bounds.h); + maxTile.x = Math.max(maxTile.x, bounds.x + bounds.w); + maxTile.y = Math.max(maxTile.y, bounds.y + bounds.h); } const minChunk = minTile.divideScalar(globalConfig.mapChunkSize).floor(); @@ -57,10 +56,10 @@ export class HUDScreenshotExporter extends BaseHUDPart { logger.log("Dimensions:", dimensions); let chunkSizePixels = 128; - const maxDimensions = Math_max(dimensions.x, dimensions.y); + const maxDimensions = Math.max(dimensions.x, dimensions.y); if (maxDimensions > 128) { - chunkSizePixels = Math_max(1, Math_floor(128 * (128 / maxDimensions))); + chunkSizePixels = Math.max(1, Math.floor(128 * (128 / maxDimensions))); } logger.log("ChunkSizePixels:", chunkSizePixels); diff --git a/src/js/game/hud/parts/shop.js b/src/js/game/hud/parts/shop.js index f83cb89b..e2b8837b 100644 --- a/src/js/game/hud/parts/shop.js +++ b/src/js/game/hud/parts/shop.js @@ -1,4 +1,3 @@ -import { Math_min } from "../../../core/builtins"; import { ClickDetector } from "../../../core/click_detector"; import { InputReceiver } from "../../../core/input_receiver"; import { formatBigNumber, makeDiv } from "../../../core/utils"; @@ -178,7 +177,7 @@ export class HUDShop extends BaseHUDPart { const { progressLabel, progressBar, definition, required } = handle.requireIndexToElement[i]; const haveAmount = this.root.hubGoals.getShapesStored(definition); - const progress = Math_min(haveAmount / required, 1.0); + const progress = Math.min(haveAmount / required, 1.0); progressLabel.innerText = formatBigNumber(haveAmount) + " / " + formatBigNumber(required); progressBar.style.width = progress * 100.0 + "%"; @@ -198,6 +197,7 @@ export class HUDShop extends BaseHUDPart { this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever); this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this); + this.keyActionMapper.getBinding(KEYMAPPINGS.ingame.menuClose).add(this.close, this); this.keyActionMapper.getBinding(KEYMAPPINGS.ingame.menuOpenShop).add(this.close, this); this.close(); diff --git a/src/js/game/hud/parts/statistics.js b/src/js/game/hud/parts/statistics.js index fc19b3fd..e1a747a2 100644 --- a/src/js/game/hud/parts/statistics.js +++ b/src/js/game/hud/parts/statistics.js @@ -1,4 +1,3 @@ -import { Math_min } from "../../../core/builtins"; import { InputReceiver } from "../../../core/input_receiver"; import { makeButton, makeDiv, removeAllChildren, capitalizeFirstLetter } from "../../../core/utils"; import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper"; @@ -82,6 +81,7 @@ export class HUDStatistics extends BaseHUDPart { this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever); this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this); + this.keyActionMapper.getBinding(KEYMAPPINGS.ingame.menuClose).add(this.close, this); this.keyActionMapper.getBinding(KEYMAPPINGS.ingame.menuOpenStats).add(this.close, this); /** @type {Object.} */ @@ -179,7 +179,7 @@ export class HUDStatistics extends BaseHUDPart { let rendered = new Set(); - for (let i = 0; i < Math_min(entries.length, 200); ++i) { + for (let i = 0; i < Math.min(entries.length, 200); ++i) { const entry = entries[i]; const shapeKey = entry[0]; diff --git a/src/js/game/hud/parts/statistics_handle.js b/src/js/game/hud/parts/statistics_handle.js index d3612d92..d5c60d3b 100644 --- a/src/js/game/hud/parts/statistics_handle.js +++ b/src/js/game/hud/parts/statistics_handle.js @@ -1,10 +1,10 @@ +import { makeOffscreenBuffer } from "../../../core/buffer_utils"; +import { globalConfig } from "../../../core/config"; +import { clamp, formatBigNumber, round2Digits } from "../../../core/utils"; +import { T } from "../../../translations"; +import { enumAnalyticsDataSource } from "../../production_analytics"; import { GameRoot } from "../../root"; import { ShapeDefinition } from "../../shape_definition"; -import { enumAnalyticsDataSource } from "../../production_analytics"; -import { formatBigNumber, clamp } from "../../../core/utils"; -import { globalConfig } from "../../../core/config"; -import { makeOffscreenBuffer } from "../../../core/buffer_utils"; -import { T } from "../../../translations"; /** @enum {string} */ export const enumDisplayMode = { @@ -91,6 +91,11 @@ export class HUDShapeStatisticsHandle { "", formatBigNumber(rate) ); + + if (G_IS_DEV && globalConfig.debug.detailedStatistics) { + this.counter.innerText = "" + round2Digits(rate / 60) + " /s"; + } + break; } } diff --git a/src/js/game/hud/parts/waypoints.js b/src/js/game/hud/parts/waypoints.js index 2472e57a..8cab85c5 100644 --- a/src/js/game/hud/parts/waypoints.js +++ b/src/js/game/hud/parts/waypoints.js @@ -1,5 +1,4 @@ import { makeOffscreenBuffer } from "../../../core/buffer_utils"; -import { Math_max, Math_PI, Math_radians } from "../../../core/builtins"; import { globalConfig, IS_DEMO } from "../../../core/config"; import { DrawParameters } from "../../../core/draw_parameters"; import { Loader } from "../../../core/loader"; @@ -112,7 +111,7 @@ export class HUDWaypoints extends BaseHUDPart { this.root.camera.downPreHandler.add(this.onMouseDown, this); this.root.keyMapper .getBinding(KEYMAPPINGS.navigation.createMarker) - .add(this.requestCreateMarker, this); + .add(() => this.requestSaveMarker({})); /** * Stores at how much opacity the markers should be rendered on the map. @@ -153,15 +152,24 @@ export class HUDWaypoints extends BaseHUDPart { if (ShapeDefinition.isValidShortKey(label)) { const canvas = this.getWaypointCanvas(waypoint); - element.appendChild(canvas); + /** + * Create a clone of the cached canvas, as calling appendElement when a canvas is + * already in the document will move the existing canvas to the new position. + */ + const [newCanvas, context] = makeOffscreenBuffer(48, 48, { + smooth: true, + label: label + "-waypoint-" + i, + }); + context.drawImage(canvas, 0, 0); + element.appendChild(newCanvas); element.classList.add("shapeIcon"); } else { element.innerText = label; } if (this.isWaypointDeletable(waypoint)) { - const deleteButton = makeDiv(element, null, ["deleteButton"]); - this.trackClicks(deleteButton, () => this.deleteWaypoint(waypoint)); + const editButton = makeDiv(element, null, ["editButton"]); + this.trackClicks(editButton, () => this.requestSaveMarker({ waypoint })); } if (!waypoint.label) { @@ -212,42 +220,61 @@ export class HUDWaypoints extends BaseHUDPart { } /** - * Requests to create a marker at the current camera position. If worldPos is set, + * Requests to save a marker at the current camera position. If worldPos is set, * uses that position instead. - * @param {Vector=} worldPos Override the world pos, otherwise it is the camera position + * @param {object} param0 + * @param {Vector=} param0.worldPos Override the world pos, otherwise it is the camera position + * @param {Waypoint=} param0.waypoint Waypoint to be edited. If omitted, create new */ - requestCreateMarker(worldPos = null) { + requestSaveMarker({ worldPos = null, waypoint = null }) { // Construct dialog with input field const markerNameInput = new FormElementInput({ id: "markerName", label: null, placeholder: "", + defaultValue: waypoint ? waypoint.label : "", validator: val => val.length > 0 && (val.length < MAX_LABEL_LENGTH || ShapeDefinition.isValidShortKey(val)), }); const dialog = new DialogWithForm({ app: this.root.app, - title: T.dialogs.createMarker.title, + title: waypoint ? T.dialogs.createMarker.titleEdit : T.dialogs.createMarker.title, desc: T.dialogs.createMarker.desc, formElements: [markerNameInput], + buttons: waypoint ? ["delete:bad", "cancel", "ok:good"] : ["cancel", "ok:good"], }); this.root.hud.parts.dialogs.internalShowDialog(dialog); - // Compute where to create the marker - const center = worldPos || this.root.camera.center; + // Edit marker + if (waypoint) { + dialog.buttonSignals.ok.add(() => { + // Actually rename the waypoint + this.renameWaypoint(waypoint, markerNameInput.getValue()); + }); + dialog.buttonSignals.delete.add(() => { + // Actually delete the waypoint + this.deleteWaypoint(waypoint); + }); + } else { + // Compute where to create the marker + const center = worldPos || this.root.camera.center; - dialog.buttonSignals.ok.add(() => { - // Show info that you can have only N markers in the demo, - // actually show this *after* entering the name so you want the - // standalone even more (I'm evil :P) - if (IS_DEMO && this.waypoints.length > 2) { - this.root.hud.parts.dialogs.showFeatureRestrictionInfo("", T.dialogs.markerDemoLimit.desc); - return; - } + dialog.buttonSignals.ok.add(() => { + // Show info that you can have only N markers in the demo, + // actually show this *after* entering the name so you want the + // standalone even more (I'm evil :P) + if (IS_DEMO && this.waypoints.length > 2) { + this.root.hud.parts.dialogs.showFeatureRestrictionInfo( + "", + T.dialogs.markerDemoLimit.desc + ); + return; + } - // Actually create the waypoint - this.addWaypoint(markerNameInput.getValue(), center); - }); + // Actually create the waypoint + this.addWaypoint(markerNameInput.getValue(), center); + }); + } } /** @@ -261,21 +288,10 @@ export class HUDWaypoints extends BaseHUDPart { center: { x: position.x, y: position.y }, // Make sure the zoom is *just* a bit above the zoom level where the map overview // starts, so you always see all buildings - zoomLevel: Math_max(this.root.camera.zoomLevel, globalConfig.mapChunkOverviewMinZoom + 0.05), + zoomLevel: Math.max(this.root.camera.zoomLevel, globalConfig.mapChunkOverviewMinZoom + 0.05), }); - // Sort waypoints by name - this.waypoints.sort((a, b) => { - if (!a.label) { - return -1; - } - if (!b.label) { - return 1; - } - return this.getWaypointLabel(a) - .padEnd(MAX_LABEL_LENGTH, "0") - .localeCompare(this.getWaypointLabel(b).padEnd(MAX_LABEL_LENGTH, "0")); - }); + this.sortWaypoints(); // Show notification about creation this.root.hud.signals.notification.dispatch( @@ -287,6 +303,26 @@ export class HUDWaypoints extends BaseHUDPart { this.rerenderWaypointList(); } + /** + * Renames a waypoint with the given label + * @param {Waypoint} waypoint + * @param {string} label + */ + renameWaypoint(waypoint, label) { + waypoint.label = label; + + this.sortWaypoints(); + + // Show notification about renamed + this.root.hud.signals.notification.dispatch( + T.ingame.waypoints.creationSuccessNotification, + enumNotificationType.success + ); + + // Re-render the list and thus add it + this.rerenderWaypointList(); + } + /** * Called every frame to update stuff */ @@ -296,6 +332,23 @@ export class HUDWaypoints extends BaseHUDPart { } } + /** + * Sort waypoints by name + */ + sortWaypoints() { + this.waypoints.sort((a, b) => { + if (!a.label) { + return -1; + } + if (!b.label) { + return 1; + } + return this.getWaypointLabel(a) + .padEnd(MAX_LABEL_LENGTH, "0") + .localeCompare(this.getWaypointLabel(b).padEnd(MAX_LABEL_LENGTH, "0")); + }); + } + /** * Returns the label for a given waypoint * @param {Waypoint} waypoint @@ -373,7 +426,7 @@ export class HUDWaypoints extends BaseHUDPart { } else if (button === enumMouseButton.right) { if (this.isWaypointDeletable(waypoint)) { this.root.soundProxy.playUiClick(); - this.deleteWaypoint(waypoint); + this.requestSaveMarker({ waypoint }); } else { this.root.soundProxy.playUiError(); } @@ -385,7 +438,7 @@ export class HUDWaypoints extends BaseHUDPart { if (button === enumMouseButton.right) { if (this.root.camera.getIsMapOverlayActive()) { const worldPos = this.root.camera.screenToWorld(pos); - this.requestCreateMarker(worldPos); + this.requestSaveMarker({ worldPos }); return STOP_PROPAGATION; } } @@ -410,7 +463,7 @@ export class HUDWaypoints extends BaseHUDPart { if (this.currentCompassOpacity > 0.01) { context.globalAlpha = this.currentCompassOpacity; - const angle = cameraPos.angle() + Math_radians(45) + Math_PI / 2; + const angle = cameraPos.angle() + Math.radians(45) + Math.PI / 2; context.translate(dims / 2, dims / 2); context.rotate(angle); this.directionIndicatorSprite.drawCentered(context, 0, 0, indicatorSize); diff --git a/src/js/game/hud/parts/wires_overlay.js b/src/js/game/hud/parts/wires_overlay.js index 0d228509..8bda5d0d 100644 --- a/src/js/game/hud/parts/wires_overlay.js +++ b/src/js/game/hud/parts/wires_overlay.js @@ -2,11 +2,13 @@ import { makeOffscreenBuffer } from "../../../core/buffer_utils"; import { globalConfig } from "../../../core/config"; import { DrawParameters } from "../../../core/draw_parameters"; import { KEYMAPPINGS } from "../../key_action_mapper"; -import { enumEditMode } from "../../root"; +import { enumLayer } from "../../root"; import { THEME } from "../../theme"; import { BaseHUDPart } from "../base_hud_part"; +import { Loader } from "../../../core/loader"; +import { lerp } from "../../../core/utils"; -const wiresBackgroundDpi = 3; +const wiresBackgroundDpi = 4; export class HUDWiresOverlay extends BaseHUDPart { createElements(parent) {} @@ -16,49 +18,52 @@ export class HUDWiresOverlay extends BaseHUDPart { this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.switchLayers).add(this.switchLayers, this); this.generateTilePattern(); + + this.currentAlpha = 0.0; } /** * Switches between layers */ switchLayers() { - if (this.root.editMode === enumEditMode.regular) { - this.root.editMode = enumEditMode.wires; + if (this.root.currentLayer === enumLayer.regular) { + this.root.currentLayer = enumLayer.wires; } else { - this.root.editMode = enumEditMode.regular; + this.root.currentLayer = enumLayer.regular; } - this.root.signals.editModeChanged.dispatch(this.root.editMode); + this.root.signals.editModeChanged.dispatch(this.root.currentLayer); } /** * Generates the background pattern for the wires overlay */ generateTilePattern() { + const overlayTile = Loader.getSprite("sprites/misc/wires_overlay_tile.png"); const dims = globalConfig.tileSize * wiresBackgroundDpi; const [canvas, context] = makeOffscreenBuffer(dims, dims, { smooth: false, reusable: false, label: "wires-tile-pattern", }); - - context.scale(wiresBackgroundDpi, wiresBackgroundDpi); - context.fillStyle = THEME.map.wires.overlay; - context.fillRect(0, 0, globalConfig.tileSize, globalConfig.tileSize); - - const lineWidth = 1; - - context.fillRect(0, 0, globalConfig.tileSize, lineWidth); - context.fillRect(0, lineWidth, lineWidth, globalConfig.tileSize); - + overlayTile.draw(context, 0, 0, dims, dims); this.tilePatternCanvas = canvas; } + update() { + const desiredAlpha = this.root.currentLayer === enumLayer.wires ? 1.0 : 0.0; + this.currentAlpha = lerp(this.currentAlpha, desiredAlpha, 0.12); + } + /** * * @param {DrawParameters} parameters */ draw(parameters) { - if (this.root.editMode !== enumEditMode.wires) { + if (this.currentAlpha < 0.02) { + return; + } + + if (this.root.camera.getIsMapOverlayActive()) { return; } @@ -70,6 +75,8 @@ export class HUDWiresOverlay extends BaseHUDPart { const scaleFactor = 1 / wiresBackgroundDpi; + parameters.context.globalAlpha = 0.9 * this.currentAlpha; + parameters.context.globalCompositeOperation = "darken"; parameters.context.scale(scaleFactor, scaleFactor); parameters.context.fillStyle = this.cachedPatternBackground; parameters.context.fillRect( @@ -79,5 +86,12 @@ export class HUDWiresOverlay extends BaseHUDPart { bounds.h / scaleFactor ); parameters.context.scale(1 / scaleFactor, 1 / scaleFactor); + parameters.context.globalCompositeOperation = "source-over"; + parameters.context.globalAlpha = 1; + + // parameters.context.fillStyle = "#3a85bf"; + // parameters.context.globalAlpha = 0.0 * this.currentAlpha; + // parameters.context.fillRect(bounds.x, bounds.y, bounds.w, bounds.h); + // parameters.context.globalAlpha = 1; } } diff --git a/src/js/game/hud/parts/wires_toolbar.js b/src/js/game/hud/parts/wires_toolbar.js new file mode 100644 index 00000000..6ebc0a98 --- /dev/null +++ b/src/js/game/hud/parts/wires_toolbar.js @@ -0,0 +1,17 @@ +import { MetaWireBaseBuilding } from "../../buildings/wire_base"; +import { enumLayer } from "../../root"; +import { HUDBaseToolbar } from "./base_toolbar"; +import { MetaWireCrossingsBuilding } from "../../buildings/wire_crossings"; + +const supportedBuildings = [MetaWireBaseBuilding, MetaWireCrossingsBuilding]; + +export class HUDWiresToolbar extends HUDBaseToolbar { + constructor(root) { + super(root, { + supportedBuildings, + visibilityCondition: () => + !this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === enumLayer.wires, + htmlElementId: "ingame_HUD_wires_toolbar", + }); + } +} diff --git a/src/js/game/hud/trailer_maker.js b/src/js/game/hud/trailer_maker.js index 72509b93..2834b40d 100644 --- a/src/js/game/hud/trailer_maker.js +++ b/src/js/game/hud/trailer_maker.js @@ -1,7 +1,6 @@ -import { GameRoot } from "../root"; +import { GameRoot, enumLayer } from "../root"; import { globalConfig } from "../../core/config"; import { Vector, mixVector } from "../../core/vector"; -import { performanceNow } from "../../core/builtins"; import { lerp } from "../../core/utils"; /* dev:start */ @@ -87,18 +86,18 @@ export class TrailerMaker { if (!nextMarker.startTime) { console.log("Starting to approach", nextMarker.pos); - nextMarker.startTime = performanceNow() / 1000.0; + nextMarker.startTime = performance.now() / 1000.0; } const speed = globalConfig.tileSize * globalConfig.beltSpeedItemsPerSecond * - globalConfig.itemSpacingOnBelts; + globalConfig.beltItemSpacingByLayer[enumLayer.regular]; // let time = // this.currentPlaybackOrigin.distance(Vector.fromSerializedObject(nextMarker.pos)) / speed; const time = nextMarker.time; - const progress = (performanceNow() / 1000.0 - nextMarker.startTime) / time; + const progress = (performance.now() / 1000.0 - nextMarker.startTime) / time; if (progress > 1.0) { if (nextMarker.wait > 0) { diff --git a/src/js/game/item_registry.js b/src/js/game/item_registry.js index b6a77836..d483119f 100644 --- a/src/js/game/item_registry.js +++ b/src/js/game/item_registry.js @@ -1,8 +1,12 @@ import { gItemRegistry } from "../core/global_registries"; import { ShapeItem } from "./items/shape_item"; import { ColorItem } from "./items/color_item"; +import { PositiveEnergyItem } from "./items/positive_energy_item"; +import { NegativeEnergyItem } from "./items/negative_energy_item"; export function initItemRegistry() { gItemRegistry.register(ShapeItem); gItemRegistry.register(ColorItem); + gItemRegistry.register(PositiveEnergyItem); + gItemRegistry.register(NegativeEnergyItem); } diff --git a/src/js/game/items/color_item.js b/src/js/game/items/color_item.js index b2a3cd74..d1b9a217 100644 --- a/src/js/game/items/color_item.js +++ b/src/js/game/items/color_item.js @@ -2,7 +2,7 @@ import { globalConfig } from "../../core/config"; import { smoothenDpi } from "../../core/dpi_manager"; import { DrawParameters } from "../../core/draw_parameters"; import { types } from "../../savegame/serialization"; -import { BaseItem } from "../base_item"; +import { BaseItem, enumItemType } from "../base_item"; import { enumColors, enumColorsToHexCode } from "../colors"; import { THEME } from "../theme"; @@ -23,6 +23,10 @@ export class ColorItem extends BaseItem { this.color = data; } + getItemType() { + return enumItemType.color; + } + /** * @param {enumColors} color */ diff --git a/src/js/game/items/negative_energy_item.js b/src/js/game/items/negative_energy_item.js new file mode 100644 index 00000000..99e2cd06 --- /dev/null +++ b/src/js/game/items/negative_energy_item.js @@ -0,0 +1,37 @@ +import { DrawParameters } from "../../core/draw_parameters"; +import { Loader } from "../../core/loader"; +import { types } from "../../savegame/serialization"; +import { BaseItem, enumItemType } from "../base_item"; + +export class NegativeEnergyItem extends BaseItem { + static getId() { + return "negative_energy"; + } + + static getSchema() { + return types.uint; + } + + serialize() { + return 0; + } + + deserialize(data) {} + + getItemType() { + return enumItemType.negativeEnergy; + } + + /** + * @param {number} x + * @param {number} y + * @param {number} size + * @param {DrawParameters} parameters + */ + draw(x, y, parameters, size = 12) { + const sprite = Loader.getSprite("sprites/wires/negative_energy.png"); + sprite.drawCachedCentered(parameters, x, y, size * 1.5); + } +} + +export const NEGATIVE_ENERGY_ITEM_SINGLETON = new NegativeEnergyItem(); diff --git a/src/js/game/items/positive_energy_item.js b/src/js/game/items/positive_energy_item.js new file mode 100644 index 00000000..260ae149 --- /dev/null +++ b/src/js/game/items/positive_energy_item.js @@ -0,0 +1,37 @@ +import { DrawParameters } from "../../core/draw_parameters"; +import { Loader } from "../../core/loader"; +import { types } from "../../savegame/serialization"; +import { BaseItem, enumItemType } from "../base_item"; + +export class PositiveEnergyItem extends BaseItem { + static getId() { + return "positive_energy"; + } + + static getSchema() { + return types.uint; + } + + serialize() { + return 0; + } + + deserialize(data) {} + + getItemType() { + return enumItemType.positiveEnergy; + } + + /** + * @param {number} x + * @param {number} y + * @param {number} size + * @param {DrawParameters} parameters + */ + draw(x, y, parameters, size = 12) { + const sprite = Loader.getSprite("sprites/wires/positive_energy.png"); + sprite.drawCachedCentered(parameters, x, y, size * 1.5); + } +} + +export const POSITIVE_ENERGY_ITEM_SINGLETON = new PositiveEnergyItem(); diff --git a/src/js/game/items/shape_item.js b/src/js/game/items/shape_item.js index cfdb9830..2aca63f6 100644 --- a/src/js/game/items/shape_item.js +++ b/src/js/game/items/shape_item.js @@ -1,6 +1,6 @@ import { DrawParameters } from "../../core/draw_parameters"; import { types } from "../../savegame/serialization"; -import { BaseItem } from "../base_item"; +import { BaseItem, enumItemType } from "../base_item"; import { ShapeDefinition } from "../shape_definition"; import { THEME } from "../theme"; @@ -21,6 +21,10 @@ export class ShapeItem extends BaseItem { this.definition = ShapeDefinition.fromShortKey(data); } + getItemType() { + return enumItemType.shape; + } + /** * @param {ShapeDefinition} definition */ diff --git a/src/js/game/key_action_mapper.js b/src/js/game/key_action_mapper.js index 45949ae3..2dfc5bb1 100644 --- a/src/js/game/key_action_mapper.js +++ b/src/js/game/key_action_mapper.js @@ -7,8 +7,6 @@ import { Application } from "../application"; import { Signal, STOP_PROPAGATION } from "../core/signal"; import { IS_MOBILE } from "../core/config"; import { T } from "../translations"; -import { JSON_stringify } from "../core/builtins"; - function key(str) { return str.toUpperCase().charCodeAt(0); } @@ -22,6 +20,7 @@ export const KEYMAPPINGS = { ingame: { menuOpenShop: { keyCode: key("F") }, menuOpenStats: { keyCode: key("G") }, + menuClose: { keyCode: key("Q") }, toggleHud: { keyCode: 113 }, // F2 exportScreenshot: { keyCode: 114 }, // F3PS @@ -56,6 +55,11 @@ export const KEYMAPPINGS = { painter: { keyCode: key("9") }, trash: { keyCode: key("0") }, energy_generator: { keyCode: key("O") }, + advanced_processor: { keyCode: key("P") }, + + // Wires layer + wire: { keyCode: key("1") }, + wire_crossings: { keyCode: key("2") }, }, placement: { @@ -241,7 +245,6 @@ export function getStringForKeyCode(code) { return "'"; } - // TODO return String.fromCharCode(code); } @@ -443,7 +446,7 @@ export class KeyActionMapper { getBinding(binding) { // @ts-ignore const id = binding.id; - assert(id, "Not a valid keybinding: " + JSON_stringify(binding)); + assert(id, "Not a valid keybinding: " + JSON.stringify(binding)); assert(this.keybindings[id], "Keybinding " + id + " not known!"); return this.keybindings[id]; } diff --git a/src/js/game/logic.js b/src/js/game/logic.js index 5c1bbf66..403fa15b 100644 --- a/src/js/game/logic.js +++ b/src/js/game/logic.js @@ -1,13 +1,10 @@ -import { GameRoot } from "./root"; -import { Entity } from "./entity"; -import { Vector, enumDirectionToVector, enumDirection } from "../core/vector"; -import { MetaBuilding } from "./meta_building"; -import { StaticMapEntityComponent } from "./components/static_map_entity"; -import { Math_abs, performanceNow } from "../core/builtins"; import { createLogger } from "../core/logging"; -import { MetaBeltBaseBuilding, arrayBeltVariantToRotation } from "./buildings/belt_base"; -import { SOUNDS } from "../platform/sound"; import { round2Digits } from "../core/utils"; +import { enumDirection, enumDirectionToVector, Vector } from "../core/vector"; +import { Entity } from "./entity"; +import { MetaBuilding } from "./meta_building"; +import { enumLayer, GameRoot } from "./root"; +import { STOP_PROPAGATION } from "../core/signal"; const logger = createLogger("ingame/logic"); @@ -48,102 +45,41 @@ export class GameLogic { } /** - * @param {object} param0 - * @param {Vector} param0.origin - * @param {number} param0.rotation - * @param {number} param0.rotationVariant - * @param {string} param0.variant - * @param {MetaBuilding} param0.building - * @returns {boolean} + * Checks if the given entity can be placed + * @param {Entity} entity + * @param {Vector=} offset Optional, move the entity by the given offset first + * @returns {boolean} true if the entity could be placed there */ - isAreaFreeToBuild({ origin, rotation, rotationVariant, variant, building }) { - const checker = new StaticMapEntityComponent({ - origin, - tileSize: building.getDimensions(variant), - rotation, - blueprintSpriteKey: "", - }); - - const rect = checker.getTileSpaceBounds(); + checkCanPlaceEntity(entity, offset = null) { + // Compute area of the building + const rect = entity.components.StaticMapEntity.getTileSpaceBounds(); + if (offset) { + rect.x += offset.x; + rect.y += offset.y; + } + // Check the whole area of the building for (let x = rect.x; x < rect.x + rect.w; ++x) { for (let y = rect.y; y < rect.y + rect.h; ++y) { - const contents = this.root.map.getTileContentXY(x, y); - if (contents) { - if ( - !this.checkCanReplaceBuilding({ - original: contents, - origin, - building, - rotation, - rotationVariant, - }) - ) { - // Content already has same rotation - return false; - } + // Check if there is any direct collision + const otherEntity = this.root.map.getLayerContentXY(x, y, entity.layer); + if (otherEntity && !otherEntity.components.ReplaceableMapEntity) { + // This one is a direct blocker + return false; } } } - return true; - } - /** - * Checks if the given building can be replaced by another - * @param {object} param0 - * @param {Entity} param0.original - * @param {Vector} param0.origin - * @param {number} param0.rotation - * @param {number} param0.rotationVariant - * @param {MetaBuilding} param0.building - * @returns {boolean} - */ - checkCanReplaceBuilding({ original, origin, building, rotation, rotationVariant }) { - if (!original.components.ReplaceableMapEntity) { - // Can not get replaced at all + // Perform additional placement checks + if (this.root.signals.prePlacementCheck.dispatch(entity, offset) === STOP_PROPAGATION) { return false; } - const staticComp = original.components.StaticMapEntity; - assert(staticComp, "Building is not static"); - const beltComp = original.components.Belt; - if (beltComp && building instanceof MetaBeltBaseBuilding) { - // Its a belt, check if it differs in either rotation or rotation variant - if (staticComp.rotation !== rotation) { - return true; - } - if (beltComp.direction !== arrayBeltVariantToRotation[rotationVariant]) { - return true; - } - } - return true; } /** - * @param {object} param0 - * @param {Vector} param0.origin - * @param {number} param0.rotation - * @param {number} param0.rotationVariant - * @param {string} param0.variant - * @param {MetaBuilding} param0.building - */ - checkCanPlaceBuilding({ origin, rotation, rotationVariant, variant, building }) { - if (!building.getIsUnlocked(this.root)) { - return false; - } - - return this.isAreaFreeToBuild({ - origin, - rotation, - rotationVariant, - variant, - building, - }); - } - - /** - * + * Attempts to place the given building * @param {object} param0 * @param {Vector} param0.origin * @param {number} param0.rotation @@ -154,54 +90,62 @@ export class GameLogic { * @returns {Entity} */ tryPlaceBuilding({ origin, rotation, rotationVariant, originalRotation, variant, building }) { - if (this.checkCanPlaceBuilding({ origin, rotation, rotationVariant, variant, building })) { - // Remove any removeable entities below - const checker = new StaticMapEntityComponent({ - origin, - tileSize: building.getDimensions(variant), - rotation, - blueprintSpriteKey: "", - }); - - const rect = checker.getTileSpaceBounds(); - - for (let x = rect.x; x < rect.x + rect.w; ++x) { - for (let y = rect.y; y < rect.y + rect.h; ++y) { - const contents = this.root.map.getTileContentXY(x, y); - if (contents) { - if (!this.tryDeleteBuilding(contents)) { - logger.error("Building has replaceable component but is also unremovable"); - return null; - } - } - } - } - - const entity = building.createAndPlaceEntity({ - root: this.root, - origin, - rotation, - rotationVariant, - originalRotation, - variant, - }); - + const entity = building.createEntity({ + root: this.root, + origin, + rotation, + originalRotation, + rotationVariant, + variant, + }); + if (this.checkCanPlaceEntity(entity)) { + this.freeEntityAreaBeforeBuild(entity); + this.root.map.placeStaticEntity(entity); + this.root.entityMgr.registerEntity(entity); return entity; } return null; } + /** + * Removes all entities with a RemovableMapEntityComponent which need to get + * removed before placing this entity + * @param {Entity} entity + */ + freeEntityAreaBeforeBuild(entity) { + const staticComp = entity.components.StaticMapEntity; + const rect = staticComp.getTileSpaceBounds(); + // Remove any removeable colliding entities on the same layer + for (let x = rect.x; x < rect.x + rect.w; ++x) { + for (let y = rect.y; y < rect.y + rect.h; ++y) { + const contents = this.root.map.getLayerContentXY(x, y, entity.layer); + if (contents) { + assertAlways( + contents.components.ReplaceableMapEntity, + "Tried to replace non-repleaceable entity" + ); + if (!this.tryDeleteBuilding(contents)) { + assertAlways(false, "Tried to replace non-repleaceable entity #2"); + } + } + } + } + + // Perform other callbacks + this.root.signals.freeEntityAreaBeforeBuild.dispatch(entity); + } + /** * Performs a bulk operation, not updating caches in the meantime * @param {function} operation */ performBulkOperation(operation) { - logger.log("Running bulk operation ..."); + logger.warn("Running bulk operation ..."); assert(!this.root.bulkOperationRunning, "Can not run two bulk operations twice"); this.root.bulkOperationRunning = true; - const now = performanceNow(); + const now = performance.now(); const returnValue = operation(); - const duration = performanceNow() - now; + const duration = performance.now() - now; logger.log("Done in", round2Digits(duration), "ms"); assert(this.root.bulkOperationRunning, "Bulk operation = false while bulk operation was running"); this.root.bulkOperationRunning = false; @@ -227,33 +171,41 @@ export class GameLogic { } this.root.map.removeStaticEntity(building); this.root.entityMgr.destroyEntity(building); + this.root.entityMgr.processDestroyList(); return true; } /** * Returns the acceptors and ejectors which affect the current tile * @param {Vector} tile + * @param {enumLayer} layer * @returns {AcceptorsAndEjectorsAffectingTile} */ - getEjectorsAndAcceptorsAtTile(tile) { + getEjectorsAndAcceptorsAtTile(tile, layer) { /** @type {EjectorsAffectingTile} */ let ejectors = []; /** @type {AcceptorsAffectingTile} */ let acceptors = []; + // Well .. please ignore this code! :D for (let dx = -1; dx <= 1; ++dx) { for (let dy = -1; dy <= 1; ++dy) { - if (Math_abs(dx) + Math_abs(dy) !== 1) { + if (Math.abs(dx) + Math.abs(dy) !== 1) { continue; } - const entity = this.root.map.getTileContentXY(tile.x + dx, tile.y + dy); - if (entity) { + const entities = this.root.map.getLayersContentsMultipleXY(tile.x + dx, tile.y + dy); + for (let i = 0; i < entities.length; ++i) { + const entity = entities[i]; + const staticComp = entity.components.StaticMapEntity; const itemEjector = entity.components.ItemEjector; if (itemEjector) { for (let ejectorSlot = 0; ejectorSlot < itemEjector.slots.length; ++ejectorSlot) { const slot = itemEjector.slots[ejectorSlot]; + if (slot.layer !== layer) { + continue; + } const wsTile = staticComp.localTileToWorld(slot.pos); const wsDirection = staticComp.localDirectionToWorld(slot.direction); const targetTile = wsTile.add(enumDirectionToVector[wsDirection]); @@ -272,6 +224,10 @@ export class GameLogic { if (itemAcceptor) { for (let acceptorSlot = 0; acceptorSlot < itemAcceptor.slots.length; ++acceptorSlot) { const slot = itemAcceptor.slots[acceptorSlot]; + if (slot.layer !== layer) { + continue; + } + const wsTile = staticComp.localTileToWorld(slot.pos); for (let k = 0; k < slot.directions.length; ++k) { const direction = slot.directions[k]; diff --git a/src/js/game/map.js b/src/js/game/map.js index ef745c6d..3f8a16f8 100644 --- a/src/js/game/map.js +++ b/src/js/game/map.js @@ -1,11 +1,7 @@ -/* typehints:start */ -import { GameRoot } from "./root"; -/* typehints:end */ - +import { GameRoot, enumLayer } from "./root"; import { globalConfig } from "../core/config"; import { Vector } from "../core/vector"; import { Entity } from "./entity"; -import { Math_floor } from "../core/builtins"; import { createLogger } from "../core/logging"; import { BaseItem } from "./base_item"; import { MapChunkView } from "./map_chunk_view"; @@ -47,7 +43,6 @@ export class BaseMap extends BasicSerializableObject { * @param {number} chunkY */ getChunk(chunkX, chunkY, createIfNotExistent = false) { - // TODO: Better generation const chunkIdentifier = chunkX + "|" + chunkY; let storedChunk; @@ -71,8 +66,8 @@ export class BaseMap extends BasicSerializableObject { * @returns {MapChunkView} */ getOrCreateChunkAtTile(tileX, tileY) { - const chunkX = Math_floor(tileX / globalConfig.mapChunkSize); - const chunkY = Math_floor(tileY / globalConfig.mapChunkSize); + const chunkX = Math.floor(tileX / globalConfig.mapChunkSize); + const chunkY = Math.floor(tileY / globalConfig.mapChunkSize); return this.getChunk(chunkX, chunkY, true); } @@ -83,8 +78,8 @@ export class BaseMap extends BasicSerializableObject { * @returns {MapChunkView?} */ getChunkAtTileOrNull(tileX, tileY) { - const chunkX = Math_floor(tileX / globalConfig.mapChunkSize); - const chunkY = Math_floor(tileY / globalConfig.mapChunkSize); + const chunkX = Math.floor(tileX / globalConfig.mapChunkSize); + const chunkY = Math.floor(tileY / globalConfig.mapChunkSize); return this.getChunk(chunkX, chunkY, false); } @@ -103,14 +98,15 @@ export class BaseMap extends BasicSerializableObject { /** * Returns the tile content of a given tile * @param {Vector} tile + * @param {enumLayer} layer * @returns {Entity} Entity or null */ - getTileContent(tile) { + getTileContent(tile, layer) { if (G_IS_DEV) { this.internalCheckTile(tile); } const chunk = this.getChunkAtTileOrNull(tile.x, tile.y); - return chunk && chunk.getTileContentFromWorldCoords(tile.x, tile.y); + return chunk && chunk.getLayerContentFromWorldCoords(tile.x, tile.y, layer); } /** @@ -127,35 +123,52 @@ export class BaseMap extends BasicSerializableObject { * Returns the tile content of a given tile * @param {number} x * @param {number} y + * @param {enumLayer} layer * @returns {Entity} Entity or null */ - getTileContentXY(x, y) { + getLayerContentXY(x, y, layer) { const chunk = this.getChunkAtTileOrNull(x, y); - return chunk && chunk.getTileContentFromWorldCoords(x, y); + return chunk && chunk.getLayerContentFromWorldCoords(x, y, layer); + } + + /** + * Returns the tile contents of a given tile + * @param {number} x + * @param {number} y + * @returns {Array} Entity or null + */ + getLayersContentsMultipleXY(x, y) { + const chunk = this.getChunkAtTileOrNull(x, y); + if (!chunk) { + return []; + } + return chunk.getLayersContentsMultipleFromWorldCoords(x, y); } /** * Checks if the tile is used * @param {Vector} tile + * @param {enumLayer} layer * @returns {boolean} */ - isTileUsed(tile) { + isTileUsed(tile, layer) { if (G_IS_DEV) { this.internalCheckTile(tile); } const chunk = this.getChunkAtTileOrNull(tile.x, tile.y); - return chunk && chunk.getTileContentFromWorldCoords(tile.x, tile.y) != null; + return chunk && chunk.getLayerContentFromWorldCoords(tile.x, tile.y, layer) != null; } /** * Checks if the tile is used * @param {number} x * @param {number} y + * @param {enumLayer} layer * @returns {boolean} */ - isTileUsedXY(x, y) { + isTileUsedXY(x, y, layer) { const chunk = this.getChunkAtTileOrNull(x, y); - return chunk && chunk.getTileContentFromWorldCoords(x, y) != null; + return chunk && chunk.getLayerContentFromWorldCoords(x, y, layer) != null; } /** @@ -168,7 +181,12 @@ export class BaseMap extends BasicSerializableObject { this.internalCheckTile(tile); } - this.getOrCreateChunkAtTile(tile.x, tile.y).setTileContentFromWorldCords(tile.x, tile.y, entity); + this.getOrCreateChunkAtTile(tile.x, tile.y).setLayerContentFromWorldCords( + tile.x, + tile.y, + entity, + entity.layer + ); const staticComponent = entity.components.StaticMapEntity; assert(staticComponent, "Can only place static map entities in tiles"); @@ -186,7 +204,7 @@ export class BaseMap extends BasicSerializableObject { for (let dy = 0; dy < rect.h; ++dy) { const x = rect.x + dx; const y = rect.y + dy; - this.getOrCreateChunkAtTile(x, y).setTileContentFromWorldCords(x, y, entity); + this.getOrCreateChunkAtTile(x, y).setLayerContentFromWorldCords(x, y, entity, entity.layer); } } } @@ -203,22 +221,11 @@ export class BaseMap extends BasicSerializableObject { for (let dy = 0; dy < rect.h; ++dy) { const x = rect.x + dx; const y = rect.y + dy; - this.getOrCreateChunkAtTile(x, y).setTileContentFromWorldCords(x, y, null); + this.getOrCreateChunkAtTile(x, y).setLayerContentFromWorldCords(x, y, null, entity.layer); } } } - /** - * Resets the tiles content - * @param {Vector} tile - */ - clearTile(tile) { - if (G_IS_DEV) { - this.internalCheckTile(tile); - } - this.getOrCreateChunkAtTile(tile.x, tile.y).setTileContentFromWorldCords(tile.x, tile.y, null); - } - // Internal /** diff --git a/src/js/game/map_chunk.js b/src/js/game/map_chunk.js index bffaf9e8..dd9ba81d 100644 --- a/src/js/game/map_chunk.js +++ b/src/js/game/map_chunk.js @@ -1,8 +1,4 @@ -/* typehints:start */ -import { GameRoot } from "./root"; -/* typehints:end */ - -import { Math_ceil, Math_max, Math_min, Math_round } from "../core/builtins"; +import { GameRoot, enumLayer } from "./root"; import { globalConfig } from "../core/config"; import { createLogger } from "../core/logging"; import { clamp, fastArrayDeleteValueIfContained, make2DUndefinedArray } from "../core/utils"; @@ -38,6 +34,13 @@ export class MapChunk { "map-chunk@" + this.x + "|" + this.y ); + /** @type {Array>} */ + this.wireContents = make2DUndefinedArray( + globalConfig.mapChunkSize, + globalConfig.mapChunkSize, + "map-chunk-wires@" + this.x + "|" + this.y + ); + /** @type {Array>} */ this.lowerLayer = make2DUndefinedArray( globalConfig.mapChunkSize, @@ -66,7 +69,7 @@ export class MapChunk { * @param {number=} overrideY Override the Y position of the patch */ internalGeneratePatch(rng, patchSize, item, overrideX = null, overrideY = null) { - const border = Math_ceil(patchSize / 2 + 3); + const border = Math.ceil(patchSize / 2 + 3); // Find a position within the chunk which is not blocked let patchX = rng.nextIntRange(border, globalConfig.mapChunkSize - border - 1); @@ -88,7 +91,7 @@ export class MapChunk { for (let i = 0; i <= numCircles; ++i) { // Determine circle parameters - const circleRadius = Math_min(1 + i, patchSize); + const circleRadius = Math.min(1 + i, patchSize); const circleRadiusSquare = circleRadius * circleRadius; const circleOffsetRadius = (numCircles - i) / 2 + 2; @@ -101,8 +104,8 @@ export class MapChunk { for (let dx = -circleRadius * circleScaleX - 2; dx <= circleRadius * circleScaleX + 2; ++dx) { for (let dy = -circleRadius * circleScaleY - 2; dy <= circleRadius * circleScaleY + 2; ++dy) { - const x = Math_round(circleX + dx); - const y = Math_round(circleY + dy); + const x = Math.round(circleX + dx); + const y = Math.round(circleY + dy); if (x >= 0 && x < globalConfig.mapChunkSize && y >= 0 && y <= globalConfig.mapChunkSize) { const originalDx = dx / circleScaleX; const originalDy = dy / circleScaleY; @@ -158,9 +161,9 @@ export class MapChunk { // Later there is a mix of everything weights = { [enumSubShape.rect]: 100, - [enumSubShape.circle]: Math_round(50 + clamp(distanceToOriginInChunks * 2, 0, 50)), - [enumSubShape.star]: Math_round(20 + clamp(distanceToOriginInChunks, 0, 30)), - [enumSubShape.windmill]: Math_round(6 + clamp(distanceToOriginInChunks / 2, 0, 20)), + [enumSubShape.circle]: Math.round(50 + clamp(distanceToOriginInChunks * 2, 0, 50)), + [enumSubShape.star]: Math.round(20 + clamp(distanceToOriginInChunks, 0, 30)), + [enumSubShape.windmill]: Math.round(6 + clamp(distanceToOriginInChunks / 2, 0, 20)), }; if (distanceToOriginInChunks < 7) { @@ -239,20 +242,20 @@ export class MapChunk { } const chunkCenter = new Vector(this.x, this.y).addScalar(0.5); - const distanceToOriginInChunks = Math_round(chunkCenter.length()); + const distanceToOriginInChunks = Math.round(chunkCenter.length()); // Determine how likely it is that there is a color patch const colorPatchChance = 0.9 - clamp(distanceToOriginInChunks / 25, 0, 1) * 0.5; if (rng.next() < colorPatchChance / 4) { - const colorPatchSize = Math_max(2, Math_round(1 + clamp(distanceToOriginInChunks / 8, 0, 4))); + const colorPatchSize = Math.max(2, Math.round(1 + clamp(distanceToOriginInChunks / 8, 0, 4))); this.internalGenerateColorPatch(rng, colorPatchSize, distanceToOriginInChunks); } // Determine how likely it is that there is a shape patch const shapePatchChance = 0.9 - clamp(distanceToOriginInChunks / 25, 0, 1) * 0.5; if (rng.next() < shapePatchChance / 4) { - const shapePatchSize = Math_max(2, Math_round(1 + clamp(distanceToOriginInChunks / 8, 0, 4))); + const shapePatchSize = Math.max(2, Math.round(1 + clamp(distanceToOriginInChunks / 8, 0, 4))); this.internalGenerateShapePatch(rng, shapePatchSize, distanceToOriginInChunks); } } @@ -325,6 +328,53 @@ export class MapChunk { return this.contents[localX][localY] || null; } + /** + * Returns the contents of this chunk from the given world space coordinates + * @param {number} worldX + * @param {number} worldY + * @param {enumLayer} layer + * @returns {Entity=} + */ + getLayerContentFromWorldCoords(worldX, worldY, layer) { + const localX = worldX - this.tileX; + const localY = worldY - this.tileY; + assert(localX >= 0, "Local X is < 0"); + assert(localY >= 0, "Local Y is < 0"); + assert(localX < globalConfig.mapChunkSize, "Local X is >= chunk size"); + assert(localY < globalConfig.mapChunkSize, "Local Y is >= chunk size"); + if (layer === enumLayer.regular) { + return this.contents[localX][localY] || null; + } else { + return this.wireContents[localX][localY] || null; + } + } + /** + * Returns the contents of this chunk from the given world space coordinates + * @param {number} worldX + * @param {number} worldY + * @returns {Array} + */ + getLayersContentsMultipleFromWorldCoords(worldX, worldY) { + const localX = worldX - this.tileX; + const localY = worldY - this.tileY; + assert(localX >= 0, "Local X is < 0"); + assert(localY >= 0, "Local Y is < 0"); + assert(localX < globalConfig.mapChunkSize, "Local X is >= chunk size"); + assert(localY < globalConfig.mapChunkSize, "Local Y is >= chunk size"); + + const regularContent = this.contents[localX][localY]; + const wireContent = this.wireContents[localX][localY]; + + const result = []; + if (regularContent) { + result.push(regularContent); + } + if (wireContent) { + result.push(wireContent); + } + return result; + } + /** * Returns the chunks contents from the given local coordinates * @param {number} localX @@ -345,22 +395,36 @@ export class MapChunk { * @param {number} tileX * @param {number} tileY * @param {Entity=} contents + * @param {enumLayer} layer */ - setTileContentFromWorldCords(tileX, tileY, contents) { + setLayerContentFromWorldCords(tileX, tileY, contents, layer) { const localX = tileX - this.tileX; const localY = tileY - this.tileY; assert(localX >= 0, "Local X is < 0"); assert(localY >= 0, "Local Y is < 0"); assert(localX < globalConfig.mapChunkSize, "Local X is >= chunk size"); assert(localY < globalConfig.mapChunkSize, "Local Y is >= chunk size"); - const oldContents = this.contents[localX][localY]; + + let oldContents; + if (layer === enumLayer.regular) { + oldContents = this.contents[localX][localY]; + } else { + oldContents = this.wireContents[localX][localY]; + } + assert(contents === null || !oldContents, "Tile already used: " + tileX + " / " + tileY); if (oldContents) { // Remove from list fastArrayDeleteValueIfContained(this.containedEntities, oldContents); } - this.contents[localX][localY] = contents; + + if (layer === enumLayer.regular) { + this.contents[localX][localY] = contents; + } else { + this.wireContents[localX][localY] = contents; + } + if (contents) { if (this.containedEntities.indexOf(contents) < 0) { this.containedEntities.push(contents); diff --git a/src/js/game/map_chunk_view.js b/src/js/game/map_chunk_view.js index cc0734d8..c3f09b39 100644 --- a/src/js/game/map_chunk_view.js +++ b/src/js/game/map_chunk_view.js @@ -3,7 +3,6 @@ import { GameRoot } from "./root"; import { globalConfig } from "../core/config"; import { DrawParameters } from "../core/draw_parameters"; import { round1Digit } from "../core/utils"; -import { Math_max, Math_round } from "../core/builtins"; import { Rectangle } from "../core/rectangle"; import { createLogger } from "../core/logging"; import { smoothenDpi } from "../core/dpi_manager"; @@ -22,9 +21,6 @@ export class MapChunkView extends MapChunk { constructor(root, x, y) { super(root, x, y); - this.boundInternalDrawBackgroundToContext = this.internalDrawBackgroundToContext.bind(this); - this.boundInternalDrawForegroundToContext = this.internalDrawForegroundToContext.bind(this); - /** * Whenever something changes, we increase this number - so we know we need to redraw */ @@ -46,29 +42,9 @@ export class MapChunkView extends MapChunk { * @param {DrawParameters} parameters */ drawBackgroundLayer(parameters) { - if (parameters.zoomLevel > globalConfig.mapChunkPrerenderMinZoom) { - this.internalDrawBackgroundSystems(parameters); - return; - } - - const dpi = smoothenDpi(parameters.zoomLevel); - const buffer = this.root.buffers.getForKey( - "" + dpi, - this.renderKey + "@bg", - chunkSizePixels, - chunkSizePixels, - dpi, - this.boundInternalDrawBackgroundToContext, - { zoomLevel: parameters.zoomLevel } - ); - - parameters.context.drawImage( - buffer, - this.tileX * globalConfig.tileSize, - this.tileY * globalConfig.tileSize, - chunkSizePixels, - chunkSizePixels - ); + const systems = this.root.systemMgr.systems; + systems.mapResources.drawChunk(parameters, this); + systems.belt.drawChunk(parameters, this); } /** @@ -76,127 +52,26 @@ export class MapChunkView extends MapChunk { * @param {DrawParameters} parameters */ drawForegroundLayer(parameters) { - if (parameters.zoomLevel > globalConfig.mapChunkPrerenderMinZoom) { - this.internalDrawForegroundSystems(parameters); - return; - } - - const dpi = smoothenDpi(parameters.zoomLevel); - const buffer = this.root.buffers.getForKey( - "" + dpi, - this.renderKey + "@fg", - chunkSizePixels, - chunkSizePixels, - dpi, - this.boundInternalDrawForegroundToContext, - { zoomLevel: parameters.zoomLevel } - ); - parameters.context.drawImage( - buffer, - this.tileX * globalConfig.tileSize, - this.tileY * globalConfig.tileSize, - chunkSizePixels, - chunkSizePixels - ); - } - - /** - * - * @param {HTMLCanvasElement} canvas - * @param {CanvasRenderingContext2D} context - * @param {number} w - * @param {number} h - * @param {number} dpi - */ - internalDrawBackgroundToContext(canvas, context, w, h, dpi, { zoomLevel }) { - const pattern = context.createPattern(this.root.map.cachedBackgroundCanvas, "repeat"); - context.scale(dpi, dpi); - - if (zoomLevel >= globalConfig.mapChunkOverviewMinZoom) { - const bgDpi = this.root.map.backgroundCacheDPI; - context.scale(1 / bgDpi, 1 / bgDpi); - context.fillStyle = pattern; - context.fillRect(0, 0, chunkSizePixels * bgDpi, chunkSizePixels * bgDpi); - context.scale(bgDpi, bgDpi); - } else { - if (this.containedEntities.length > 0) { - context.fillStyle = THEME.map.chunkOverview.filled; - } else { - context.fillStyle = THEME.map.chunkOverview.empty; - } - context.fillRect(0, 0, 10000, 10000); - } - - if (G_IS_DEV && globalConfig.debug.showChunkBorders) { - context.fillStyle = "rgba(0, 0, 255, 0.1)"; - context.fillRect(0, 0, 10000, 10000); - } - - const parameters = new DrawParameters({ - context, - visibleRect: new Rectangle( - this.tileX * globalConfig.tileSize, - this.tileY * globalConfig.tileSize, - chunkSizePixels, - chunkSizePixels - ), - desiredAtlasScale: "1", - zoomLevel, - root: this.root, - }); - - parameters.context.translate( - -this.tileX * globalConfig.tileSize, - -this.tileY * globalConfig.tileSize - ); - this.internalDrawBackgroundSystems(parameters); - } - - /** - * - * @param {HTMLCanvasElement} canvas - * @param {CanvasRenderingContext2D} context - * @param {number} w - * @param {number} h - * @param {number} dpi - */ - internalDrawForegroundToContext(canvas, context, w, h, dpi, { zoomLevel }) { - context.scale(dpi, dpi); - - const parameters = new DrawParameters({ - context, - visibleRect: new Rectangle( - this.tileX * globalConfig.tileSize, - this.tileY * globalConfig.tileSize, - chunkSizePixels, - chunkSizePixels - ), - desiredAtlasScale: "1", - zoomLevel, - root: this.root, - }); - parameters.context.translate( - -this.tileX * globalConfig.tileSize, - -this.tileY * globalConfig.tileSize - ); - this.internalDrawForegroundSystems(parameters); - } - - /** - * @param {DrawParameters} parameters - */ - internalDrawBackgroundSystems(parameters) { - const systems = this.root.systemMgr.systems; - systems.mapResources.drawChunk(parameters, this); - systems.belt.drawChunk(parameters, this); - } - - /** - * @param {DrawParameters} parameters - */ - internalDrawForegroundSystems(parameters) { const systems = this.root.systemMgr.systems; systems.miner.drawChunk(parameters, this); systems.staticMapEntities.drawChunk(parameters, this); } + + /** + * Draws the wires layer + * @param {DrawParameters} parameters + */ + drawWiresLayer(parameters) { + const systems = this.root.systemMgr.systems; + systems.belt.drawWiresChunk(parameters, this); + } + + /** + * Draws the wires layer + * @param {DrawParameters} parameters + */ + drawWiresForegroundLayer(parameters) { + const systems = this.root.systemMgr.systems; + systems.staticMapEntities.drawWiresChunk(parameters, this); + } } diff --git a/src/js/game/map_view.js b/src/js/game/map_view.js index 5c4bf88a..bd10755c 100644 --- a/src/js/game/map_view.js +++ b/src/js/game/map_view.js @@ -1,10 +1,10 @@ -import { Math_max, Math_min, Math_floor, Math_ceil } from "../core/builtins"; import { globalConfig } from "../core/config"; import { DrawParameters } from "../core/draw_parameters"; import { BaseMap } from "./map"; import { freeCanvas, makeOffscreenBuffer } from "../core/buffer_utils"; import { Entity } from "./entity"; import { THEME } from "./theme"; +import { MapChunkView } from "./map_chunk_view"; /** * This is the view of the map, it extends the map which is the raw model and allows @@ -36,6 +36,7 @@ export class MapView extends BaseMap { this.root.signals.entityAdded.add(this.onEntityChanged, this); this.root.signals.entityDestroyed.add(this.onEntityChanged, this); + this.root.signals.entityChanged.add(this.onEntityChanged, this); } cleanup() { @@ -45,7 +46,7 @@ export class MapView extends BaseMap { } /** - * Called when an entity was added or removed + * Called when an entity was added, removed or changed * @param {Entity} entity */ onEntityChanged(entity) { @@ -130,6 +131,15 @@ export class MapView extends BaseMap { * @param {DrawParameters} parameters */ drawForeground(parameters) { + this.drawVisibleChunks(parameters, MapChunkView.prototype.drawForegroundLayer); + } + + /** + * Calls a given method on all given chunks + * @param {DrawParameters} parameters + * @param {function} method + */ + drawVisibleChunks(parameters, method) { const cullRange = parameters.visibleRect.toTileCullRectangle(); const top = cullRange.top(); const right = cullRange.right(); @@ -142,21 +152,37 @@ export class MapView extends BaseMap { const minX = left - border; const maxX = right + border - 1; - const chunkStartX = Math_floor(minX / globalConfig.mapChunkSize); - const chunkStartY = Math_floor(minY / globalConfig.mapChunkSize); + const chunkStartX = Math.floor(minX / globalConfig.mapChunkSize); + const chunkStartY = Math.floor(minY / globalConfig.mapChunkSize); - const chunkEndX = Math_ceil(maxX / globalConfig.mapChunkSize); - const chunkEndY = Math_ceil(maxY / globalConfig.mapChunkSize); + const chunkEndX = Math.ceil(maxX / globalConfig.mapChunkSize); + const chunkEndY = Math.ceil(maxY / globalConfig.mapChunkSize); // Render y from top down for proper blending for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) { for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) { const chunk = this.root.map.getChunk(chunkX, chunkY, true); - chunk.drawForegroundLayer(parameters); + method.call(chunk, parameters); } } } + /** + * Draws the wires background + * @param {DrawParameters} parameters + */ + drawWiresLayer(parameters) { + this.drawVisibleChunks(parameters, MapChunkView.prototype.drawWiresLayer); + } + + /** + * Draws the wires foreground + * @param {DrawParameters} parameters + */ + drawWiresForegroundLayer(parameters) { + this.drawVisibleChunks(parameters, MapChunkView.prototype.drawWiresForegroundLayer); + } + /** * Draws the map background * @param {DrawParameters} parameters @@ -184,31 +210,7 @@ export class MapView extends BaseMap { parameters.context.scale(dpi, dpi); } - const cullRange = parameters.visibleRect.toTileCullRectangle(); - const top = cullRange.top(); - const right = cullRange.right(); - const bottom = cullRange.bottom(); - const left = cullRange.left(); - - const border = 1; - const minY = top - border; - const maxY = bottom + border; - const minX = left - border; - const maxX = right + border - 1; - - const chunkStartX = Math_floor(minX / globalConfig.mapChunkSize); - const chunkStartY = Math_floor(minY / globalConfig.mapChunkSize); - - const chunkEndX = Math_ceil(maxX / globalConfig.mapChunkSize); - const chunkEndY = Math_ceil(maxY / globalConfig.mapChunkSize); - - // Render y from top down for proper blending - for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) { - for (let chunkY = chunkStartY; chunkY <= chunkEndY; ++chunkY) { - const chunk = this.root.map.getChunk(chunkX, chunkY, true); - chunk.drawBackgroundLayer(parameters); - } - } + this.drawVisibleChunks(parameters, MapChunkView.prototype.drawBackgroundLayer); if (G_IS_DEV && globalConfig.debug.showChunkBorders) { const cullRange = parameters.visibleRect.toTileCullRectangle(); @@ -223,11 +225,11 @@ export class MapView extends BaseMap { const minX = left - border; const maxX = right + border - 1; - const chunkStartX = Math_floor(minX / globalConfig.mapChunkSize); - const chunkStartY = Math_floor(minY / globalConfig.mapChunkSize); + const chunkStartX = Math.floor(minX / globalConfig.mapChunkSize); + const chunkStartY = Math.floor(minY / globalConfig.mapChunkSize); - const chunkEndX = Math_ceil(maxX / globalConfig.mapChunkSize); - const chunkEndY = Math_ceil(maxY / globalConfig.mapChunkSize); + const chunkEndX = Math.ceil(maxX / globalConfig.mapChunkSize); + const chunkEndY = Math.ceil(maxY / globalConfig.mapChunkSize); // Render y from top down for proper blending for (let chunkX = chunkStartX; chunkX <= chunkEndX; ++chunkX) { diff --git a/src/js/game/meta_building.js b/src/js/game/meta_building.js index 798e4d4c..514474c9 100644 --- a/src/js/game/meta_building.js +++ b/src/js/game/meta_building.js @@ -4,7 +4,7 @@ import { Vector } from "../core/vector"; import { SOUNDS } from "../platform/sound"; import { StaticMapEntityComponent } from "./components/static_map_entity"; import { Entity } from "./entity"; -import { enumEditMode, GameRoot } from "./root"; +import { enumLayer, GameRoot } from "./root"; export const defaultBuildingVariant = "default"; @@ -26,10 +26,10 @@ export class MetaBuilding { /** * Returns the edit layer of the building - * @returns {enumEditMode} + * @returns {enumLayer} */ - getEditLayer() { - return enumEditMode.regular; + getLayer() { + return enumLayer.regular; } /** @@ -144,30 +144,6 @@ export class MetaBuilding { return null; } - /** - * Creates the entity at the given location - * @param {object} param0 - * @param {GameRoot} param0.root - * @param {Vector} param0.origin Origin tile - * @param {number=} param0.rotation Rotation - * @param {number} param0.originalRotation Original Rotation - * @param {number} param0.rotationVariant Rotation variant - * @param {string} param0.variant - */ - createAndPlaceEntity({ root, origin, rotation, originalRotation, rotationVariant, variant }) { - const entity = this.createEntity({ - root, - origin, - rotation, - originalRotation, - rotationVariant, - variant, - }); - root.map.placeStaticEntity(entity); - root.entityMgr.registerEntity(entity); - return entity; - } - /** * Creates the entity without placing it * @param {object} param0 @@ -180,6 +156,7 @@ export class MetaBuilding { */ createEntity({ root, origin, rotation, originalRotation, rotationVariant, variant }) { const entity = new Entity(root); + entity.layer = this.getLayer(); const blueprintSprite = this.getBlueprintSprite(rotationVariant, variant); entity.addComponent( new StaticMapEntityComponent({ @@ -203,13 +180,15 @@ export class MetaBuilding { /** * Should compute the optimal rotation variant on the given tile - * @param {GameRoot} root - * @param {Vector} tile - * @param {number} rotation - * @param {string} variant + * @param {object} param0 + * @param {GameRoot} param0.root + * @param {Vector} param0.tile + * @param {number} param0.rotation + * @param {string} param0.variant + * @param {string} param0.layer * @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array }} */ - computeOptimalDirectionAndRotationVariantAtTile(root, tile, rotation, variant) { + computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) { if (!this.isRotateable(variant)) { return { rotation: 0, diff --git a/src/js/game/meta_building_registry.js b/src/js/game/meta_building_registry.js index 0f37762d..4e1fdd81 100644 --- a/src/js/game/meta_building_registry.js +++ b/src/js/game/meta_building_registry.js @@ -11,6 +11,10 @@ import { MetaTrashBuilding } from "./buildings/trash"; import { MetaUndergroundBeltBuilding } from "./buildings/underground_belt"; import { MetaHubBuilding } from "./buildings/hub"; import { MetaEnergyGenerator } from "./buildings/energy_generator"; +import { MetaWireBaseBuilding } from "./buildings/wire_base"; +import { MetaAdvancedProcessorBuilding } from "./buildings/advanced_processor"; +import { MetaBeltBuilding } from "./buildings/belt"; +import { MetaWireCrossingsBuilding } from "./buildings/wire_crossings"; export function initMetaBuildingRegistry() { gMetaBuildingRegistry.register(MetaSplitterBuilding); @@ -21,8 +25,11 @@ export function initMetaBuildingRegistry() { gMetaBuildingRegistry.register(MetaMixerBuilding); gMetaBuildingRegistry.register(MetaPainterBuilding); gMetaBuildingRegistry.register(MetaTrashBuilding); - gMetaBuildingRegistry.register(MetaBeltBaseBuilding); + gMetaBuildingRegistry.register(MetaBeltBuilding); gMetaBuildingRegistry.register(MetaUndergroundBeltBuilding); gMetaBuildingRegistry.register(MetaHubBuilding); gMetaBuildingRegistry.register(MetaEnergyGenerator); + gMetaBuildingRegistry.register(MetaWireBaseBuilding); + gMetaBuildingRegistry.register(MetaAdvancedProcessorBuilding); + gMetaBuildingRegistry.register(MetaWireCrossingsBuilding); } diff --git a/src/js/game/production_analytics.js b/src/js/game/production_analytics.js index 1abac940..41ec31ae 100644 --- a/src/js/game/production_analytics.js +++ b/src/js/game/production_analytics.js @@ -1,7 +1,7 @@ import { GameRoot } from "./root"; import { ShapeDefinition } from "./shape_definition"; import { globalConfig } from "../core/config"; -import { BaseItem } from "./base_item"; +import { BaseItem, enumItemType } from "./base_item"; import { ShapeItem } from "./items/shape_item"; import { BasicSerializableObject } from "../savegame/serialization"; @@ -53,8 +53,8 @@ export class ProductionAnalytics extends BasicSerializableObject { * @param {BaseItem} item */ onItemProduced(item) { - if (item instanceof ShapeItem) { - const definition = item.definition; + if (item.getItemType() === enumItemType.shape) { + const definition = /** @type {ShapeItem} */ (item).definition; const key = definition.getHash(); const entry = this.history[enumAnalyticsDataSource.produced]; entry[entry.length - 1][key] = (entry[entry.length - 1][key] || 0) + 1; diff --git a/src/js/game/root.js b/src/js/game/root.js index e8808317..df0db09e 100644 --- a/src/js/game/root.js +++ b/src/js/game/root.js @@ -27,16 +27,20 @@ import { ShapeDefinition } from "./shape_definition"; import { BaseItem } from "./base_item"; import { DynamicTickrate } from "./dynamic_tickrate"; import { KeyActionMapper } from "./key_action_mapper"; +import { Vector } from "../core/vector"; /* typehints:end */ const logger = createLogger("game/root"); /** @enum {string} */ -export const enumEditMode = { +export const enumLayer = { regular: "regular", wires: "wires", }; +/** @type {Array} */ +export const arrayLayers = [enumLayer.regular, enumLayer.wires]; + /** * The game root is basically the whole game state at a given point, * combining all important classes. We don't have globals, but this @@ -130,13 +134,14 @@ export class GameRoot { /** @type {DynamicTickrate} */ this.dynamicTickrate = null; - /** @type {enumEditMode} */ - this.editMode = enumEditMode.regular; + /** @type {enumLayer} */ + this.currentLayer = enumLayer.regular; this.signals = { // Entities entityManuallyPlaced: /** @type {TypedSignal<[Entity]>} */ (new Signal()), entityAdded: /** @type {TypedSignal<[Entity]>} */ (new Signal()), + entityChanged: /** @type {TypedSignal<[Entity]>} */ (new Signal()), entityGotNewComponent: /** @type {TypedSignal<[Entity]>} */ (new Signal()), entityComponentRemoved: /** @type {TypedSignal<[Entity]>} */ (new Signal()), entityQueuedForDestroy: /** @type {TypedSignal<[Entity]>} */ (new Signal()), @@ -165,7 +170,15 @@ export class GameRoot { bulkOperationFinished: /** @type {TypedSignal<[]>} */ (new Signal()), - editModeChanged: /** @type {TypedSignal<[enumEditMode]>} */ (new Signal()), + editModeChanged: /** @type {TypedSignal<[enumLayer]>} */ (new Signal()), + + // Called to check if an entity can be placed, second parameter is an additional offset. + // Use to introduce additional placement checks + prePlacementCheck: /** @type {TypedSignal<[Entity, Vector]>} */ (new Signal()), + + // Called before actually placing an entity, use to perform additional logic + // for freeing space before actually placing. + freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()), }; // RNG's diff --git a/src/js/game/shape_definition.js b/src/js/game/shape_definition.js index 8644e353..af2214e3 100644 --- a/src/js/game/shape_definition.js +++ b/src/js/game/shape_definition.js @@ -1,12 +1,17 @@ import { makeOffscreenBuffer } from "../core/buffer_utils"; -import { JSON_parse, JSON_stringify, Math_max, Math_PI, Math_radians } from "../core/builtins"; import { globalConfig } from "../core/config"; import { smoothenDpi } from "../core/dpi_manager"; import { DrawParameters } from "../core/draw_parameters"; import { createLogger } from "../core/logging"; import { Vector } from "../core/vector"; import { BasicSerializableObject, types } from "../savegame/serialization"; -import { enumColors, enumColorsToHexCode, enumColorToShortcode, enumShortcodeToColor } from "./colors"; +import { + enumColors, + enumColorsToHexCode, + enumColorToShortcode, + enumShortcodeToColor, + enumInvertedColors, +} from "./colors"; import { THEME } from "./theme"; const rusha = require("rusha"); @@ -235,7 +240,7 @@ export class ShapeDefinition extends BasicSerializableObject { * @returns {Array} */ internalCloneLayers() { - return JSON_parse(JSON_stringify(this.layers)); + return JSON.parse(JSON.stringify(this.layers)); } /** @@ -340,7 +345,7 @@ export class ShapeDefinition extends BasicSerializableObject { for (let layerIndex = 0; layerIndex < this.layers.length; ++layerIndex) { const quadrants = this.layers[layerIndex]; - const layerScale = Math_max(0.1, 0.9 - layerIndex * 0.22); + const layerScale = Math.max(0.1, 0.9 - layerIndex * 0.22); for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) { if (!quadrants[quadrantIndex]) { @@ -352,7 +357,7 @@ export class ShapeDefinition extends BasicSerializableObject { const centerQuadrantX = quadrantPos.x * quadrantHalfSize; const centerQuadrantY = quadrantPos.y * quadrantHalfSize; - const rotation = Math_radians(quadrantIndex * 90); + const rotation = Math.radians(quadrantIndex * 90); context.translate(centerQuadrantX, centerQuadrantY); context.rotate(rotation); @@ -414,7 +419,7 @@ export class ShapeDefinition extends BasicSerializableObject { insetPadding + -quadrantHalfSize, -insetPadding + quadrantHalfSize, quadrantSize * layerScale, - -Math_PI * 0.5, + -Math.PI * 0.5, 0 ); context.closePath(); @@ -567,6 +572,23 @@ export class ShapeDefinition extends BasicSerializableObject { return new ShapeDefinition({ layers: newLayers }); } + /** + * Clones the shape and inverts all colors + */ + cloneAndInvertColors() { + const newLayers = this.internalCloneLayers(); + for (let layerIndex = 0; layerIndex < newLayers.length; ++layerIndex) { + const quadrants = newLayers[layerIndex]; + for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) { + const item = quadrants[quadrantIndex]; + if (item) { + item.color = enumInvertedColors[item.color]; + } + } + } + return new ShapeDefinition({ layers: newLayers }); + } + /** * Clones the shape and colors everything in the given colors * @param {[enumColors, enumColors, enumColors, enumColors]} colors diff --git a/src/js/game/shape_definition_manager.js b/src/js/game/shape_definition_manager.js index ad682bf0..bebb4592 100644 --- a/src/js/game/shape_definition_manager.js +++ b/src/js/game/shape_definition_manager.js @@ -161,6 +161,22 @@ export class ShapeDefinitionManager extends BasicSerializableObject { )); } + /** + * Generates a definition for inverting all colors on that shape + * @param {ShapeDefinition} definition + * @returns {ShapeDefinition} + */ + shapeActionInvertColors(definition) { + const key = "invert:" + definition.getHash(); + if (this.operationCache[key]) { + return /** @type {ShapeDefinition} */ (this.operationCache[key]); + } + const inverted = definition.cloneAndInvertColors(); + return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle( + inverted + )); + } + /** * Generates a definition for painting it with the 4 colors * @param {ShapeDefinition} definition diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index 5e4ac7f0..db538a56 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -1,24 +1,29 @@ -import { Math_sqrt, Math_max } from "../../core/builtins"; import { globalConfig } from "../../core/config"; import { DrawParameters } from "../../core/draw_parameters"; import { gMetaBuildingRegistry } from "../../core/global_registries"; import { Loader } from "../../core/loader"; import { createLogger } from "../../core/logging"; -import { Rectangle } from "../../core/rectangle"; import { AtlasSprite } from "../../core/sprites"; +import { fastArrayDeleteValue } from "../../core/utils"; import { enumDirection, enumDirectionToVector, enumInvertedDirections, Vector } from "../../core/vector"; -import { MetaBeltBaseBuilding } from "../buildings/belt_base"; +import { BeltPath } from "../belt_path"; +import { arrayBeltVariantToRotation, MetaBeltBaseBuilding } from "../buildings/belt_base"; import { BeltComponent } from "../components/belt"; import { Entity } from "../entity"; import { GameSystemWithFilter } from "../game_system_with_filter"; import { MapChunkView } from "../map_chunk_view"; import { defaultBuildingVariant } from "../meta_building"; +import { enumLayer } from "../root"; +import { MetaWireBaseBuilding } from "../buildings/wire_base"; +import { enumItemType } from "../base_item"; export const BELT_ANIM_COUNT = 28; -const SQRT_2 = Math_sqrt(2); const logger = createLogger("belt"); +/** + * Manages all belts + */ export class BeltSystem extends GameSystemWithFilter { constructor(root) { super(root, [BeltComponent]); @@ -31,6 +36,15 @@ export class BeltSystem extends GameSystemWithFilter { [enumDirection.right]: Loader.getSprite("sprites/belt/right_0.png"), }; + /** + * @type {Object.>} + */ + this.wireSprites = { + [enumDirection.top]: Loader.getSprite("sprites/buildings/wire_top.png"), + [enumDirection.left]: Loader.getSprite("sprites/buildings/wire_left.png"), + [enumDirection.right]: Loader.getSprite("sprites/buildings/wire_right.png"), + }; + /** * @type {Object.>} */ @@ -50,12 +64,58 @@ export class BeltSystem extends GameSystemWithFilter { ); } - this.root.signals.entityAdded.add(this.updateSurroundingBeltPlacement, this); + this.root.signals.entityDestroyed.add(this.onEntityDestroyed, this); this.root.signals.entityDestroyed.add(this.updateSurroundingBeltPlacement, this); - this.root.signals.postLoadHook.add(this.computeBeltCache, this); - /** @type {Rectangle} */ - this.areaToRecompute = null; + // Notice: These must come *after* the entity destroyed signals + this.root.signals.entityAdded.add(this.onEntityAdded, this); + this.root.signals.entityAdded.add(this.updateSurroundingBeltPlacement, this); + + /** @type {Array} */ + this.beltPaths = []; + } + + /** + * Serializes all belt paths + * @returns {Array} + */ + serializePaths() { + let data = []; + for (let i = 0; i < this.beltPaths.length; ++i) { + data.push(this.beltPaths[i].serialize()); + } + return data; + } + + /** + * Deserializes all belt paths + * @param {Array} data + */ + deserializePaths(data) { + if (!Array.isArray(data)) { + return "Belt paths are not an array: " + typeof data; + } + + for (let i = 0; i < data.length; ++i) { + const path = BeltPath.fromSerialized(this.root, data[i]); + // If path is a string, that means its an error + if (!(path instanceof BeltPath)) { + return "Failed to create path from belt data: " + path; + } + this.beltPaths.push(path); + } + + if (this.beltPaths.length === 0) { + // Old savegames might not have paths yet + logger.warn("Recomputing belt paths (most likely the savegame is old or empty)"); + this.recomputeAllBeltPaths(); + } else { + logger.warn("Restored", this.beltPaths.length, "belt paths"); + } + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_verifyBeltPaths(); + } } /** @@ -72,64 +132,219 @@ export class BeltSystem extends GameSystemWithFilter { return; } - if (entity.components.Belt) { - this.cacheNeedsUpdate = true; - } - const metaBelt = gMetaBuildingRegistry.findByClass(MetaBeltBaseBuilding); - // Compute affected area const originalRect = staticComp.getTileSpaceBounds(); const affectedArea = originalRect.expandedInAllDirections(1); - // Store if anything got changed, if so we need to queue a recompute - let anythingChanged = false; - for (let x = affectedArea.x; x < affectedArea.right(); ++x) { for (let y = affectedArea.y; y < affectedArea.bottom(); ++y) { - if (!originalRect.containsPoint(x, y)) { - const targetEntity = this.root.map.getTileContentXY(x, y); - if (targetEntity) { - const targetBeltComp = targetEntity.components.Belt; - if (targetBeltComp) { - const targetStaticComp = targetEntity.components.StaticMapEntity; - const { - rotation, - rotationVariant, - } = metaBelt.computeOptimalDirectionAndRotationVariantAtTile( - this.root, - new Vector(x, y), - targetStaticComp.originalRotation, - defaultBuildingVariant - ); - targetStaticComp.rotation = rotation; - metaBelt.updateVariants(targetEntity, rotationVariant, defaultBuildingVariant); - anythingChanged = true; + if (originalRect.containsPoint(x, y)) { + // Make sure we don't update the original entity + continue; + } + + const targetEntities = this.root.map.getLayersContentsMultipleXY(x, y); + for (let i = 0; i < targetEntities.length; ++i) { + const targetEntity = targetEntities[i]; + + const targetBeltComp = targetEntity.components.Belt; + const targetStaticComp = targetEntity.components.StaticMapEntity; + + if (!targetBeltComp) { + // Not a belt + continue; + } + + const { + rotation, + rotationVariant, + } = metaBelt.computeOptimalDirectionAndRotationVariantAtTile({ + root: this.root, + tile: new Vector(x, y), + rotation: targetStaticComp.originalRotation, + variant: defaultBuildingVariant, + layer: targetEntity.layer, + }); + + // Compute delta to see if anything changed + const newDirection = arrayBeltVariantToRotation[rotationVariant]; + + if (targetStaticComp.rotation !== rotation || newDirection !== targetBeltComp.direction) { + // Ok, first remove it from its current path + this.deleteEntityFromPath(targetBeltComp.assignedPath, targetEntity); + + // Change stuff + targetStaticComp.rotation = rotation; + metaBelt.updateVariants(targetEntity, rotationVariant, defaultBuildingVariant); + + // Now add it again + this.addEntityToPaths(targetEntity); + + // Sanity + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_verifyBeltPaths(); } + + // Make sure the chunks know about the update + this.root.signals.entityChanged.dispatch(targetEntity); } } } } - if (anythingChanged) { - if (this.areaToRecompute) { - this.areaToRecompute = this.areaToRecompute.getUnion(affectedArea); - } else { - this.areaToRecompute = affectedArea.clone(); + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_verifyBeltPaths(); + } + } + + /** + * Called when an entity got destroyed + * @param {Entity} entity + */ + onEntityDestroyed(entity) { + if (!this.root.gameInitialized) { + return; + } + + if (!entity.components.Belt) { + return; + } + + const assignedPath = entity.components.Belt.assignedPath; + assert(assignedPath, "Entity has no belt path assigned"); + this.deleteEntityFromPath(assignedPath, entity); + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_verifyBeltPaths(); + } + } + + /** + * Attempts to delete the belt from its current path + * @param {BeltPath} path + * @param {Entity} entity + */ + deleteEntityFromPath(path, entity) { + if (path.entityPath.length === 1) { + // This is a single entity path, easy to do, simply erase whole path + fastArrayDeleteValue(this.beltPaths, path); + return; + } + + // Notice: Since there might be circular references, it is important to check + // which role the entity has + if (path.isStartEntity(entity)) { + // We tried to delete the start + path.deleteEntityOnStart(entity); + } else if (path.isEndEntity(entity)) { + // We tried to delete the end + path.deleteEntityOnEnd(entity); + } else { + // We tried to delete something inbetween + const newPath = path.deleteEntityOnPathSplitIntoTwo(entity); + this.beltPaths.push(newPath); + } + + // Sanity + entity.components.Belt.assignedPath = null; + } + + /** + * Adds the given entity to the appropriate paths + * @param {Entity} entity + */ + addEntityToPaths(entity) { + const fromEntity = this.findSupplyingEntity(entity); + const toEntity = this.findFollowUpEntity(entity); + + // Check if we can add the entity to the previous path + if (fromEntity) { + const fromPath = fromEntity.components.Belt.assignedPath; + fromPath.extendOnEnd(entity); + + // Check if we now can extend the current path by the next path + if (toEntity) { + const toPath = toEntity.components.Belt.assignedPath; + + if (fromPath === toPath) { + // This is a circular dependency -> Ignore + } else { + fromPath.extendByPath(toPath); + + // Delete now obsolete path + fastArrayDeleteValue(this.beltPaths, toPath); + } } - if (G_IS_DEV) { - logger.log("Queuing recompute:", this.areaToRecompute); + } else { + if (toEntity) { + // Prepend it to the other path + const toPath = toEntity.components.Belt.assignedPath; + toPath.extendOnBeginning(entity); + } else { + // This is an empty belt path + const path = new BeltPath(this.root, [entity]); + this.beltPaths.push(path); } } } - draw(parameters) { - this.forEachMatchingEntityOnScreen(parameters, this.drawEntityItems.bind(this)); + /** + * Called when an entity got added + * @param {Entity} entity + */ + onEntityAdded(entity) { + if (!this.root.gameInitialized) { + return; + } + + if (!entity.components.Belt) { + return; + } + + this.addEntityToPaths(entity); + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_verifyBeltPaths(); + } + } + + /** + * Draws all belt paths + * @param {DrawParameters} parameters + * @param {enumLayer} layer + */ + drawLayerBeltItems(parameters, layer) { + for (let i = 0; i < this.beltPaths.length; ++i) { + const path = this.beltPaths[i]; + if (path.layer === layer) { + path.draw(parameters); + } + } + } + + /** + * Verifies all belt paths + */ + debug_verifyBeltPaths() { + for (let i = 0; i < this.beltPaths.length; ++i) { + this.beltPaths[i].debug_checkIntegrity("general-verify"); + } + + const belts = this.root.entityMgr.getAllWithComponent(BeltComponent); + for (let i = 0; i < belts.length; ++i) { + const path = belts[i].components.Belt.assignedPath; + if (!path) { + throw new Error("Belt has no path: " + belts[i].uid); + } + if (this.beltPaths.indexOf(path) < 0) { + throw new Error("Path of entity not contained: " + belts[i].uid); + } + } } /** * Finds the follow up entity for a given belt. Used for building the dependencies * @param {Entity} entity + * @returns {Entity|null} */ findFollowUpEntity(entity) { const staticComp = entity.components.StaticMapEntity; @@ -139,7 +354,7 @@ export class BeltSystem extends GameSystemWithFilter { const followUpVector = enumDirectionToVector[followUpDirection]; const followUpTile = staticComp.origin.add(followUpVector); - const followUpEntity = this.root.map.getTileContent(followUpTile); + const followUpEntity = this.root.map.getLayerContentXY(followUpTile.x, followUpTile.y, entity.layer); // Check if theres a belt at the tile we point to if (followUpEntity) { @@ -152,6 +367,12 @@ export class BeltSystem extends GameSystemWithFilter { const acceptorSlots = followUpAcceptor.slots; for (let i = 0; i < acceptorSlots.length; ++i) { const slot = acceptorSlots[i]; + + // Make sure the acceptor slot is on the same layer + if (slot.layer !== entity.layer) { + continue; + } + for (let k = 0; k < slot.directions.length; ++k) { const localDirection = followUpStatic.localDirectionToWorld(slot.directions[k]); if (enumInvertedDirections[localDirection] === followUpDirection) { @@ -166,170 +387,120 @@ export class BeltSystem extends GameSystemWithFilter { } /** - * Recomputes the belt cache + * Finds the supplying belt for a given belt. Used for building the dependencies + * @param {Entity} entity + * @returns {Entity|null} */ - computeBeltCache() { - if (this.areaToRecompute) { - logger.log("Updating belt cache by updating area:", this.areaToRecompute); + findSupplyingEntity(entity) { + const staticComp = entity.components.StaticMapEntity; - if (G_IS_DEV && globalConfig.debug.renderChanges) { - this.root.hud.parts.changesDebugger.renderChange( - "belt-area", - this.areaToRecompute, - "#00fff6" - ); - } + const supplyDirection = staticComp.localDirectionToWorld(enumDirection.bottom); + const supplyVector = enumDirectionToVector[supplyDirection]; - for (let x = this.areaToRecompute.x; x < this.areaToRecompute.right(); ++x) { - for (let y = this.areaToRecompute.y; y < this.areaToRecompute.bottom(); ++y) { - const tile = this.root.map.getTileContentXY(x, y); - if (tile && tile.components.Belt) { - tile.components.Belt.followUpCache = this.findFollowUpEntity(tile); + const supplyTile = staticComp.origin.add(supplyVector); + const supplyEntity = this.root.map.getLayerContentXY(supplyTile.x, supplyTile.y, entity.layer); + + // Check if theres a belt at the tile we point to + if (supplyEntity) { + const supplyBeltComp = supplyEntity.components.Belt; + if (supplyBeltComp) { + const supplyStatic = supplyEntity.components.StaticMapEntity; + const supplyEjector = supplyEntity.components.ItemEjector; + + // Check if the belt accepts items from our direction + const ejectorSlots = supplyEjector.slots; + for (let i = 0; i < ejectorSlots.length; ++i) { + const slot = ejectorSlots[i]; + + // Make sure the ejector slot is on the same layer + if (slot.layer !== entity.layer) { + continue; + } + const localDirection = supplyStatic.localDirectionToWorld(slot.direction); + if (enumInvertedDirections[localDirection] === supplyDirection) { + return supplyEntity; } } } - - // Reset stale areas afterwards - this.areaToRecompute = null; - } else { - logger.log("Doing full belt recompute"); - - if (G_IS_DEV && globalConfig.debug.renderChanges) { - this.root.hud.parts.changesDebugger.renderChange( - "", - new Rectangle(-1000, -1000, 2000, 2000), - "#00fff6" - ); - } - - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; - entity.components.Belt.followUpCache = this.findFollowUpEntity(entity); - } } + + return null; } - update() { - if (this.areaToRecompute) { - this.computeBeltCache(); - } + /** + * Recomputes the belt path network. Only required for old savegames + */ + recomputeAllBeltPaths() { + logger.warn("Recomputing all belt paths"); + const visitedUids = new Set(); - // Divide by item spacing on belts since we use throughput and not speed - let beltSpeed = - this.root.hubGoals.getBeltBaseSpeed() * - this.root.dynamicTickrate.deltaSeconds * - globalConfig.itemSpacingOnBelts; - - if (G_IS_DEV && globalConfig.debug.instantBelts) { - beltSpeed *= 100; - } + const result = []; for (let i = 0; i < this.allEntities.length; ++i) { const entity = this.allEntities[i]; - - const beltComp = entity.components.Belt; - const items = beltComp.sortedItems; - - if (items.length === 0) { - // Fast out for performance + if (visitedUids.has(entity.uid)) { continue; } - const ejectorComp = entity.components.ItemEjector; - let maxProgress = 1; + // Mark entity as visited + visitedUids.add(entity.uid); - /* PERFORMANCE OPTIMIZATION */ - // Original: - // const isCurrentlyEjecting = ejectorComp.isAnySlotEjecting(); - // Replaced (Since belts always have just one slot): - const ejectorSlot = ejectorComp.slots[0]; - const isCurrentlyEjecting = ejectorSlot.item; + // Compute path, start with entity and find precedors / successors + const path = [entity]; - // When ejecting, we can not go further than the item spacing since it - // will be on the corner - if (isCurrentlyEjecting) { - maxProgress = 1 - globalConfig.itemSpacingOnBelts; - } else { - // Otherwise our progress depends on the follow up - if (beltComp.followUpCache) { - const spacingOnBelt = beltComp.followUpCache.components.Belt.getDistanceToFirstItemCenter(); - maxProgress = Math.min(2, 1 - globalConfig.itemSpacingOnBelts + spacingOnBelt); + // Prevent infinite loops + let maxIter = 99999; - // Useful check, but hurts performance - // assert(maxProgress >= 0.0, "max progress < 0 (I) (" + maxProgress + ")"); + // Find precedors + let prevEntity = this.findSupplyingEntity(entity); + while (prevEntity && --maxIter > 0) { + if (visitedUids.has(prevEntity.uid)) { + break; } + path.unshift(prevEntity); + visitedUids.add(prevEntity.uid); + prevEntity = this.findSupplyingEntity(prevEntity); } - let speedMultiplier = 1; - if (beltComp.direction !== enumDirection.top) { - // Curved belts are shorter, thus being quicker (Looks weird otherwise) - speedMultiplier = SQRT_2; - } - - // How much offset we add when transferring to a new belt - // This substracts one tick because the belt will be updated directly - // afterwards anyways - const takeoverOffset = 1.0 + beltSpeed * speedMultiplier; - - // Not really nice. haven't found the reason for this yet. - if (items.length > 2 / globalConfig.itemSpacingOnBelts) { - beltComp.sortedItems = []; - } - - for (let itemIndex = items.length - 1; itemIndex >= 0; --itemIndex) { - const progressAndItem = items[itemIndex]; - - progressAndItem[0] = Math.min(maxProgress, progressAndItem[0] + speedMultiplier * beltSpeed); - assert(progressAndItem[0] >= 0, "Bad progress: " + progressAndItem[0]); - - if (progressAndItem[0] >= 1.0) { - if (beltComp.followUpCache) { - const followUpBelt = beltComp.followUpCache.components.Belt; - if (followUpBelt.canAcceptItem()) { - followUpBelt.takeItem( - progressAndItem[1], - Math_max(0, progressAndItem[0] - takeoverOffset) - ); - items.splice(itemIndex, 1); - } else { - // Well, we couldn't really take it to a follow up belt, keep it at - // max progress - progressAndItem[0] = 1.0; - maxProgress = 1 - globalConfig.itemSpacingOnBelts; - } - } else { - // Try to give this item to a new belt - - /* PERFORMANCE OPTIMIZATION */ - - // Original: - // const freeSlot = ejectorComp.getFirstFreeSlot(); - - // Replaced - if (ejectorSlot.item) { - // So, we don't have a free slot - damned! - progressAndItem[0] = 1.0; - maxProgress = 1 - globalConfig.itemSpacingOnBelts; - } else { - // We got a free slot, remove this item and keep it on the ejector slot - if (!ejectorComp.tryEject(0, progressAndItem[1])) { - assert(false, "Ejection failed"); - } - items.splice(itemIndex, 1); - - // NOTICE: Do not override max progress here at all, this leads to issues - } - } - } else { - // We just moved this item forward, so determine the maximum progress of other items - maxProgress = Math.max(0, progressAndItem[0] - globalConfig.itemSpacingOnBelts); + // Find succedors + let nextEntity = this.findFollowUpEntity(entity); + while (nextEntity && --maxIter > 0) { + if (visitedUids.has(nextEntity.uid)) { + break; } + + path.push(nextEntity); + visitedUids.add(nextEntity.uid); + nextEntity = this.findFollowUpEntity(nextEntity); } + + assert(maxIter > 1, "Ran out of iterations"); + result.push(new BeltPath(this.root, path)); + } + + logger.log("Found", this.beltPaths.length, "belt paths"); + this.beltPaths = result; + } + + /** + * Updates all belts + */ + update() { + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_verifyBeltPaths(); + } + + for (let i = 0; i < this.beltPaths.length; ++i) { + this.beltPaths[i].update(); + } + + if (G_IS_DEV && globalConfig.debug.checkBeltPaths) { + this.debug_verifyBeltPaths(); } } /** - * + * Draws a given chunk * @param {DrawParameters} parameters * @param {MapChunkView} chunk */ @@ -338,13 +509,14 @@ export class BeltSystem extends GameSystemWithFilter { return; } - const speedMultiplier = this.root.hubGoals.getBeltBaseSpeed(); + // Limit speed to avoid belts going backwards + const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(enumLayer.regular), 10); // SYNC with systems/item_acceptor.js:drawEntityUnderlays! // 126 / 42 is the exact animation speed of the png animation const animationIndex = Math.floor( - ((this.root.time.now() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * - globalConfig.itemSpacingOnBelts + ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * + globalConfig.beltItemSpacingByLayer[enumLayer.regular] ); const contents = chunk.contents; for (let y = 0; y < globalConfig.mapChunkSize; ++y) { @@ -368,38 +540,41 @@ export class BeltSystem extends GameSystemWithFilter { } /** + * Draws a given chunk * @param {DrawParameters} parameters - * @param {Entity} entity + * @param {MapChunkView} chunk */ - drawEntityItems(parameters, entity) { - const beltComp = entity.components.Belt; - const staticComp = entity.components.StaticMapEntity; - - const items = beltComp.sortedItems; - - if (items.length === 0) { - // Fast out for performance + drawWiresChunk(parameters, chunk) { + if (parameters.zoomLevel < globalConfig.mapChunkOverviewMinZoom) { return; } - if (!staticComp.shouldBeDrawn(parameters)) { - return; + const contents = chunk.wireContents; + for (let y = 0; y < globalConfig.mapChunkSize; ++y) { + for (let x = 0; x < globalConfig.mapChunkSize; ++x) { + const entity = contents[x][y]; + + if (entity && entity.components.Belt) { + const direction = entity.components.Belt.direction; + const sprite = this.wireSprites[direction]; + entity.components.StaticMapEntity.drawSpriteOnFullEntityBounds( + parameters, + sprite, + 0, + false + ); + } + } } + } - for (let i = 0; i < items.length; ++i) { - const itemAndProgress = items[i]; - - // Nice would be const [pos, item] = itemAndPos; but that gets polyfilled and is super slow then - const progress = itemAndProgress[0]; - const item = itemAndProgress[1]; - - const position = staticComp.applyRotationToVector(beltComp.transformBeltToLocalSpace(progress)); - - item.draw( - (staticComp.origin.x + position.x + 0.5) * globalConfig.tileSize, - (staticComp.origin.y + position.y + 0.5) * globalConfig.tileSize, - parameters - ); + /** + * Draws the belt path debug overlays + * @param {DrawParameters} parameters + */ + drawBeltPathDebug(parameters) { + for (let i = 0; i < this.beltPaths.length; ++i) { + this.beltPaths[i].drawDebug(parameters); } } } diff --git a/src/js/game/systems/energy_consumer.js b/src/js/game/systems/energy_consumer.js new file mode 100644 index 00000000..6552fb9a --- /dev/null +++ b/src/js/game/systems/energy_consumer.js @@ -0,0 +1,90 @@ +import { DrawParameters } from "../../core/draw_parameters"; +import { Loader } from "../../core/loader"; +import { clamp } from "../../core/utils"; +import { enumItemType } from "../base_item"; +import { EnergyConsumerComponent } from "../components/energy_consumer"; +import { Entity } from "../entity"; +import { GameSystemWithFilter } from "../game_system_with_filter"; +import { NEGATIVE_ENERGY_ITEM_SINGLETON } from "../items/negative_energy_item"; +import { POSITIVE_ENERGY_ITEM_SINGLETON } from "../items/positive_energy_item"; + +export class EnergyConsumerSystem extends GameSystemWithFilter { + constructor(root) { + super(root, [EnergyConsumerComponent]); + + this.batterySprites = [ + Loader.getSprite("sprites/wires/battery_empty.png"), + Loader.getSprite("sprites/wires/battery_low.png"), + Loader.getSprite("sprites/wires/battery_medium.png"), + Loader.getSprite("sprites/wires/battery_full.png"), + ]; + + this.piledWasteSprite = Loader.getSprite("sprites/wires/waste_piled.png"); + } + + update() { + for (let i = 0; i < this.allEntities.length; ++i) { + const entity = this.allEntities[i]; + const energyConsumerComp = entity.components.EnergyConsumer; + + if (energyConsumerComp.piledOutput >= 1.0) { + // Try to get rid of waste + + const ejectorComp = entity.components.ItemEjector; + const item = this.getItemSingletonByType(energyConsumerComp.wasteType); + if (ejectorComp.tryEject(energyConsumerComp.ejectorSlotIndex, item)) { + // Got rid of waste + energyConsumerComp.reduceWaste(1.0); + } + } + } + } + + /** + * + * @param {enumItemType} itemType + */ + getItemSingletonByType(itemType) { + switch (itemType) { + case enumItemType.positiveEnergy: + return POSITIVE_ENERGY_ITEM_SINGLETON; + case enumItemType.negativeEnergy: + return NEGATIVE_ENERGY_ITEM_SINGLETON; + default: + assertAlways(false, "Bad item type: " + itemType); + } + } + + /** + * Draws everything + * @param {DrawParameters} parameters + */ + draw(parameters) { + this.forEachMatchingEntityOnScreen(parameters, this.drawSingleEntity.bind(this)); + } + + /** + * Draws a given entity + * @param {DrawParameters} parameters + * @param {Entity} entity + */ + drawSingleEntity(parameters, entity) { + const staticComp = entity.components.StaticMapEntity; + const consumerComp = entity.components.EnergyConsumer; + + const position = staticComp.localTileToWorld(consumerComp.batteryPosition).toWorldSpaceCenterOfTile(); + + if (consumerComp.hasTooMuchWastePiled()) { + this.piledWasteSprite.drawCachedCentered(parameters, position.x, position.y, 12); + } else { + const percentage = consumerComp.stored / consumerComp.bufferSize; + const index = clamp( + Math.round(percentage * this.batterySprites.length), + 0, + this.batterySprites.length - 1 + ); + + this.batterySprites[index].drawCachedCentered(parameters, position.x, position.y, 12); + } + } +} diff --git a/src/js/game/systems/energy_generator.js b/src/js/game/systems/energy_generator.js index 733ea90a..76e14c01 100644 --- a/src/js/game/systems/energy_generator.js +++ b/src/js/game/systems/energy_generator.js @@ -1,13 +1,19 @@ import { DrawParameters } from "../../core/draw_parameters"; +import { formatBigNumber } from "../../core/utils"; import { T } from "../../translations"; import { EnergyGeneratorComponent } from "../components/energy_generator"; import { Entity } from "../entity"; import { GameSystemWithFilter } from "../game_system_with_filter"; +import { POSITIVE_ENERGY_ITEM_SINGLETON } from "../items/positive_energy_item"; import { ShapeDefinition } from "../shape_definition"; +import { Loader } from "../../core/loader"; +import { globalConfig } from "../../core/config"; export class EnergyGeneratorSystem extends GameSystemWithFilter { constructor(root) { super(root, [EnergyGeneratorComponent]); + + this.energyGeneratorOverlay = Loader.getSprite("sprites/misc/energy_generator_overlay.png"); } draw(parameters) { @@ -26,11 +32,19 @@ export class EnergyGeneratorSystem extends GameSystemWithFilter { for (let i = 0; i < this.allEntities.length; ++i) { const entity = this.allEntities[i]; const energyGenComp = entity.components.EnergyGenerator; + const ejectorComp = entity.components.ItemEjector; if (!energyGenComp.requiredKey) { // Compute required key for this generator energyGenComp.requiredKey = this.getShapeRequiredForGenerator(entity); } + + if (energyGenComp.itemsInQueue > 0) { + // FIXME: Find slot dynamically + if (ejectorComp.tryEject(0, POSITIVE_ENERGY_ITEM_SINGLETON)) { + energyGenComp.itemsInQueue -= 1; + } + } } } @@ -54,23 +68,30 @@ export class EnergyGeneratorSystem extends GameSystemWithFilter { const pos = staticComp.getTileSpaceBounds().getCenter().toWorldSpace(); - // TESTING const definition = ShapeDefinition.fromShortKey(energyGenComp.requiredKey); definition.draw(pos.x, pos.y, parameters, 30); + // Draw background + this.energyGeneratorOverlay.drawCachedCentered( + parameters, + pos.x, + pos.y, + globalConfig.tileSize * 2 + 8 + ); + + // TODO const energyGenerated = 5; // deliver: Deliver // toGenerateEnergy: For energy - context.font = "bold 7px GameFont"; + context.font = "bold 9px GameFont"; context.fillStyle = "#64666e"; context.textAlign = "left"; context.fillText(T.buildings.energy_generator.deliver.toUpperCase(), pos.x - 25, pos.y - 18); + context.fillText(T.buildings.energy_generator.toGenerateEnergy.toUpperCase(), pos.x - 25, pos.y + 27); - context.fillText( - T.buildings.energy_generator.toGenerateEnergy.replace("", "" + energyGenerated).toUpperCase(), - pos.x - 25, - pos.y + 28 - ); + context.font = "700 9px GameFont"; + context.fillStyle = "#dee1ea"; + context.fillText("" + formatBigNumber(energyGenerated), pos.x + 1, pos.y + 27); } } diff --git a/src/js/game/systems/item_acceptor.js b/src/js/game/systems/item_acceptor.js index f583f116..2c0f1686 100644 --- a/src/js/game/systems/item_acceptor.js +++ b/src/js/game/systems/item_acceptor.js @@ -6,8 +6,9 @@ import { enumDirectionToVector, enumDirectionToAngle } from "../../core/vector"; import { ItemAcceptorComponent } from "../components/item_acceptor"; import { Loader } from "../../core/loader"; import { drawRotatedSprite } from "../../core/draw_utils"; -import { Math_radians } from "../../core/builtins"; import { BELT_ANIM_COUNT } from "./belt"; +import { fastArrayDelete } from "../../core/utils"; +import { enumLayer } from "../root"; export class ItemAcceptorSystem extends GameSystemWithFilter { constructor(root) { @@ -21,39 +22,58 @@ export class ItemAcceptorSystem extends GameSystemWithFilter { } update() { + const progress = this.root.dynamicTickrate.deltaSeconds * 2; // * 2 because its only a half tile + for (let i = 0; i < this.allEntities.length; ++i) { const entity = this.allEntities[i]; const aceptorComp = entity.components.ItemAcceptor; + const animations = aceptorComp.itemConsumptionAnimations; // Process item consumption animations to avoid items popping from the belts - for (let animIndex = 0; animIndex < aceptorComp.itemConsumptionAnimations.length; ++animIndex) { - const anim = aceptorComp.itemConsumptionAnimations[animIndex]; + for (let animIndex = 0; animIndex < animations.length; ++animIndex) { + const anim = animations[animIndex]; + const layer = aceptorComp.slots[anim.slotIndex].layer; anim.animProgress += - this.root.dynamicTickrate.deltaSeconds * - this.root.hubGoals.getBeltBaseSpeed() * - 2 * - globalConfig.itemSpacingOnBelts; + progress * + this.root.hubGoals.getBeltBaseSpeed(layer) * + globalConfig.beltItemSpacingByLayer[layer]; if (anim.animProgress > 1) { - aceptorComp.itemConsumptionAnimations.splice(animIndex, 1); + // Original + // animations.splice(animIndex, 1); + + // Faster variant + fastArrayDelete(animations, animIndex); + animIndex -= 1; } } } } - draw(parameters) { - this.forEachMatchingEntityOnScreen(parameters, this.drawEntity.bind(this)); - } - - drawUnderlays(parameters) { - this.forEachMatchingEntityOnScreen(parameters, this.drawEntityUnderlays.bind(this)); + /** + * Draws the acceptor items + * @param {DrawParameters} parameters + * @param {enumLayer} layer + */ + drawLayer(parameters, layer) { + this.forEachMatchingEntityOnScreen(parameters, this.drawEntityRegularLayer.bind(this, layer)); } /** + * Draws the acceptor underlays + * @param {DrawParameters} parameters + * @param {enumLayer} layer + */ + drawUnderlays(parameters, layer) { + this.forEachMatchingEntityOnScreen(parameters, this.drawEntityUnderlays.bind(this, layer)); + } + + /** + * @param {enumLayer} layer * @param {DrawParameters} parameters * @param {Entity} entity */ - drawEntity(parameters, entity) { + drawEntityRegularLayer(layer, parameters, entity) { const staticComp = entity.components.StaticMapEntity; const acceptorComp = entity.components.ItemAcceptor; @@ -67,8 +87,12 @@ export class ItemAcceptorSystem extends GameSystemWithFilter { ]; const slotData = acceptorComp.slots[slotIndex]; - const slotWorldPos = staticComp.applyRotationToVector(slotData.pos).add(staticComp.origin); + if (slotData.layer !== layer) { + // Don't draw non-regular slots for now + continue; + } + const slotWorldPos = staticComp.applyRotationToVector(slotData.pos).add(staticComp.origin); const fadeOutDirection = enumDirectionToVector[staticComp.localDirectionToWorld(direction)]; const finalTile = slotWorldPos.subScalars( fadeOutDirection.x * (animProgress / 2 - 0.5), @@ -83,10 +107,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter { } /** + * @param {enumLayer} layer * @param {DrawParameters} parameters * @param {Entity} entity */ - drawEntityUnderlays(parameters, entity) { + drawEntityUnderlays(layer, parameters, entity) { const staticComp = entity.components.StaticMapEntity; const acceptorComp = entity.components.ItemAcceptor; @@ -94,21 +119,24 @@ export class ItemAcceptorSystem extends GameSystemWithFilter { return; } + // Limit speed to avoid belts going backwards + const speedMultiplier = Math.min(this.root.hubGoals.getBeltBaseSpeed(layer), 10); + const underlays = acceptorComp.beltUnderlays; for (let i = 0; i < underlays.length; ++i) { - const { pos, direction } = underlays[i]; + const { pos, direction, layer: underlayLayer } = underlays[i]; + if (underlayLayer !== layer) { + // Not our layer + continue; + } const transformedPos = staticComp.localTileToWorld(pos); const angle = enumDirectionToAngle[staticComp.localDirectionToWorld(direction)]; // SYNC with systems/belt.js:drawSingleEntity! const animationIndex = Math.floor( - ((this.root.time.now() * - this.root.hubGoals.getBeltBaseSpeed() * - this.underlayBeltSprites.length * - 126) / - 42) * - globalConfig.itemSpacingOnBelts + ((this.root.time.realtimeNow() * speedMultiplier * BELT_ANIM_COUNT * 126) / 42) * + globalConfig.beltItemSpacingByLayer[layer] ); drawRotatedSprite({ @@ -116,7 +144,7 @@ export class ItemAcceptorSystem extends GameSystemWithFilter { sprite: this.underlayBeltSprites[animationIndex % this.underlayBeltSprites.length], x: (transformedPos.x + 0.5) * globalConfig.tileSize, y: (transformedPos.y + 0.5) * globalConfig.tileSize, - angle: Math_radians(angle), + angle: Math.radians(angle), size: globalConfig.tileSize, }); } diff --git a/src/js/game/systems/item_ejector.js b/src/js/game/systems/item_ejector.js index d6597ecd..316dc053 100644 --- a/src/js/game/systems/item_ejector.js +++ b/src/js/game/systems/item_ejector.js @@ -1,13 +1,13 @@ -import { Math_min } from "../../core/builtins"; import { globalConfig } from "../../core/config"; import { DrawParameters } from "../../core/draw_parameters"; import { createLogger } from "../../core/logging"; import { Rectangle } from "../../core/rectangle"; import { enumDirectionToVector, Vector } from "../../core/vector"; -import { BaseItem } from "../base_item"; +import { BaseItem, enumItemType, enumItemTypeToLayer } from "../base_item"; import { ItemEjectorComponent } from "../components/item_ejector"; import { Entity } from "../entity"; import { GameSystemWithFilter } from "../game_system_with_filter"; +import { enumLayer } from "../root"; const logger = createLogger("systems/ejector"); @@ -63,7 +63,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter { "#fe50a6" ); } - this.recomputeAreaCache(this.areaToRecompute); + this.recomputeAreaCache(); this.areaToRecompute = null; } else { logger.log("Full cache recompute"); @@ -84,10 +84,10 @@ export class ItemEjectorSystem extends GameSystemWithFilter { } /** - * - * @param {Rectangle} area + * Recomputes the cache in the given area */ - recomputeAreaCache(area) { + recomputeAreaCache() { + const area = this.areaToRecompute; let entryCount = 0; logger.log("Recomputing area:", area.x, area.y, "/", area.w, area.h); @@ -97,8 +97,10 @@ export class ItemEjectorSystem extends GameSystemWithFilter { for (let x = area.x; x < area.right(); ++x) { for (let y = area.y; y < area.bottom(); ++y) { - const entity = this.root.map.getTileContentXY(x, y); - if (entity) { + const entities = this.root.map.getLayersContentsMultipleXY(x, y); + for (let i = 0; i < entities.length; ++i) { + const entity = entities[i]; + // Recompute the entity in case its relevant for this system and it // hasn't already been computed if (!recomputedEntities.has(entity.uid) && entity.components.ItemEjector) { @@ -135,37 +137,45 @@ export class ItemEjectorSystem extends GameSystemWithFilter { const ejectSlotTargetWsTile = ejectSlotWsTile.add(ejectSlotWsDirectionVector); // Try to find the given acceptor component to take the item - const targetEntity = this.root.map.getTileContent(ejectSlotTargetWsTile); - if (!targetEntity) { - // No consumer for item - continue; - } - - const targetAcceptorComp = targetEntity.components.ItemAcceptor; - const targetStaticComp = targetEntity.components.StaticMapEntity; - if (!targetAcceptorComp) { - // Entity doesn't accept items - continue; - } - - const matchingSlot = targetAcceptorComp.findMatchingSlot( - targetStaticComp.worldToLocalTile(ejectSlotTargetWsTile), - targetStaticComp.worldDirectionToLocal(ejectSlotWsDirection) + // Since there can be cross layer dependencies, check on all layers + const targetEntities = this.root.map.getLayersContentsMultipleXY( + ejectSlotTargetWsTile.x, + ejectSlotTargetWsTile.y ); - if (!matchingSlot) { - // No matching slot found - continue; - } + for (let i = 0; i < targetEntities.length; ++i) { + const targetEntity = targetEntities[i]; - // Ok we found a connection - if (ejectorComp.cachedConnectedSlots) { - ejectorComp.cachedConnectedSlots.push(ejectorSlot); - } else { - ejectorComp.cachedConnectedSlots = [ejectorSlot]; + const targetAcceptorComp = targetEntity.components.ItemAcceptor; + const targetStaticComp = targetEntity.components.StaticMapEntity; + if (!targetAcceptorComp) { + // Entity doesn't accept items + continue; + } + + const matchingSlot = targetAcceptorComp.findMatchingSlot( + targetStaticComp.worldToLocalTile(ejectSlotTargetWsTile), + targetStaticComp.worldDirectionToLocal(ejectSlotWsDirection), + ejectorSlot.layer + ); + + if (!matchingSlot) { + // No matching slot found + continue; + } + + // Ok we found a connection + if (ejectorComp.cachedConnectedSlots) { + ejectorComp.cachedConnectedSlots.push(ejectorSlot); + } else { + ejectorComp.cachedConnectedSlots = [ejectorSlot]; + } + + // A slot can always be connected to one other slot only + ejectorSlot.cachedTargetEntity = targetEntity; + ejectorSlot.cachedDestSlot = matchingSlot; + break; } - ejectorSlot.cachedTargetEntity = targetEntity; - ejectorSlot.cachedDestSlot = matchingSlot; } } @@ -175,8 +185,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter { } // Precompute effective belt speed - const effectiveBeltSpeed = this.root.hubGoals.getBeltBaseSpeed() * globalConfig.itemSpacingOnBelts; - let progressGrowth = (effectiveBeltSpeed / 0.5) * this.root.dynamicTickrate.deltaSeconds; + let progressGrowth = 2 * this.root.dynamicTickrate.deltaSeconds; if (G_IS_DEV && globalConfig.debug.instantBelts) { progressGrowth = 1; @@ -186,23 +195,34 @@ export class ItemEjectorSystem extends GameSystemWithFilter { for (let i = 0; i < this.allEntities.length; ++i) { const sourceEntity = this.allEntities[i]; const sourceEjectorComp = sourceEntity.components.ItemEjector; + if (!sourceEjectorComp.enabled) { + continue; + } + if (!sourceEjectorComp.cachedConnectedSlots) { continue; } - for (let j = 0; j < sourceEjectorComp.cachedConnectedSlots.length; j++) { - const sourceSlot = sourceEjectorComp.cachedConnectedSlots[j]; - const destSlot = sourceSlot.cachedDestSlot; - const targetEntity = sourceSlot.cachedTargetEntity; + const slots = sourceEjectorComp.cachedConnectedSlots; + for (let j = 0; j < slots.length; ++j) { + const sourceSlot = slots[j]; const item = sourceSlot.item; - if (!item) { // No item available to be ejected continue; } + const destSlot = sourceSlot.cachedDestSlot; + const targetEntity = sourceSlot.cachedTargetEntity; + // Advance items on the slot - sourceSlot.progress = Math_min(1, sourceSlot.progress + progressGrowth); + sourceSlot.progress = Math.min( + 1, + sourceSlot.progress + + progressGrowth * + this.root.hubGoals.getBeltBaseSpeed(sourceSlot.layer) * + globalConfig.beltItemSpacingByLayer[sourceSlot.layer] + ); // Check if we are still in the process of ejecting, can't proceed then if (sourceSlot.progress < 1.0) { @@ -237,29 +257,39 @@ export class ItemEjectorSystem extends GameSystemWithFilter { // TODO: Kinda hacky. How to solve this properly? Don't want to go through inheritance hell. // Also its just a few cases (hope it stays like this .. :x). + const itemLayer = enumItemTypeToLayer[item.getItemType()]; + const beltComp = receiver.components.Belt; if (beltComp) { - // Ayy, its a belt! - if (beltComp.canAcceptItem()) { - beltComp.takeItem(item); + const path = beltComp.assignedPath; + assert(path, "belt has no path"); + if (path.tryAcceptItem(item)) { return true; } + // Belt can have nothing else + return false; } - const storageComp = receiver.components.Storage; - if (storageComp) { - // It's a storage - if (storageComp.canAcceptItem(item)) { - storageComp.takeItem(item); + const energyConsumerComp = receiver.components.EnergyConsumer; + if (energyConsumerComp) { + if (energyConsumerComp.tryAcceptItem(item, slotIndex)) { + // All good return true; } + + // Energy consumer can have more components } const itemProcessorComp = receiver.components.ItemProcessor; if (itemProcessorComp) { - // Its an item processor .. - if (itemProcessorComp.tryTakeItem(item, slotIndex)) { - return true; + // Make sure its the same layer + if (itemLayer === receiver.layer) { + // Its an item processor .. + if (itemProcessorComp.tryTakeItem(item, slotIndex)) { + return true; + } + // Item processor can have nothing else + return false; } } @@ -274,28 +304,52 @@ export class ItemEjectorSystem extends GameSystemWithFilter { ) { return true; } + + // Underground belt can have nothing else + return false; + } + + const storageComp = receiver.components.Storage; + if (storageComp) { + // It's a storage + if (storageComp.canAcceptItem(item)) { + storageComp.takeItem(item); + return true; + } + + // Storage can't have anything else + return false; } const energyGeneratorComp = receiver.components.EnergyGenerator; if (energyGeneratorComp) { - if (energyGeneratorComp.tryTakeItem(item)) { + if (energyGeneratorComp.tryTakeItem(item, slotIndex)) { // Passed it over return true; } + + // Energy generator comp can't have anything else + return false; } return false; } - draw(parameters) { - this.forEachMatchingEntityOnScreen(parameters, this.drawSingleEntity.bind(this)); + /** + * Draws the given layer + * @param {DrawParameters} parameters + * @param {enumLayer} layer + */ + drawLayer(parameters, layer) { + this.forEachMatchingEntityOnScreen(parameters, this.drawSingleEntity.bind(this, layer)); } /** + * @param {enumLayer} layer * @param {DrawParameters} parameters * @param {Entity} entity */ - drawSingleEntity(parameters, entity) { + drawSingleEntity(layer, parameters, entity) { const ejectorComp = entity.components.ItemEjector; const staticComp = entity.components.StaticMapEntity; @@ -306,11 +360,17 @@ export class ItemEjectorSystem extends GameSystemWithFilter { for (let i = 0; i < ejectorComp.slots.length; ++i) { const slot = ejectorComp.slots[i]; const ejectedItem = slot.item; + if (!ejectedItem) { // No item continue; } + if (slot.layer !== layer) { + // Not our layer + continue; + } + const realPosition = slot.pos.rotateFastMultipleOf90(staticComp.rotation); const realDirection = Vector.transformDirectionFromMultipleOf90( slot.direction, diff --git a/src/js/game/systems/item_processor.js b/src/js/game/systems/item_processor.js index ae7a4568..8713f599 100644 --- a/src/js/game/systems/item_processor.js +++ b/src/js/game/systems/item_processor.js @@ -1,7 +1,6 @@ -import { Math_max } from "../../core/builtins"; import { globalConfig } from "../../core/config"; -import { BaseItem } from "../base_item"; -import { enumColorMixingResults } from "../colors"; +import { BaseItem, enumItemType } from "../base_item"; +import { enumColorMixingResults, enumInvertedColors } from "../colors"; import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor"; import { Entity } from "../entity"; import { GameSystemWithFilter } from "../game_system_with_filter"; @@ -21,7 +20,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { const ejectorComp = entity.components.ItemEjector; // First of all, process the current recipe - processorComp.secondsUntilEject = Math_max( + processorComp.secondsUntilEject = Math.max( 0, processorComp.secondsUntilEject - this.root.dynamicTickrate.deltaSeconds ); @@ -49,11 +48,11 @@ export class ItemProcessorSystem extends GameSystemWithFilter { if (ejectorComp.canEjectOnSlot(preferredSlot)) { slot = preferredSlot; } else { - slot = ejectorComp.getFirstFreeSlot(); + slot = ejectorComp.getFirstFreeSlot(entity.layer); } } else { // We can eject on any slot - slot = ejectorComp.getFirstFreeSlot(); + slot = ejectorComp.getFirstFreeSlot(entity.layer); } if (slot !== null) { @@ -71,7 +70,16 @@ export class ItemProcessorSystem extends GameSystemWithFilter { // Check if we have an empty queue and can start a new charge if (processorComp.itemsToEject.length === 0) { if (processorComp.inputSlots.length >= processorComp.inputsPerCharge) { - this.startNewCharge(entity); + const energyConsumerComp = entity.components.EnergyConsumer; + if (energyConsumerComp) { + // Check if we have enough energy + if (energyConsumerComp.tryStartNextCharge()) { + this.startNewCharge(entity); + } + } else { + // No further checks required + this.startNewCharge(entity); + } } } } @@ -107,6 +115,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter { switch (processorComp.type) { // SPLITTER + case enumItemProcessorTypes.splitterWires: case enumItemProcessorTypes.splitter: { trackProduction = false; const availableSlots = entity.components.ItemEjector.slots.length; @@ -332,6 +341,35 @@ export class ItemProcessorSystem extends GameSystemWithFilter { break; } + // ADVANCED PROCESSING + + case enumItemProcessorTypes.advancedProcessor: { + const item = items[0].item; + + if (item.getItemType() === enumItemType.color) { + const colorItem = /** @type {ColorItem} */ (items[0].item); + const newColor = enumInvertedColors[colorItem.color]; + outItems.push({ + item: new ColorItem(newColor), + requiredSlot: 0, + }); + } else if (item.getItemType() === enumItemType.shape) { + const shapeItem = /** @type {ShapeItem} */ (items[0].item); + const newItem = this.root.shapeDefinitionMgr.shapeActionInvertColors( + shapeItem.definition + ); + + outItems.push({ + item: new ShapeItem(newItem), + requiredSlot: 0, + }); + } else { + assertAlways(false, "Bad item type: " + item.getItemType() + " for advanced processor."); + } + + break; + } + default: assertAlways(false, "Unkown item processor type: " + processorComp.type); } diff --git a/src/js/game/systems/miner.js b/src/js/game/systems/miner.js index b195e6ab..f317d0d1 100644 --- a/src/js/game/systems/miner.js +++ b/src/js/game/systems/miner.js @@ -6,6 +6,7 @@ import { MinerComponent } from "../components/miner"; import { Entity } from "../entity"; import { GameSystemWithFilter } from "../game_system_with_filter"; import { MapChunkView } from "../map_chunk_view"; +import { enumLayer } from "../root"; export class MinerSystem extends GameSystemWithFilter { constructor(root) { @@ -74,7 +75,7 @@ export class MinerSystem extends GameSystemWithFilter { const ejectingDirection = staticComp.localDirectionToWorld(ejectingSlot.direction); const targetTile = ejectingPos.add(enumDirectionToVector[ejectingDirection]); - const targetContents = this.root.map.getTileContent(targetTile); + const targetContents = this.root.map.getTileContent(targetTile, enumLayer.regular); // Check if we are connected to another miner and thus do not eject directly if (targetContents) { diff --git a/src/js/game/systems/static_map_entity.js b/src/js/game/systems/static_map_entity.js index 616a0aa7..a212dcf6 100644 --- a/src/js/game/systems/static_map_entity.js +++ b/src/js/game/systems/static_map_entity.js @@ -4,6 +4,7 @@ import { globalConfig } from "../../core/config"; import { MapChunkView } from "../map_chunk_view"; import { Loader } from "../../core/loader"; import { enumDirection } from "../../core/vector"; +import { enumLayer } from "../root"; export class StaticMapEntitySystem extends GameSystem { constructor(root) { @@ -40,7 +41,6 @@ export class StaticMapEntitySystem extends GameSystem { continue; } drawnUids.add(entity.uid); - const staticComp = entity.components.StaticMapEntity; if (drawOutlinesOnly) { const rect = staticComp.getTileSpaceBounds(); @@ -68,4 +68,36 @@ export class StaticMapEntitySystem extends GameSystem { } } } + + /** + * Draws the static wire entities + * @param {DrawParameters} parameters + * @param {MapChunkView} chunk + */ + drawWiresChunk(parameters, chunk) { + if (G_IS_DEV && globalConfig.debug.doNotRenderStatics) { + return; + } + + const drawnUids = new Set(); + const contents = chunk.wireContents; + for (let y = 0; y < globalConfig.mapChunkSize; ++y) { + for (let x = 0; x < globalConfig.mapChunkSize; ++x) { + const entity = contents[x][y]; + if (entity) { + if (drawnUids.has(entity.uid)) { + continue; + } + drawnUids.add(entity.uid); + const staticComp = entity.components.StaticMapEntity; + + const spriteKey = staticComp.spriteKey; + if (spriteKey) { + const sprite = Loader.getSprite(spriteKey); + staticComp.drawSpriteOnFullEntityBounds(parameters, sprite, 2, false); + } + } + } + } + } } diff --git a/src/js/game/systems/storage.js b/src/js/game/systems/storage.js index 0917e56f..7f946e5b 100644 --- a/src/js/game/systems/storage.js +++ b/src/js/game/systems/storage.js @@ -4,6 +4,7 @@ import { Entity } from "../entity"; import { DrawParameters } from "../../core/draw_parameters"; import { formatBigNumber, lerp } from "../../core/utils"; import { Loader } from "../../core/loader"; +import { enumLayer } from "../root"; export class StorageSystem extends GameSystemWithFilter { constructor(root) { @@ -20,7 +21,9 @@ export class StorageSystem extends GameSystemWithFilter { // Eject from storage if (storageComp.storedItem && storageComp.storedCount > 0) { const ejectorComp = entity.components.ItemEjector; - const nextSlot = ejectorComp.getFirstFreeSlot(); + + /* FIXME: WIRES */ + const nextSlot = ejectorComp.getFirstFreeSlot(enumLayer.regular); if (nextSlot !== null) { if (ejectorComp.tryEject(nextSlot, storageComp.storedItem)) { storageComp.storedCount--; diff --git a/src/js/game/systems/underground_belt.js b/src/js/game/systems/underground_belt.js index 0456638a..f5e1b0ab 100644 --- a/src/js/game/systems/underground_belt.js +++ b/src/js/game/systems/underground_belt.js @@ -1,17 +1,21 @@ -import { Math_max } from "../../core/builtins"; import { globalConfig } from "../../core/config"; import { Loader } from "../../core/loader"; +import { createLogger } from "../../core/logging"; +import { Rectangle } from "../../core/rectangle"; import { + enumAngleToDirection, enumDirection, enumDirectionToAngle, enumDirectionToVector, - Vector, - enumAngleToDirection, enumInvertedDirections, } from "../../core/vector"; import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt"; import { Entity } from "../entity"; import { GameSystemWithFilter } from "../game_system_with_filter"; +import { fastArrayDelete } from "../../core/utils"; +import { enumLayer } from "../root"; + +const logger = createLogger("tunnels"); export class UndergroundBeltSystem extends GameSystemWithFilter { constructor(root) { @@ -26,30 +30,40 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { ), }; - this.root.signals.entityManuallyPlaced.add(this.onEntityPlaced, this); + this.root.signals.entityManuallyPlaced.add(this.onEntityManuallyPlaced, this); + + /** + * @type {Rectangle} + */ + this.areaToRecompute = null; + + this.root.signals.entityAdded.add(this.onEntityChanged, this); + this.root.signals.entityDestroyed.add(this.onEntityChanged, this); } - update() { - for (let i = 0; i < this.allEntities.length; ++i) { - const entity = this.allEntities[i]; + /** + * Called when an entity got added or removed + * @param {Entity} entity + */ + onEntityChanged(entity) { + if (!this.root.gameInitialized) { + return; + } + const undergroundComp = entity.components.UndergroundBelt; + if (!undergroundComp) { + return; + } - const undergroundComp = entity.components.UndergroundBelt; + const affectedArea = entity.components.StaticMapEntity.getTileSpaceBounds().expandedInAllDirections( + globalConfig.undergroundBeltMaxTilesByTier[ + globalConfig.undergroundBeltMaxTilesByTier.length - 1 + ] + 1 + ); - // Decrease remaining time of all items in belt - for (let k = 0; k < undergroundComp.pendingItems.length; ++k) { - const item = undergroundComp.pendingItems[k]; - item[1] = Math_max(0, item[1] - this.root.dynamicTickrate.deltaSeconds); - - if (G_IS_DEV && globalConfig.debug.instantBelts) { - item[1] = 0; - } - } - - if (undergroundComp.mode === enumUndergroundBeltMode.sender) { - this.handleSender(entity); - } else { - this.handleReceiver(entity); - } + if (this.areaToRecompute) { + this.areaToRecompute = this.areaToRecompute.getUnion(affectedArea); + } else { + this.areaToRecompute = affectedArea; } } @@ -57,7 +71,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { * Callback when an entity got placed, used to remove belts between underground belts * @param {Entity} entity */ - onEntityPlaced(entity) { + onEntityManuallyPlaced(entity) { if (!this.root.app.settings.getAllSettings().enableTunnelSmartplace) { // Smart-place disabled return; @@ -82,16 +96,18 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { let matchingEntrance = null; for (let i = 0; i < range; ++i) { currentPos.addInplace(offset); - const contents = this.root.map.getTileContent(currentPos); + const contents = this.root.map.getTileContent(currentPos, entity.layer); if (!contents) { continue; } const contentsUndergroundComp = contents.components.UndergroundBelt; + const contentsStaticComp = contents.components.StaticMapEntity; if ( contentsUndergroundComp && contentsUndergroundComp.tier === undergroundComp.tier && - contentsUndergroundComp.mode === enumUndergroundBeltMode.sender + contentsUndergroundComp.mode === enumUndergroundBeltMode.sender && + enumAngleToDirection[contentsStaticComp.rotation] === direction ) { matchingEntrance = { entity: contents, @@ -113,7 +129,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { for (let i = 0; i < matchingEntrance.range; ++i) { currentPos.addInplace(offset); - const contents = this.root.map.getTileContent(currentPos); + const contents = this.root.map.getTileContent(currentPos, entity.layer); if (!contents) { allBeltsMatch = false; break; @@ -141,7 +157,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { // All belts between this are obsolete, so drop them for (let i = 0; i < matchingEntrance.range; ++i) { currentPos.addInplace(offset); - const contents = this.root.map.getTileContent(currentPos); + const contents = this.root.map.getTileContent(currentPos, entity.layer); assert(contents, "Invalid smart underground belt logic"); this.root.logic.tryDeleteBuilding(contents); } @@ -154,8 +170,8 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { const posBefore = currentPos.copy(); currentPos.addInplace(offset); - const entityBefore = this.root.map.getTileContent(posBefore); - const entityAfter = this.root.map.getTileContent(currentPos); + const entityBefore = this.root.map.getTileContent(posBefore, entity.layer); + const entityAfter = this.root.map.getTileContent(currentPos, entity.layer); if (!entityBefore || !entityAfter) { continue; @@ -206,63 +222,157 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { } } + /** + * Recomputes the cache in the given area, invalidating all entries there + */ + recomputeArea() { + const area = this.areaToRecompute; + logger.log("Recomputing area:", area.x, area.y, "/", area.w, area.h); + if (G_IS_DEV && globalConfig.debug.renderChanges) { + this.root.hud.parts.changesDebugger.renderChange("tunnels", this.areaToRecompute, "#fc03be"); + } + + for (let x = area.x; x < area.right(); ++x) { + for (let y = area.y; y < area.bottom(); ++y) { + const entities = this.root.map.getLayersContentsMultipleXY(x, y); + for (let i = 0; i < entities.length; ++i) { + const entity = entities[i]; + const undergroundComp = entity.components.UndergroundBelt; + if (!undergroundComp) { + continue; + } + + undergroundComp.cachedLinkedEntity = null; + } + } + } + } + + update() { + if (this.areaToRecompute) { + this.recomputeArea(); + this.areaToRecompute = null; + } + + const delta = this.root.dynamicTickrate.deltaSeconds; + + for (let i = 0; i < this.allEntities.length; ++i) { + const entity = this.allEntities[i]; + const undergroundComp = entity.components.UndergroundBelt; + const pendingItems = undergroundComp.pendingItems; + + // Decrease remaining time of all items in belt + for (let k = 0; k < pendingItems.length; ++k) { + const item = pendingItems[k]; + item[1] = Math.max(0, item[1] - delta); + if (G_IS_DEV && globalConfig.debug.instantBelts) { + item[1] = 0; + } + } + if (undergroundComp.mode === enumUndergroundBeltMode.sender) { + this.handleSender(entity); + } else { + this.handleReceiver(entity); + } + } + } + + /** + * Finds the receiver for a given sender + * @param {Entity} entity + * @returns {import("../components/underground_belt").LinkedUndergroundBelt} + */ + findRecieverForSender(entity) { + const staticComp = entity.components.StaticMapEntity; + const undergroundComp = entity.components.UndergroundBelt; + const searchDirection = staticComp.localDirectionToWorld(enumDirection.top); + const searchVector = enumDirectionToVector[searchDirection]; + const targetRotation = enumDirectionToAngle[searchDirection]; + let currentTile = staticComp.origin; + + // Search in the direction of the tunnel + for ( + let searchOffset = 0; + searchOffset < globalConfig.undergroundBeltMaxTilesByTier[undergroundComp.tier]; + ++searchOffset + ) { + currentTile = currentTile.add(searchVector); + + const potentialReceiver = this.root.map.getTileContent(currentTile, enumLayer.regular); + if (!potentialReceiver) { + // Empty tile + continue; + } + const receiverUndergroundComp = potentialReceiver.components.UndergroundBelt; + if (!receiverUndergroundComp || receiverUndergroundComp.tier !== undergroundComp.tier) { + // Not a tunnel, or not on the same tier + continue; + } + + const receiverStaticComp = potentialReceiver.components.StaticMapEntity; + if (receiverStaticComp.rotation !== targetRotation) { + // Wrong rotation + continue; + } + + if (receiverUndergroundComp.mode !== enumUndergroundBeltMode.receiver) { + // Not a receiver, but a sender -> Abort to make sure we don't deliver double + break; + } + + return { entity: potentialReceiver, distance: searchOffset }; + } + + // None found + return { entity: null, distance: 0 }; + } + /** * * @param {Entity} entity */ handleSender(entity) { - const staticComp = entity.components.StaticMapEntity; const undergroundComp = entity.components.UndergroundBelt; - // Check if we have any item + // Find the current receiver + let receiver = undergroundComp.cachedLinkedEntity; + if (!receiver) { + // We don't have a receiver, compute it + receiver = undergroundComp.cachedLinkedEntity = this.findRecieverForSender(entity); + if (G_IS_DEV && globalConfig.debug.renderChanges) { + this.root.hud.parts.changesDebugger.renderChange( + "sender", + entity.components.StaticMapEntity.getTileSpaceBounds(), + "#fc03be" + ); + } + } + + if (!receiver.entity) { + // If there is no connection to a receiver, ignore this one + return; + } + + // Check if we have any item if (undergroundComp.pendingItems.length > 0) { + assert(undergroundComp.pendingItems.length === 1, "more than 1 pending"); const nextItemAndDuration = undergroundComp.pendingItems[0]; const remainingTime = nextItemAndDuration[1]; const nextItem = nextItemAndDuration[0]; + // Check if the item is ready to be emitted if (remainingTime === 0) { - // Try to find a receiver - const searchDirection = staticComp.localDirectionToWorld(enumDirection.top); - const searchVector = enumDirectionToVector[searchDirection]; - const targetRotation = enumDirectionToAngle[searchDirection]; - - let currentTile = staticComp.origin; - - for ( - let searchOffset = 0; - searchOffset < globalConfig.undergroundBeltMaxTilesByTier[undergroundComp.tier]; - ++searchOffset + // Check if the receiver can accept it + if ( + receiver.entity.components.UndergroundBelt.tryAcceptTunneledItem( + nextItem, + receiver.distance, + this.root.hubGoals.getUndergroundBeltBaseSpeed() + ) ) { - currentTile = currentTile.add(searchVector); - - const contents = this.root.map.getTileContent(currentTile); - if (contents) { - const receiverUndergroundComp = contents.components.UndergroundBelt; - if ( - receiverUndergroundComp && - receiverUndergroundComp.tier === undergroundComp.tier - ) { - const receiverStaticComp = contents.components.StaticMapEntity; - if (receiverStaticComp.rotation === targetRotation) { - if (receiverUndergroundComp.mode === enumUndergroundBeltMode.receiver) { - // Try to pass over the item to the receiver - if ( - receiverUndergroundComp.tryAcceptTunneledItem( - nextItem, - searchOffset, - this.root.hubGoals.getUndergroundBeltBaseSpeed() - ) - ) { - undergroundComp.pendingItems = []; - } - } - - // When we hit some underground belt, always stop, no matter what - break; - } - } - } + // Drop this item + fastArrayDelete(undergroundComp.pendingItems, 0); } } } @@ -275,7 +385,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { handleReceiver(entity) { const undergroundComp = entity.components.UndergroundBelt; - // Try to eject items, we only check the first one cuz its sorted by remaining time + // Try to eject items, we only check the first one because it is sorted by remaining time const items = undergroundComp.pendingItems; if (items.length > 0) { const nextItemAndDuration = undergroundComp.pendingItems[0]; @@ -284,7 +394,8 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { if (remainingTime <= 0) { const ejectorComp = entity.components.ItemEjector; - const nextSlotIndex = ejectorComp.getFirstFreeSlot(); + + const nextSlotIndex = ejectorComp.getFirstFreeSlot(entity.layer); if (nextSlotIndex !== null) { if (ejectorComp.tryEject(nextSlotIndex, nextItem)) { items.shift(); diff --git a/src/js/game/systems/wired_pins.js b/src/js/game/systems/wired_pins.js index 44e062b0..853568ef 100644 --- a/src/js/game/systems/wired_pins.js +++ b/src/js/game/systems/wired_pins.js @@ -1,37 +1,171 @@ -import { GameSystemWithFilter } from "../game_system_with_filter"; -import { WiredPinsComponent } from "../components/wired_pins"; +import { globalConfig } from "../../core/config"; import { DrawParameters } from "../../core/draw_parameters"; +import { Loader } from "../../core/loader"; +import { Vector } from "../../core/vector"; +import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins"; import { Entity } from "../entity"; -import { THEME } from "../theme"; +import { GameSystemWithFilter } from "../game_system_with_filter"; +import { enumLayer } from "../root"; +import { STOP_PROPAGATION } from "../../core/signal"; +import { drawRotatedSprite } from "../../core/draw_utils"; export class WiredPinsSystem extends GameSystemWithFilter { constructor(root) { super(root, [WiredPinsComponent]); + + this.pinSprites = { + [enumPinSlotType.positiveEnergyEjector]: Loader.getSprite("sprites/wires/pin_positive_eject.png"), + [enumPinSlotType.positiveEnergyAcceptor]: Loader.getSprite( + "sprites/wires/pin_positive_accept.png" + ), + [enumPinSlotType.negativeEnergyEjector]: Loader.getSprite("sprites/wires/pin_negative_eject.png"), + [enumPinSlotType.negativeEnergyAcceptor]: Loader.getSprite( + "sprites/wires/pin_negative_accept.png" + ), + }; + + this.root.signals.prePlacementCheck.add(this.prePlacementCheck, this); + this.root.signals.freeEntityAreaBeforeBuild.add(this.freeEntityAreaBeforeBuild, this); + } + + /** + * Performs pre-placement checks + * @param {Entity} entity + * @param {Vector} offset + */ + prePlacementCheck(entity, offset) { + // Compute area of the building + const rect = entity.components.StaticMapEntity.getTileSpaceBounds(); + if (offset) { + rect.x += offset.x; + rect.y += offset.y; + } + + // If this entity is placed on the wires layer, make sure we don't + // place it above a pin + if (entity.layer === enumLayer.wires) { + for (let x = rect.x; x < rect.x + rect.w; ++x) { + for (let y = rect.y; y < rect.y + rect.h; ++y) { + // Find which entities are in same tiles of both layers + const entities = this.root.map.getLayersContentsMultipleXY(x, y); + for (let i = 0; i < entities.length; ++i) { + const otherEntity = entities[i]; + + // Check if entity has a wired component + const pinComponent = otherEntity.components.WiredPins; + const staticComp = otherEntity.components.StaticMapEntity; + if (!pinComponent) { + continue; + } + + if (otherEntity.components.ReplaceableMapEntity) { + // Don't mind here, even if there would be a collision we + // could replace it + continue; + } + + // Go over all pins and check if they are blocking + const pins = pinComponent.slots; + for (let pinSlot = 0; pinSlot < pins.length; ++pinSlot) { + const pos = staticComp.localTileToWorld(pins[pinSlot].pos); + // Occupied by a pin + if (pos.x === x && pos.y === y) { + return STOP_PROPAGATION; + } + } + } + } + } + } + + // Check for collisions on the wires layer + if (this.checkEntityPinsCollide(entity, offset)) { + return STOP_PROPAGATION; + } + } + + /** + * Checks if the pins of the given entity collide on the wires layer + * @param {Entity} entity + * @param {Vector=} offset Optional, move the entity by the given offset first + * @returns {boolean} True if the pins collide + */ + checkEntityPinsCollide(entity, offset) { + const pinsComp = entity.components.WiredPins; + if (!pinsComp) { + return false; + } + + // Go over all slots + for (let slotIndex = 0; slotIndex < pinsComp.slots.length; ++slotIndex) { + const slot = pinsComp.slots[slotIndex]; + + // Figure out which tile this slot is on + const worldPos = entity.components.StaticMapEntity.localTileToWorld(slot.pos); + if (offset) { + worldPos.x += offset.x; + worldPos.y += offset.y; + } + + // Check if there is any entity on that tile (Wired pins are always on the wires layer) + const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, enumLayer.wires); + + // If there's an entity, and it can't get removed -> That's a collision + if (collidingEntity && !collidingEntity.components.ReplaceableMapEntity) { + return true; + } + } + return false; + } + + /** + * Called to free space for the given entity + * @param {Entity} entity + */ + freeEntityAreaBeforeBuild(entity) { + const pinsComp = entity.components.WiredPins; + if (!pinsComp) { + // Entity has no pins + return; + } + + // Remove any stuff which collides with the pins + for (let i = 0; i < pinsComp.slots.length; ++i) { + const slot = pinsComp.slots[i]; + const worldPos = entity.components.StaticMapEntity.localTileToWorld(slot.pos); + const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, enumLayer.wires); + if (collidingEntity) { + assertAlways( + collidingEntity.components.ReplaceableMapEntity, + "Tried to replace non-repleaceable entity for pins" + ); + if (!this.root.logic.tryDeleteBuilding(collidingEntity)) { + assertAlways(false, "Tried to replace non-repleaceable entity for pins #2"); + } + } + } } update() { // TODO } - drawWiresLayer(parameters) { - this.forEachMatchingEntityOnScreen(parameters, this.drawEntityPins.bind(this)); + /** + * Draws the pins + * @param {DrawParameters} parameters + */ + draw(parameters) { + this.forEachMatchingEntityOnScreen(parameters, this.drawSingleEntity.bind(this)); } /** - * + * Draws a given entity * @param {DrawParameters} parameters * @param {Entity} entity */ - drawEntityPins(parameters, entity) { + drawSingleEntity(parameters, entity) { const staticComp = entity.components.StaticMapEntity; - - if (!staticComp.shouldBeDrawn(parameters)) { - return; - } - - const pinsComp = entity.components.WiredPins; - - const slots = pinsComp.slots; + const slots = entity.components.WiredPins.slots; for (let i = 0; i < slots.length; ++i) { const slot = slots[i]; @@ -39,13 +173,16 @@ export class WiredPinsSystem extends GameSystemWithFilter { const worldPos = tile.toWorldSpaceCenterOfTile(); - parameters.context.fillStyle = THEME.map.wires.pins[slot.type]; - parameters.context.beginCircle(worldPos.x, worldPos.y, 5); - parameters.context.fill(); - - parameters.context.lineWidth = 2; - parameters.context.fillStyle = "rgba(0, 0, 0, 0.1)"; - parameters.context.stroke(); + drawRotatedSprite({ + parameters, + sprite: this.pinSprites[slot.type], + x: worldPos.x, + y: worldPos.y, + angle: Math.radians(staticComp.rotation), + size: globalConfig.tileSize, + offsetX: 0, + offsetY: 0, + }); } } } diff --git a/src/js/game/themes/dark.json b/src/js/game/themes/dark.json index 231e4bcd..626efa19 100644 --- a/src/js/game/themes/dark.json +++ b/src/js/game/themes/dark.json @@ -9,8 +9,16 @@ "selectionOutline": "rgba(74, 163, 223, 0.5)", "selectionBackground": "rgba(74, 163, 223, 0.2)", - "directionLock": "rgb(74, 237, 134)", - "directionLockTrack": "rgba(74, 237, 134, 0.2)", + "directionLock": { + "regular": { + "color": "rgb(74, 237, 134)", + "background": "rgba(74, 237, 134, 0.2)" + }, + "wires": { + "color": "rgb(209, 107, 203)", + "background": "rgba(209, 107, 203, 0.2)" + } + }, "colorBlindPickerTile": "rgba(255, 255, 255, 0.5)", @@ -26,7 +34,6 @@ }, "wires": { - "overlay": "rgba(52, 150, 128, 0.5)", "pins": { "energyEjector": "#c425d7" } diff --git a/src/js/game/themes/light.json b/src/js/game/themes/light.json index 1356a2b6..21599585 100644 --- a/src/js/game/themes/light.json +++ b/src/js/game/themes/light.json @@ -9,8 +9,16 @@ "selectionOutline": "rgba(74, 163, 223, 0.5)", "selectionBackground": "rgba(74, 163, 223, 0.2)", - "directionLock": "rgb(74, 237, 134)", - "directionLockTrack": "rgba(74, 237, 134, 0.2)", + "directionLock": { + "regular": { + "color": "rgb(74, 237, 134)", + "background": "rgba(74, 237, 134, 0.2)" + }, + "wires": { + "color": "rgb(209, 107, 203)", + "background": "rgba(209, 107, 203, 0.2)" + } + }, "colorBlindPickerTile": "rgba(50, 50, 50, 0.4)", @@ -27,7 +35,6 @@ }, "wires": { - "overlay": "rgba(52, 150, 128, 0.8)", "pins": { "energyEjector": "#c425d7" } diff --git a/src/js/game/time/game_time.js b/src/js/game/time/game_time.js index 748ccb2d..7d0c310d 100644 --- a/src/js/game/time/game_time.js +++ b/src/js/game/time/game_time.js @@ -6,7 +6,6 @@ import { types, BasicSerializableObject } from "../../savegame/serialization"; import { RegularGameSpeed } from "./regular_game_speed"; import { BaseGameSpeed } from "./base_game_speed"; import { PausedGameSpeed } from "./paused_game_speed"; -import { performanceNow, Math_max } from "../../core/builtins"; import { FastForwardGameSpeed } from "./fast_forward_game_speed"; import { gGameSpeedRegistry } from "../../core/global_registries"; import { globalConfig } from "../../core/config"; @@ -55,7 +54,7 @@ export class GameTime extends BasicSerializableObject { * Fetches the new "real" time, called from the core once per frame, since performance now() is kinda slow */ updateRealtimeNow() { - this.realtimeSeconds = performanceNow() / 1000.0 + this.realtimeAdjust; + this.realtimeSeconds = performance.now() / 1000.0 + this.realtimeAdjust; } /** @@ -104,7 +103,7 @@ export class GameTime extends BasicSerializableObject { } // Check for too big pile of updates -> reduce it to 1 - let maxLogicSteps = Math_max( + let maxLogicSteps = Math.max( 3, (this.speed.getMaxLogicStepsInQueue() * this.root.dynamicTickrate.currentTickRate) / 60 ); @@ -209,7 +208,7 @@ export class GameTime extends BasicSerializableObject { } // Adjust realtime now difference so they match - this.realtimeAdjust = this.realtimeSeconds - performanceNow() / 1000.0; + this.realtimeAdjust = this.realtimeSeconds - performance.now() / 1000.0; this.updateRealtimeNow(); // Make sure we have a quantizied time diff --git a/src/js/game/tutorial_goals.js b/src/js/game/tutorial_goals.js index 67ca17d7..366877ee 100644 --- a/src/js/game/tutorial_goals.js +++ b/src/js/game/tutorial_goals.js @@ -23,8 +23,6 @@ export const enumHubGoalRewards = { reward_painter_quad: "reward_painter_quad", reward_storage: "reward_storage", - reward_wires: "reward_wires", - reward_blueprints: "reward_blueprints", reward_freeplay: "reward_freeplay", @@ -90,7 +88,7 @@ export const tutorialGoals = [ // 8 { shape: "RbRb----", // painter t2 - required: 1250, + required: 1000, reward: enumHubGoalRewards.reward_mixer, }, @@ -98,7 +96,7 @@ export const tutorialGoals = [ // Mixing (purple) { shape: "CpCpCpCp", // belts t3 - required: 1750, + required: 1400, reward: enumHubGoalRewards.reward_splitter_compact, }, @@ -106,7 +104,7 @@ export const tutorialGoals = [ // Star shape + cyan { shape: "ScScScSc", // miners t3 - required: 2250, + required: 1600, reward: enumHubGoalRewards.reward_stacker, }, @@ -114,7 +112,7 @@ export const tutorialGoals = [ // Stacker { shape: "CgScScCg", // processors t3 - required: 3000, + required: 1800, reward: enumHubGoalRewards.reward_miner_chainable, }, @@ -122,7 +120,7 @@ export const tutorialGoals = [ // Blueprints { shape: "CbCbCbRb:CwCwCwCw", - required: 4000, + required: 2000, reward: enumHubGoalRewards.reward_blueprints, }, @@ -156,8 +154,8 @@ export const tutorialGoals = [ // 17 { - shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", // processors t4 (two varinats) - required: 100000, + shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", // processors t4 (two variants) + required: 120000, reward: enumHubGoalRewards.reward_painter_quad, }, @@ -165,19 +163,12 @@ export const tutorialGoals = [ { shape: finalGameShape, required: 250000, - reward: enumHubGoalRewards.reward_wires, - }, - - // 19 - { - shape: finalGameShape, - required: 1, reward: enumHubGoalRewards.reward_freeplay, }, ]; if (G_IS_DEV) { - tutorialGoals.forEach(({ shape, required, reward }) => { + tutorialGoals.forEach(({ shape }) => { try { ShapeDefinition.fromShortKey(shape); } catch (ex) { diff --git a/src/js/game/upgrades.js b/src/js/game/upgrades.js index 500a2afe..6e0c7c64 100644 --- a/src/js/game/upgrades.js +++ b/src/js/game/upgrades.js @@ -12,7 +12,7 @@ export const UPGRADES = { improvement: 1, }, { - required: [{ shape: "--CuCu--", amount: 1500 }], + required: [{ shape: "--CuCu--", amount: 1200 }], improvement: 2, }, { @@ -42,7 +42,7 @@ export const UPGRADES = { improvement: 1, }, { - required: [{ shape: "Cu------", amount: 5500 }], + required: [{ shape: "Cu------", amount: 4000 }], improvement: 2, }, { @@ -102,7 +102,7 @@ export const UPGRADES = { improvement: 2, }, { - required: [{ shape: "WrWrWrWr", amount: 5000 }], + required: [{ shape: "WrWrWrWr", amount: 4000 }], improvement: 1, }, { diff --git a/src/js/platform/ad_providers/adinplay.js b/src/js/platform/ad_providers/adinplay.js index efad0574..00a08fcb 100644 --- a/src/js/platform/ad_providers/adinplay.js +++ b/src/js/platform/ad_providers/adinplay.js @@ -5,7 +5,6 @@ import { Application } from "../../application"; import { AdProviderInterface } from "../ad_provider"; import { createLogger } from "../../core/logging"; import { ClickDetector } from "../../core/click_detector"; -import { performanceNow } from "../../core/builtins"; import { clamp } from "../../core/utils"; import { T } from "../../translations"; @@ -52,7 +51,7 @@ export class AdinplayAdProvider extends AdProviderInterface { return ( this.getHasAds() && !this.videoAdResolveFunction && - performanceNow() - this.lastVideoAdShowTime > minimumTimeBetweenVideoAdsMs + performance.now() - this.lastVideoAdShowTime > minimumTimeBetweenVideoAdsMs ); } @@ -141,7 +140,7 @@ export class AdinplayAdProvider extends AdProviderInterface { showVideoAd() { assert(this.getHasAds(), "Called showVideoAd but ads are not supported!"); assert(!this.videoAdResolveFunction, "Video ad still running, can not show again!"); - this.lastVideoAdShowTime = performanceNow(); + this.lastVideoAdShowTime = performance.now(); document.body.appendChild(this.adContainerMainElement); this.adContainerMainElement.classList.add("visible"); this.adContainerMainElement.classList.remove("waitingForFinish"); @@ -167,7 +166,7 @@ export class AdinplayAdProvider extends AdProviderInterface { this.videoAdResolveTimer = null; // When the ad closed, also set the time - this.lastVideoAdShowTime = performanceNow(); + this.lastVideoAdShowTime = performance.now(); resolve(); }; diff --git a/src/js/platform/ad_providers/gamedistribution.js b/src/js/platform/ad_providers/gamedistribution.js index 431d6096..6ff031f0 100644 --- a/src/js/platform/ad_providers/gamedistribution.js +++ b/src/js/platform/ad_providers/gamedistribution.js @@ -3,7 +3,6 @@ import { Application } from "../../application"; /* typehints:end */ import { AdProviderInterface } from "../ad_provider"; -import { performanceNow } from "../../core/builtins"; import { createLogger } from "../../core/logging"; const minimumTimeBetweenVideoAdsMs = G_IS_DEV ? 1 : 5 * 60 * 1000; @@ -45,7 +44,7 @@ export class GamedistributionAdProvider extends AdProviderInterface { return ( this.getHasAds() && !this.videoAdResolveFunction && - performanceNow() - this.lastVideoAdShowTime > minimumTimeBetweenVideoAdsMs + performance.now() - this.lastVideoAdShowTime > minimumTimeBetweenVideoAdsMs ); } @@ -84,7 +83,7 @@ export class GamedistributionAdProvider extends AdProviderInterface { showVideoAd() { assert(this.getHasAds(), "Called showVideoAd but ads are not supported!"); assert(!this.videoAdResolveFunction, "Video ad still running, can not show again!"); - this.lastVideoAdShowTime = performanceNow(); + this.lastVideoAdShowTime = performance.now(); console.log("🎬 Gamedistribution: Start ad"); try { @@ -104,7 +103,7 @@ export class GamedistributionAdProvider extends AdProviderInterface { this.videoAdResolveTimer = null; // When the ad closed, also set the time - this.lastVideoAdShowTime = performanceNow(); + this.lastVideoAdShowTime = performance.now(); resolve(); }; diff --git a/src/js/platform/browser/google_analytics.js b/src/js/platform/browser/google_analytics.js index 3c54fbbd..782471d2 100644 --- a/src/js/platform/browser/google_analytics.js +++ b/src/js/platform/browser/google_analytics.js @@ -1,5 +1,4 @@ import { AnalyticsInterface } from "../analytics"; -import { Math_random, performanceNow } from "../../core/builtins"; import { createLogger } from "../../core/logging"; const logger = createLogger("ga"); diff --git a/src/js/platform/browser/wrapper.js b/src/js/platform/browser/wrapper.js index ab5ec327..bbe9d221 100644 --- a/src/js/platform/browser/wrapper.js +++ b/src/js/platform/browser/wrapper.js @@ -1,4 +1,3 @@ -import { Math_min } from "../../core/builtins"; import { globalConfig, IS_DEMO, IS_MOBILE } from "../../core/config"; import { createLogger } from "../../core/logging"; import { queryParamOptions } from "../../core/query_parameters"; @@ -83,7 +82,7 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface { return new Promise(resolve => { logger.log("Detecting storage"); - if (!window.indexedDB) { + if (!window.indexedDB || G_IS_DEV) { logger.log("Indexed DB not supported"); this.app.storage = new StorageImplBrowser(this.app); resolve(); @@ -130,7 +129,7 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface { return 1; } - const avgDims = Math_min(this.app.screenWidth, this.app.screenHeight); + const avgDims = Math.min(this.app.screenWidth, this.app.screenHeight); return clamp((avgDims / 1000.0) * 1.9, 0.1, 10); } diff --git a/src/js/profile/application_settings.js b/src/js/profile/application_settings.js index be81c695..708c4d7b 100644 --- a/src/js/profile/application_settings.js +++ b/src/js/profile/application_settings.js @@ -215,7 +215,7 @@ export const allApplicationSettings = [ }), new EnumSetting("refreshRate", { - options: ["60", "100", "144", "165", "250", G_IS_DEV ? "10" : "500"], + options: ["60", "100", "120", "144", "165", "250", G_IS_DEV ? "10" : "500"], valueGetter: rate => rate, textGetter: rate => rate + " Hz", category: categoryGame, diff --git a/src/js/savegame/savegame.js b/src/js/savegame/savegame.js index 359a48b5..1db813d7 100644 --- a/src/js/savegame/savegame.js +++ b/src/js/savegame/savegame.js @@ -14,6 +14,7 @@ import { SavegameInterface_V1001 } from "./schemas/1001"; import { SavegameInterface_V1002 } from "./schemas/1002"; import { SavegameInterface_V1003 } from "./schemas/1003"; import { SavegameInterface_V1004 } from "./schemas/1004"; +import { SavegameInterface_V1005 } from "./schemas/1005"; const logger = createLogger("savegame"); @@ -45,7 +46,7 @@ export class Savegame extends ReadWriteProxy { * @returns {number} */ static getCurrentVersion() { - return 1004; + return 1005; } /** @@ -104,6 +105,11 @@ export class Savegame extends ReadWriteProxy { data.version = 1004; } + if (data.version === 1004) { + SavegameInterface_V1005.migrate1004to1005(data); + data.version = 1005; + } + return ExplainedResult.good(); } @@ -203,7 +209,7 @@ export class Savegame extends ReadWriteProxy { // Construct a new serializer const serializer = new SavegameSerializer(); - // let timer = performanceNow(); + // let timer = performance.now(); const dump = serializer.generateDumpFromGameRoot(root); if (!dump) { return false; diff --git a/src/js/savegame/savegame_interface.js b/src/js/savegame/savegame_interface.js index 8671471d..55fd27e7 100644 --- a/src/js/savegame/savegame_interface.js +++ b/src/js/savegame/savegame_interface.js @@ -90,18 +90,4 @@ export class BaseSavegameInterface { readIngameTimeSeconds() { return this.data.dump.time.timeSeconds; } - - /** - - - //////// ANTICHEAT /////// - - /** - * Detects cheats in the savegame - returns false if the game looks cheated - */ - performAnticheatCheck() { - // TODO - - return true; - } } diff --git a/src/js/savegame/savegame_interface_registry.js b/src/js/savegame/savegame_interface_registry.js index 6144ca62..fb1df52f 100644 --- a/src/js/savegame/savegame_interface_registry.js +++ b/src/js/savegame/savegame_interface_registry.js @@ -5,6 +5,7 @@ import { SavegameInterface_V1001 } from "./schemas/1001"; import { SavegameInterface_V1002 } from "./schemas/1002"; import { SavegameInterface_V1003 } from "./schemas/1003"; import { SavegameInterface_V1004 } from "./schemas/1004"; +import { SavegameInterface_V1005 } from "./schemas/1005"; /** @type {Object.} */ export const savegameInterfaces = { @@ -13,6 +14,7 @@ export const savegameInterfaces = { 1002: SavegameInterface_V1002, 1003: SavegameInterface_V1003, 1004: SavegameInterface_V1004, + 1005: SavegameInterface_V1005, }; const logger = createLogger("savegame_interface_registry"); diff --git a/src/js/savegame/savegame_manager.js b/src/js/savegame/savegame_manager.js index 2c20c819..e3052806 100644 --- a/src/js/savegame/savegame_manager.js +++ b/src/js/savegame/savegame_manager.js @@ -3,8 +3,6 @@ import { createLogger } from "../core/logging"; import { ReadWriteProxy } from "../core/read_write_proxy"; import { globalConfig } from "../core/config"; import { Savegame } from "./savegame"; -import { Math_floor } from "../core/builtins"; - const logger = createLogger("savegame_manager"); const Rusha = require("rusha"); diff --git a/src/js/savegame/savegame_serializer.js b/src/js/savegame/savegame_serializer.js index 52a59528..eff802a0 100644 --- a/src/js/savegame/savegame_serializer.js +++ b/src/js/savegame/savegame_serializer.js @@ -3,7 +3,6 @@ import { Component } from "../game/component"; import { GameRoot } from "../game/root"; /* typehints:end */ -import { JSON_stringify } from "../core/builtins"; import { ExplainedResult } from "../core/explained_result"; import { createLogger } from "../core/logging"; // import { BuildingComponent } from "../components/impl/building"; @@ -27,10 +26,6 @@ export class SavegameSerializer { * @returns {object} */ generateDumpFromGameRoot(root, sanityChecks = true) { - // Finalize particles before saving (Like granting destroy indicator rewards) - // root.particleMgr.finalizeBeforeSave(); - // root.uiParticleMgr.finalizeBeforeSave(); - // Now store generic savegame payload const data = { camera: root.camera.serialize(), @@ -40,6 +35,7 @@ export class SavegameSerializer { hubGoals: root.hubGoals.serialize(), pinnedShapes: root.hud.parts.pinnedShapes.serialize(), waypoints: root.hud.parts.waypoints.serialize(), + beltPaths: root.systemMgr.systems.belt.serializePaths(), }; data.entities = this.internal.serializeEntityArray(root.entityMgr.entities); @@ -87,7 +83,7 @@ export class SavegameSerializer { // Verify components if (!entity.components) { return ExplainedResult.bad( - "Entity is missing key 'components': " + JSON_stringify(entity) + "Entity is missing key 'components': " + JSON.stringify(entity) ); } const components = entity.components; @@ -140,6 +136,7 @@ export class SavegameSerializer { errorReason = errorReason || root.hud.parts.pinnedShapes.deserialize(savegame.pinnedShapes); errorReason = errorReason || root.hud.parts.waypoints.deserialize(savegame.waypoints); errorReason = errorReason || this.internal.deserializeEntityArray(root, savegame.entities); + errorReason = errorReason || root.systemMgr.systems.belt.deserializePaths(savegame.beltPaths); // Check for errors if (errorReason) { diff --git a/src/js/savegame/savegame_typedefs.js b/src/js/savegame/savegame_typedefs.js index 6211150f..642865cd 100644 --- a/src/js/savegame/savegame_typedefs.js +++ b/src/js/savegame/savegame_typedefs.js @@ -5,6 +5,10 @@ import { Entity } from "../game/entity"; * }} SavegameStats */ +/** + * + */ + /** * @typedef {{ * camera: any, @@ -14,7 +18,8 @@ import { Entity } from "../game/entity"; * hubGoals: any, * pinnedShapes: any, * waypoints: any, - * entities: Array + * entities: Array, + * beltPaths: Array * }} SerializedGame */ diff --git a/src/js/savegame/schemas/1005.js b/src/js/savegame/schemas/1005.js new file mode 100644 index 00000000..0380f8eb --- /dev/null +++ b/src/js/savegame/schemas/1005.js @@ -0,0 +1,45 @@ +import { createLogger } from "../../core/logging.js"; +import { SavegameInterface_V1004 } from "./1004.js"; + +const schema = require("./1005.json"); +const logger = createLogger("savegame_interface/1005"); + +export class SavegameInterface_V1005 extends SavegameInterface_V1004 { + getVersion() { + return 1005; + } + + getSchemaUncached() { + return schema; + } + + /** + * @param {import("../savegame_typedefs.js").SavegameData} data + */ + static migrate1004to1005(data) { + logger.log("Migrating 1004 to 1005"); + const dump = data.dump; + if (!dump) { + return true; + } + + // just reset belt paths for now + dump.beltPaths = []; + + const entities = dump.entities; + + // clear ejector slots + for (let i = 0; i < entities.length; ++i) { + const entity = entities[i]; + const itemEjector = entity.components.ItemEjector; + if (itemEjector) { + const slots = itemEjector.slots; + for (let k = 0; k < slots.length; ++k) { + const slot = slots[k]; + slot.item = null; + slot.progress = 0; + } + } + } + } +} diff --git a/src/js/savegame/schemas/1005.json b/src/js/savegame/schemas/1005.json new file mode 100644 index 00000000..6682f615 --- /dev/null +++ b/src/js/savegame/schemas/1005.json @@ -0,0 +1,5 @@ +{ + "type": "object", + "required": [], + "additionalProperties": true +} diff --git a/src/js/savegame/serialization.js b/src/js/savegame/serialization.js index 7ab6f678..aea2f944 100644 --- a/src/js/savegame/serialization.js +++ b/src/js/savegame/serialization.js @@ -1,4 +1,3 @@ -import { JSON_stringify } from "../core/builtins"; import { BaseDataType, TypeArray, @@ -223,7 +222,7 @@ export function serializeSchema(obj, schema, mergeWith = {}) { ); } if (!schema[key]) { - assert(false, "Invalid schema (bad key '" + key + "'): " + JSON_stringify(schema)); + assert(false, "Invalid schema (bad key '" + key + "'): " + JSON.stringify(schema)); } if (G_IS_DEV) { diff --git a/src/js/savegame/serialization_data_types.js b/src/js/savegame/serialization_data_types.js index 332dc274..86b177c1 100644 --- a/src/js/savegame/serialization_data_types.js +++ b/src/js/savegame/serialization_data_types.js @@ -5,8 +5,6 @@ import { BasicSerializableObject } from "./serialization"; import { Vector } from "../core/vector"; import { round4Digits, schemaObject, accessNestedPropertyReverse } from "../core/utils"; -import { JSON_stringify } from "../core/builtins"; - export const globalJsonSchemaDefs = {}; /** @@ -128,7 +126,7 @@ export class BaseDataType { "serialization verify failed: " + errorCode + " [value " + - JSON_stringify(value).substr(0, 100) + + JSON.stringify(value).substr(0, 100) + "]" ); } diff --git a/src/js/savegame/serializer_internal.js b/src/js/savegame/serializer_internal.js index ec761beb..8df6f6e4 100644 --- a/src/js/savegame/serializer_internal.js +++ b/src/js/savegame/serializer_internal.js @@ -1,15 +1,9 @@ -/* typehints:start */ -import { GameRoot } from "../game/root"; -/* typehints:end */ - import { gComponentRegistry } from "../core/global_registries"; -import { createLogger } from "../core/logging"; import { Entity } from "../game/entity"; +import { enumLayer, GameRoot } from "../game/root"; // Internal serializer methods export class SerializerInternal { - constructor() {} - /** * Serializes an array of entities * @param {Array} array @@ -45,6 +39,11 @@ export class SerializerInternal { deserializeEntity(root, payload) { const entity = new Entity(root); this.deserializeComponents(entity, payload.components); + entity.layer = payload.layer; + + if (!enumLayer[payload.layer]) { + assert(false, "Invalid layer: " + payload.layer); + } root.entityMgr.registerEntity(entity, payload.uid); diff --git a/src/js/states/keybindings.js b/src/js/states/keybindings.js index bc2b4a18..b68626c7 100644 --- a/src/js/states/keybindings.js +++ b/src/js/states/keybindings.js @@ -111,9 +111,7 @@ export class KeybindingsState extends TextualGameState { if ( // Enter - keyCode === 13 || - // TAB - keyCode === 9 + keyCode === 13 ) { // Ignore builtins return; diff --git a/src/js/states/main_menu.js b/src/js/states/main_menu.js index 8f7d4a93..cf7a05ac 100644 --- a/src/js/states/main_menu.js +++ b/src/js/states/main_menu.js @@ -46,18 +46,15 @@ export class MainMenuState extends GameState { : "" } - - ${ - G_IS_STANDALONE - ? "" - : ` @@ -208,14 +205,12 @@ export class MainMenuState extends GameState { // Initialize video this.videoElement = this.htmlElement.querySelector("video"); - if (this.videoElement) { - this.videoElement.playbackRate = 0.9; - this.videoElement.addEventListener("canplay", () => { - if (this.videoElement) { - this.videoElement.classList.add("loaded"); - } - }); - } + this.videoElement.playbackRate = 0.9; + this.videoElement.addEventListener("canplay", () => { + if (this.videoElement) { + this.videoElement.classList.add("loaded"); + } + }); this.trackClicks(qs(".settingsButton"), this.onSettingsButtonClicked); this.trackClicks(qs(".changelog"), this.onChangelogClicked); diff --git a/sync-translations.js b/sync-translations.js index 4815704d..d6b87278 100644 --- a/sync-translations.js +++ b/sync-translations.js @@ -17,7 +17,7 @@ const originalContents = fs const original = YAML.parse(originalContents); -const placeholderRegexp = /<([a-zA-Z_0-9]+)>/gi; +const placeholderRegexp = /[[<]([a-zA-Z_0-9]+)[\]<]/gi; function match(originalObj, translatedObj, path = "/") { for (const key in originalObj) { diff --git a/translations/README.md b/translations/README.md index 6e46a6fe..48400a48 100644 --- a/translations/README.md +++ b/translations/README.md @@ -1,10 +1,9 @@ # Translations -The base translation is `base-en.yaml`. It will always contain the latest phrases and structure. +The base language is English and can be found [here](base-en.yaml). ## Languages -- [English (Base Language, Source of Truth)](base-en.yaml) - [German](base-de.yaml) - [French](base-fr.yaml) - [Korean](base-kor.yaml) @@ -19,7 +18,7 @@ The base translation is `base-en.yaml`. It will always contain the latest phrase - [Swedish](base-sv.yaml) - [Chinese (Simplified)](base-zh-CN.yaml) - [Chinese (Traditional)](base-zh-TW.yaml) -- [Spanish (Latin America)](base-es.yaml) +- [Spanish](base-es.yaml) - [Hungarian](base-hu.yaml) - [Turkish](base-tr.yaml) - [Japanese](base-ja.yaml) @@ -28,6 +27,10 @@ The base translation is `base-en.yaml`. It will always contain the latest phrase - [Norwegian](base-no.yaml) - [Kroatian](base-hr.yaml) - [Danish](base-da.yaml) +- [Finnish](base-fi.yaml) +- [Catalan](base-cat.yaml) +- [Slovenian](base-sl.yaml) +- [Ukrainian](base-uk.yaml) (If you want to translate into a new language, see below!) @@ -35,15 +38,39 @@ The base translation is `base-en.yaml`. It will always contain the latest phrase If you want to edit an existing translation (Fixing typos, Updating it to a newer version, etc), you can just use the github file editor to edit the file. -- Find the file you want to edit (For example, `base-de.yaml` if you want to change the german translation) -- Click on the file name on, there will be a small "edit" symbol on the top right -- Do the changes you wish to do (Be sure **not** to translate placeholders!) +- Click the language you want to edit from the list above +- Click the small "edit" symbol on the top right + +edit symbol + +- Do the changes you wish to do (Be sure **not** to translate placeholders! For example, ` minutes` should get ` Minuten` and **not** ` Minuten`!) + - Click "Propose Changes" -- I will review your changes and make comments, and eventually merge them so they will be in the next release! + +propose changes + +- Click "Create pull request" + +create pull request + +- I will review your changes and make comments, and eventually merge them so they will be in the next release! Be sure to regulary check the created pull request for comments. ## Adding a new language -Please DM me on discord (tobspr#5407), so I can add the language template for you. It is not as simple as creating a new file. +Please DM me on discord (tobspr#5407), so I can add the language template for you. + +Please use the following template: + +``` +Hey, could you add a new translation? + +Language: +Short code: +Local Name: +``` + +You can find the short code [here](https://www.science.co.il/language/Codes.php) (In column `Code 2`). + PS: I'm super busy, but I'll give my best to do it quickly! ## Updating a language to the latest version diff --git a/translations/base-ar.yaml b/translations/base-ar.yaml index 9e10dd65..c42d5e0d 100644 --- a/translations/base-ar.yaml +++ b/translations/base-ar.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Unlimited Savegames [*] Dark Mode - [*] More settings - [*] Allow me to further develop shapez.io ❤️ - [*] More features in the future! + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - This game is open source - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story mode where buildings cost shapes - [*] More levels & buildings (standalone exclusive) - [*] Different maps, and maybe map obstacles - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] More types of shapes - [*] More performance improvements (Although the game already runs pretty good!) - [*] Color blind mode + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Loading @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -131,28 +151,7 @@ mainMenu: savegameLevel: Level savegameLevelUnknown: Unknown Level - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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! continue: Continue newGame: New Game madeBy: Made by @@ -255,6 +254,7 @@ dialogs: createMarker: title: New Marker desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker markerDemoLimit: desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! @@ -270,6 +270,10 @@ dialogs: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -292,6 +296,7 @@ ingame: copySelection: Copy clearSelection: Clear Selection pipette: Pipette + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -407,9 +412,11 @@ ingame: cyan: Cyan white: White uncolored: No color + black: Black shapeViewer: title: Layers empty: Empty + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -517,6 +524,27 @@ buildings: storage: name: Storage description: Stores excess items, up to a given capacity. Can be used as an overflow gate. + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -729,11 +757,11 @@ settings: title: Color Blind Mode description: Enables various tools which allow to play the game if you are color blind. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. + This may be more comfortable if you frequently switch between placing + different building types. keybindings: title: Keybindings @@ -801,6 +829,11 @@ keybindings: lockBeltDirection: Enable belt planner switchDirectionLockSide: "Planner: Switch side" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: About this Game diff --git a/translations/base-cat.yaml b/translations/base-cat.yaml new file mode 100644 index 00000000..1abab2ca --- /dev/null +++ b/translations/base-cat.yaml @@ -0,0 +1,845 @@ +# +# 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: `. They are encapsulated within angle brackets. The correct +# translation for this one in German for example would be: `Taste: ` (notice +# how the placeholder stayed '' 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. +# + +steamPage: + # This is the short text appearing on the steam page + shortText: shapez.io és un joc que té com a objectiu construir i automatitzar fàbriques per tal de produir figures cada cop més complexes en un mapa infinit. + + # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. + # NOTICE: + # - Do not translate the first line (This is the gif image at the start of the store) + # - Please keep the markup (Stuff like [b], [list] etc) in the same format + longText: >- + [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] + + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. + + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! + + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. + + [b]Standalone Advantages[/b] + + [list] + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ + [/list] + + [b]Future Updates[/b] + + I am updating the game very often and trying to push an update at least every week! + + [list] + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! + [/list] + + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! + +global: + loading: Carregant + error: Error + + # How big numbers are rendered, e.g. "10,000" + thousandsDivider: "," + + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + + # 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: fa un segon + xSecondsAgo: fa segons + oneMinuteAgo: fa un minut + xMinutesAgo: fa minuts + oneHourAgo: fa una hora + xHoursAgo: fa hores + oneDayAgo: fa un dia + xDaysAgo: fa dies + + # Short formats for times, e.g. '5h 23m' + secondsShort: s + minutesAndSecondsShort: m s + hoursAndMinutesShort: h m + + xMinutes: minuts + + keys: + tab: TAB + control: CTRL + alt: ALT + escape: ESC + shift: SHIFT + space: ESPAI + +demoBanners: + # This is the "advertisement" shown in the main menu and other various places + title: Demo - Versió de prova + intro: >- + Aconsegueix el joc complet per obtenir totes les característiques! +mainMenu: + play: Jugar + continue: Continuar + newGame: Nou joc + changelog: Historial de canvis + subreddit: Reddit + importSavegame: Importar + openSourceHint: Aquest joc es de codi obert! + discordLink: Servidor Discord oficial + helpTranslate: Ajuda a traduir-lo! + madeBy: Creat per + + # This is shown when using firefox and other browsers which are not supported. + browserWarning: >- + + Disculpa, però el joc funcionarà lent al teu navegador! Aconsegueix el joc complet o descarrega't chrome per una millor experiència. + savegameLevel: Nivell + savegameLevelUnknown: Nivell desconegut + + + +dialogs: + buttons: + ok: OK + delete: Eliminar + cancel: Cancel·lar + later: Més tard + restart: Tornar a començar + reset: Reiniciar + getStandalone: Obtenir versió completa + deleteGame: Sé el que faig + viewUpdate: Veure actualitzacions + showUpgrades: Mostrar millores + showKeybindings: Mostrar dreceres de teclat + + importSavegameError: + title: Error en importar + text: >- + Failed to import your savegame: + + importSavegameSuccess: + title: Importar + text: >- + La partida ha sigut importada amb èxit. + + gameLoadFailure: + title: No es pot carregar la partida guardada + text: >- + Failed to load your savegame: + + confirmSavegameDelete: + title: Eliminar + text: >- + Estàs segur que vols eliminar la partida guardada? + + savegameDeletionError: + title: Error en eliminar + text: >- + Failed to delete the savegame: + + restartRequired: + title: Reiniciar + text: >- + És necessari reiniciar el joc per aplicar els canvis. + + editKeybinding: + title: Cambiar dreceres de teclat + desc: Pressiona la tecla o botó del ratolí que vols designar o ESC per cancel·lar. + + resetKeybindingsConfirmation: + title: Reiniciar dreceres de teclat + desc: Això reiniciarà tots els canvis realitzats, n'estàs segur? + + keybindingsResetOk: + title: Cambiar dreceres de teclat + desc: Les dreceres han tornat en el seu estat predeterminat! + + featureRestriction: + title: Demo - Versió de prova + desc: Has intentat accedir a una característica () que no està disponible en la demo. Considera obtenir el joc complet per a una experiència completa! + + oneSavegameLimit: + title: Partides guardades limitades + desc: Només pots tenir una sola partida guardada a la versió de demostració. Si vols, elimina la ja existent o fes-te amb la versió completa del joc! + + updateSummary: + title: Nova actualització! + desc: >- + Aquí tens els canvis des de l'últim cop que vas jugar: + + upgradesIntroduction: + title: Desbloquejar millora + desc: >- + Totes les figures poden ser usades per desbloquejar millores - No eliminis/es les teves fabriques anteriors! + La pestanya de millores està a la part superior dreta de la pantalla. + + massDeleteConfirm: + title: Eliminar edificis + desc: >- + Estàs esborrant molts edificis de cop ( per ser exactes)! Estàs segur que vols seguir? + + massCutConfirm: + title: Tallar edificis + desc: >- + Estàs esborrant molts edificis de cop ( per ser exactes)! Estàs segur que vols seguir? + + blueprintsNotUnlocked: + title: Encara no s'ha desbloquejat + desc: >- + Completa el nivell 12 per poder desbloquejar aquesta característica. + + keybindingsIntroduction: + title: Dreceres de teclat útils + desc: >- + El joc té moltes dreceres que faciliten la feina a l'hora de construir grans línies de producció. + Aquí tens algunes, però asegura't de revisar les dreceres de teclat!

+ CTRL + Arrossegar: Selecciona una àrea.
+ SHIFT: Mentè pressionat per col·locar vàries vegades el mateix edifici.
+ ALT: Invertir la orientació de les cintes transportadores ja col·locades.
+ + createMarker: + title: Nou Marcador + titleEdit: Edit Marker + desc: >- + Dona-li un nom significatiu, també pots usar claus de les figures (Pots generarles a: aquí) + + markerDemoLimit: + desc: En la Demo només pots crear dos marcadors, aconsegueix la versió completa per gaudir de l'experiència completa! + + exportScreenshotWarning: + title: Export screenshot + desc: Has demanat exportar la teva/teua base com una captura de pantalla. Tin en conte que aquest procés pot ser molt lent i inclús crashear el teu joc! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + +ingame: + # This is shown in the top left corner and displays useful keybindings in + # every situation + keybindingsOverlay: + moveMap: Moure + selectBuildings: Seleccionar àrea + stopPlacement: Parar de col·locar + rotateBuilding: Rotar edifici + placeMultiple: Col·locar múltiples + reverseOrientation: Invertir orientació + disableAutoOrientation: Desactivar autoorientació + toggleHud: Activar/Desactivar HUD + placeBuilding: Col·locar edifici + createMarker: Crear marcador + delete: Esborrar + pasteLastBlueprint: Apegar/Enganxar últim plànol + lockBeltDirection: Activar planificador de cintes + plannerSwitchSide: Emmirallar plànol + cutSelection: Tallar + copySelection: Copiar + clearSelection: Buidar selecció + pipette: Pipeta + switchLayers: Intercanviar capes + + # Names of the colors, used for the color blind mode + colors: + red: Roig + green: Verd + blue: Blau + yellow: Groc + purple: Morat + cyan: Cian + white: Blanc + uncolored: Sense color + black: Black + + # 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: Pulsa per a ciclar entre variants. + + # Shows the hotkey in the ui, e.g. "Hotkey: Q" + hotkeyLabel: >- + Hotkey: + infoTexts: + speed: Velocitat + range: Distància + storage: Emmagatzemament + oneItemPerSecond: 1 objecte / s + itemsPerSecond: objectes / s + itemsPerSecondDouble: (x2) + + tiles: caselles + + # The notification when completing a level + levelCompleteNotification: + # is replaced by the actual level, so this gets 'Level 03' for example. + levelTitle: Nivell + completed: Complet + unlockText: Desbloquejat ! + buttonNextLevel: Següent nivell + + # Notifications on the lower right + notifications: + newUpgrade: Una nova millora està disponible! + gameSaved: La teva/ua partida s'ha guardat. + + # The "Upgrades" window + shop: + title: Millores + buttonUnlock: Millorar + + # Gets replaced to e.g. "Tier IX" + tier: Nivell + + # The roman number for each tier + tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X] + + maximumLevel: NIVELL MÀXIM (Velocitat x) + + # The "Statistics" window + statistics: + title: Estadístiques + dataSources: + stored: + title: Emmagatzemat + description: Mostrant la quantitat de figures emmagatzemades en el teu edifici central. + produced: + title: Produit + description: Mostrant la producció total de figures de la fàbrica, incluïnt productes intermijos. + delivered: + title: Enviats + description: Mostrant les figures que són enviades a l'edifici central. + noShapesProduced: Ninguna figura s'ha produit fins ara. + + # Displays the shapes per minute, e.g. '523 / m' + shapesPerMinute: / m + + # Settings menu, when you press "ESC" + settingsMenu: + playtime: Temps de joc + + buildingsPlaced: Edificis + beltsPlaced: Cintes transportadores + + buttons: + continue: Continuar + settings: Configuració + menu: Tornar al menú + + # Bottom left tutorial hints + tutorialHints: + title: Necessites ajuda? + showHint: Mostrar pista + hideHint: Tancar + + # When placing a blueprint + blueprintPlacer: + cost: Cost + + # Map markers + waypoints: + waypoints: Marcadors + hub: NEXE + description: Fes clic esquerre en un marcador per desplaçar-te cap a ell. Fes clic dret per esborrar-lo.

Pressiona per a crear un marcador des de la vista actual, o fes clic dret per a crear un marcador en el punt seleccionat. + creationSuccessNotification: S'ha creat un marcador . + + # Shape viewer + shapeViewer: + title: Capes + empty: Buit + copyKey: Copiar clau + + # Interactive tutorial + interactiveTutorial: + title: Tutorial + hints: + 1_1_extractor: Col·loca un extractor damunt d'una figura circular per extraure-la! + 1_2_conveyor: >- + Connecta l'extractor a la cinta transportadora cap al teu nexe!

Pista: Pots clicar i arrossegar la cinta transportadora amb el teu ratolí! + 1_3_expand: >- + Aquest NO és un joc d'espera! Contrueix més extractors i cintes per a completar l'objectiu més ràpidament.

Pista: Manté pressionat SHIFT per a col·locar més extractors, i utilitza R per a rotar-los. +# All shop upgrades +shopUpgrades: + belt: + name: Cintes transportadores, Distribuidors i Túnels + description: Velocitat x → x + miner: + name: Extracció + description: Velocitat x → x + processors: + name: Tallar, Rotar i Apilar + description: Velocitat x → x + painting: + name: Mesclar i Pintar + description: Velocitat x → x + +# Buildings and their name / description +buildings: + hub: + deliver: Envia + toUnlock: per a desbloquejar + levelShortcut: NVL + + belt: + default: + name: &belt Cinta transportadora + description: Transporta objectes, mantén pressionat i arrossega per a col·locar múltiples. + + wire: + default: + name: &wire Cable + description: Permet transportar energia. + + miner: # Internal name for the Extractor + default: + name: &miner Extractor + description: Posa-ho damunt d'una font de figures o colors per extraure'ls. + + chainable: + name: Extractor (Cadena) + description: Posa-ho damunt d'una font de figures o colors per extraure'ls. Pot ser encadenat! + + underground_belt: # Internal name for the Tunnel + default: + name: &underground_belt Túnel + description: Permet transportar recursos per sota d'edificis i cintes. + + tier2: + name: Túnel de Nivell II + description: Permet transportar recursos per sota d'edificis i cintes. + + splitter: # Internal name for the Balancer + default: + name: &splitter Distribuïdor + description: Multifuncional - Distribueix les entrades i sortides equitativament. + + compact: + name: Fusionador (compacte) + description: Fusiona dos cintes en una. + + compact-inverse: + name: Fusionador (compacte) + description: Fusiona dos cintes en una. + + cutter: + default: + name: &cutter Cisalla + description: Talla figures de dalt a baix i produeix les dues meitats. Si utilitzes sols una part, assegura't de destruir l'altra o es pararà! + quad: + name: Cisalla (Quàdruple) + description: Talla figures en quatre parts. Si no utilitzes totes les parts, assegura't de destruir les altres o es pararà! + + advanced_processor: + default: + name: &advanced_processor Processador avançat + description: Processament de figures avançat. + + rotater: + default: + name: &rotater Rotador + description: Rota formes en sentit horari 90 graus. + ccw: + name: Rotador (Antihorari) + description: Rota formes en sentit antihorari 90 graus. + + stacker: + default: + name: &stacker Apilador + description: Fusiona o apila ambdues figures. Si no poden ser fusionades, la figura de la dreta es posarà damunt de la de l'esquerra. + + mixer: + default: + name: &mixer Mesclador de colors + description: Mescla dos colors amb mescla additiva. + + painter: + default: + name: &painter Pintor + description: &painter_desc Pinta la figura sencera de l'esquerra amb el color de l'entrada de dalt. + + mirrored: + name: Pintor + description: Pinta la figura sencera de l'esquerra amb el color de l'entrada de baix. + + double: + name: Pintor (Doble) + description: Pinta les figures de l'esquerra amb el color de dalt. + quad: + name: Pintor (Quàdruple) + description: Permet pintar cadascun dels quadrants de forma diferent. + + trash: + default: + name: &trash Paperera + description: Acepta objectes de tots els costats i els destrueix. Permanentment. + + storage: + name: Magatzem + description: Emmagatzema objectes en excés, fins a una capacitat màxima. Es pot utilitzar com a control d'excedents. + + energy_generator: + deliver: Envia + + # This will be shown before the amount, so for example 'For 123 Energy' + toGenerateEnergy: Per a + + default: + name: &energy_generator Generador d'energia + description: Genera energia consumint figures. Cada generador requereix una figura diferent. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. + +storyRewards: + # Those are the rewards gained from completing the store + reward_cutter_and_trash: + title: Tallar figures + desc: Acabes de desbloquejar la Cisalla - talla les figures per la meitat de dalt a baix; sense importar la seva/ua orientació!

Assegura't d'eliminar les parts que no utilitzes, si no es pararà - Es per això que t'he donat una paperera, utilitza-la! + + reward_rotater: + title: Rotar + desc: El Rotador s'ha desbloquejat! Rota formes en sentit horari 90 graus. + + reward_painter: + title: Pintar + desc: >- + El Pintor s'ha desbloquejat! - Extreu mena de color (de la mateixa forma que les figures) i pinta les figures amb el pintor!

- Si ets daltònic, pots activar l'opció per daltònics en les opcions! + + reward_mixer: + title: Mesclar colors + desc: El Mesclador de colors s'ha desbloquejat! - Combina dos colors utilitzant la mescla additiva amb aquest edifici! + + reward_stacker: + title: Apilador + desc: Ara pots combinar figures amb el apilador! Ambdues entrades són combinades. Si es poden posar una vora l'altra, es fusionaran. Si no, l'entrada de la dreta s'apilarà damunt de la de l'esquerra! + + reward_splitter: + title: Distribuïdor + desc: El distribuïdor multifuncional s'ha desbloquejat - Pot ser utilitzat per a construir fàbriques més grans per mitjà de la separació i fusió de figures de diferents cintes!

+ + reward_tunnel: + title: Túnel + desc: El túnel s'ha desbloquejat - Ara pots passar objectes a través d'edificis i cintes transportadores! + + reward_rotater_ccw: + title: Rotació antihorària + desc: Has desbloquejat una variant del rotador - Et permet rotar en sentit antihorari! Per tal de construir-lo, selecciona el rotador i pressiona 'T' per a ciclar les diferents variants! + + reward_miner_chainable: + title: Extractor en cadena + desc: Has desbloquejat el extractor en cadena! Pot passar els seus recursos a altres extractors perquè pugues extraure recursos més eficientment! + + reward_underground_belt_tier_2: + title: Túnel de Nivell II + desc: Has desbloquejat una nova variant del túnel - Té una major distància màxima, i ara pots mesclar tipus de túnels! + + reward_splitter_compact: + title: Distribuïdor compacte + desc: >- + Has desbloquejat una variant compacta del distribuïdor - Acepta dues entrades i les fusiona en una sola! + reward_cutter_quad: + title: Cisalla quàdruple + desc: Has desbloquejat una variant de la cisalla - Et permet tallar figures en quatre parts en lloc de sols en dos! + + reward_painter_double: + title: Pintor doble + desc: Has desbloquejat una variant del pintor - Funciona com el pintor regular però processa dos figures alhora, consumint sols un color en lloc de dos! + + reward_painter_quad: + title: Pintor quàdruple + desc: Has desbloquejat una variant del pintor - Et permet pintar cada part de la figura individualment! + + reward_storage: + title: Magatzem de reserva + desc: Has desbloquejat una variant de la paperera - Et permet emmagatzemar objectes fins a una capacitat màxima! + + reward_freeplay: + title: Joc lliure + desc: Ho has fet! Has desbloquejat el mode de joc lliure! Això significa que les figures ara són generades aleatòriament! (No t'angoixis/es, hi ha més contingut planejat per a la versió completa - fora del web) + + reward_blueprints: + title: Plànols + desc: Ara pots copiar i apegar/enxegar parts de la teva/ua fàbrica! Selecciona una àrea (Mantén pressionat CTRL, i arrossega el ratolí), i pressiona 'C' per a copiar-la.

Apegar/enxegar-la no és gratis, necessites produir figures de plànols per a poder fer-ho! (Les que n'acabes d'enviar). + + # Special reward, which is shown when there is no reward actually + no_reward: + title: Següent nivell + desc: >- + Aquest nivell no t'ha donat res, però el següent ho farà!

PD: És millor que no destrueixes la part de la fàbrica existent - Necessitaràs totes aquestes figures més tard per a desbloquejar millores! + + no_reward_freeplay: + title: Següent nivell + desc: >- + Enhorabona! Per cert, hi ha més contingut planejat per a la versió completa - fora del web! + +settings: + title: Opcions + categories: + game: Joc + app: Aplicació + + versionBadges: + dev: Desenvolupament + staging: Staging + prod: Producció + buildDate: Generat + + labels: + uiScale: + title: Escala de la interfície + description: >- + Canvia la dimensió de la interfície de l'usuari. La interfície se seguirà redimensionant depenent de la resolució del teu dispositiu, però aquesta opció controla la quantitat del redimensionat. + scales: + super_small: Micro + small: Petit + regular: Estàndard + large: Gran + huge: Macro + + autosaveInterval: + title: Interval de guardat automàtic + description: >- + Controla el temps entre guardats automàtics que fa el joc, pots deshabilitar-ho des d'aquí + intervals: + one_minute: 1 Minut + two_minutes: 2 Minuts + five_minutes: 5 Minuts + ten_minutes: 10 Minuts + twenty_minutes: 20 Minuts + disabled: Desactivat + + scrollWheelSensitivity: + title: Zoom sensitivity + description: >- + Changes how sensitive the zoom is (Either mouse wheel or trackpad). + sensitivity: + super_slow: Super slow + slow: Slow + regular: Regular + fast: Fast + super_fast: Super fast + + movementSpeed: + title: Movement speed + description: >- + Changes how fast the view moves when using the keyboard. + speeds: + super_slow: Super slow + slow: Slow + regular: Regular + fast: Fast + super_fast: Super Fast + extremely_fast: Extremely Fast + + language: + title: Language + description: >- + Change the language. All translations are user contributed and might be incomplete! + enableColorBlindHelper: + title: Color Blind Mode + description: >- + Enables various tools which allow to play the game if you are color blind. + fullscreen: + title: Fullscreen + description: >- + It is recommended to play the game in fullscreen to get the best experience. Only available in the standalone. + soundsMuted: + title: Mute Sounds + description: >- + If enabled, mutes all sound effects. + musicMuted: + title: Mute Music + description: >- + If enabled, mutes all music. + theme: + title: Game theme + description: >- + Choose the game theme (light / dark). + themes: + dark: Dark + light: Light + + refreshRate: + title: Simulation Target + description: >- + If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates. This might actually decrease the FPS if your computer is too slow. + alwaysMultiplace: + title: Multiplace + description: >- + If enabled, all buildings will stay selected after placement until you cancel it. This is equivalent to holding SHIFT permanently. + offerHints: + title: Hints & Tutorials + description: >- + 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. + enableTunnelSmartplace: + title: Smart Tunnels + description: >- + When enabled, placing tunnels will automatically remove unnecessary belts. This also enables to drag tunnels and excess tunnels will get removed. + vignette: + title: Vignette + description: >- + Enables the vignette which darkens the screen corners and makes text easier to read. + rotationByBuilding: + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. This may be more comfortable if you frequently switch between placing different building types. + compactBuildingInfo: + title: Compact Building Infos + description: >- + Shortens info boxes for buildings by only showing their ratios. Otherwise a description and image is shown. + disableCutDeleteWarnings: + title: Disable Cut/Delete Warnings + description: >- + Disable the warning dialogs brought up when cutting/deleting more than 100 entities. +keybindings: + title: Keybindings + hint: >- + Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different placement options. + resetKeybindings: Reset Keybindings + + categoryLabels: + general: Application + ingame: Game + navigation: Navigating + placement: Placement + massSelect: Mass Select + buildings: Building Shortcuts + placementModifiers: Placement Modifiers + + mappings: + confirm: Confirm + back: Back + mapMoveUp: Move Up + mapMoveRight: Move Right + mapMoveDown: Move Down + mapMoveLeft: Move Left + mapMoveFaster: Move Faster + centerMap: Center Map + + mapZoomIn: Zoom in + mapZoomOut: Zoom out + createMarker: Create Marker + + menuOpenShop: Upgrades + menuOpenStats: Statistics + + toggleHud: Toggle HUD + toggleFPSInfo: Toggle FPS and Debug Info + switchLayers: Switch layers + exportScreenshot: Export whole Base as Image + belt: *belt + splitter: *splitter + underground_belt: *underground_belt + miner: *miner + cutter: *cutter + advanced_processor: *advanced_processor + rotater: *rotater + stacker: *stacker + mixer: *mixer + energy_generator: *energy_generator + painter: *painter + trash: *trash + wire: *wire + + pipette: Pipette + rotateWhilePlacing: Rotate + rotateInverseModifier: >- + Modifier: Rotate CCW instead + cycleBuildingVariants: Cycle Variants + confirmMassDelete: Delete area + pasteLastBlueprint: Paste last blueprint + cycleBuildings: Cycle Buildings + lockBeltDirection: Enable belt planner + switchDirectionLockSide: >- + Planner: Switch side + massSelectStart: Hold and drag to start + massSelectSelectMultiple: Select multiple areas + massSelectCopy: Copy area + massSelectCut: Cut area + + placementDisableAutoOrientation: Disable automatic orientation + placeMultiple: Stay in placement mode + placeInverse: Invert automatic belt orientation + menuClose: Close Menu + +about: + title: About this Game + body: >- + This game is open source and developed by Tobias Springer (this is me).

+ If you want to contribute, check out shapez.io on github.

+ This game wouldn't have been possible without the great discord community around my games - You should really join the discord server!

+ The soundtrack was made by Peppsen - He's awesome.

+ Finally, huge thanks to my best friend Niklas - Without our factorio sessions this game would never have existed. +changelog: + title: Changelog + +demo: + features: + restoringGames: Restoring savegames + importingGames: Importing savegames + oneGameLimit: Limited to one savegame + customizeKeybindings: Customizing Keybindings + exportingBase: Exporting whole Base as Image + + settingNotAvailable: Not available in the demo. diff --git a/translations/base-cz.yaml b/translations/base-cz.yaml index dd34958c..e722a7ee 100644 --- a/translations/base-cz.yaml +++ b/translations/base-cz.yaml @@ -11,42 +11,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io je hra o stavbě továren pro automatizaci výroby a kombinování tvarů. Poskytněte vyžadované, stále složitější tvary, aby jste postoupili ve hře dále, a odemkněte vylepšení pro zrychlení vaší továrny. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Protože poptávka postupně roste, musíte svou továrnu rozšiřovat tak, aby vyhověla potřebám - Nové zdroje, najdete na [b]nekonečné mapě[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Jen tvary by byly nuda, proto máme pigmenty kterými musíte dílky obarvit - zkombinujte červené, zelené a modré barvivo pro vytvoření dalších odstínů a obarvěte s nimi tvary pro uspokojení poptávky. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - Hra obsahuje 18 úrovní (což by vás mělo zaměstnat na spoustu hodin!), ale nový obsah je neustále přidáván - je toho hodně naplánováno! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]Výhody plné hry[/b] + [b]Standalone Advantages[/b] [list] - [*] Označování pozic na mapě - [*] Neomezený počet uložených her - [*] Tmavý motiv - [*] Více nastavení - [*] Pomůžete mi dále vyvíjet shapez.io ❤️ - [*] Více funkcí v budoucnu! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Plánované funkce a komunitní návrhy[/b] + [b]Future Updates[/b] - Tato hra je open source - kdokoli může přispět! Kromě toho [b]hodně[/b] poslouchám komunitu! Snažím se přečíst si všechny návrhy a vzít v úvahu zpětnou vazbu. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Mód s příběhem, kde stavba budov stojí tvary - [*] Více úrovní a budov (exkluzivní pro plnou verzi) - [*] Různé mapy a zábrany na mapě - [*] Konfigurace generátoru map (úprava počtu a velikosti nálezišť, seed map, a další) - [*] Více tvarů - [*] Další zlepšení výkonu (I když hra již běží docela dobře!) - [*] Režim pro barvoslepé - [*] A mnohem více! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - Nezapomeňte se podívat na moji Trello nástěnku pro úplný plán! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Načítám @@ -55,6 +72,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: " " + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -112,28 +132,7 @@ mainMenu: savegameLevel: Úroveň savegameLevelUnknown: Neznámá úroveň - contests: - contest_01_03062020: - title: "Soutěž #01" - desc: Vyhraj $25 za nejvíc cool základnu! - longDesc: >- - Abych vám poděkoval, myslel jsem, že by bylo skvělé dělat týdenní soutěže! -

- Téma tohoto týdne: Postavte nejvíc cool základnu! -

- Zde je zadání:
-
    -
  • Zašlete screenshot své základny na contest@shapez.io
  • -
  • Bonusové body za sdílení na sociálních médiích!
  • -
  • Vyberu 5 screenshotů a Discord komunita bude hlasovat o vítězi.
  • -
  • Vítěz dostane $25 (Paypal, Amazon Dárkový Poukaz, co preferujete)
  • -
  • Uzávěrka: 07.06.2020 12:00 CEST
  • -
-
- Těším se na vaše úžasné výtvory! - showInfo: Zobrazit - contestOver: Tato soutěž skončila - Připojte se na Discord a získejte informace o nových soutěžích! continue: Pokračovat newGame: Nová hra madeBy: Vytvořil @@ -236,6 +235,7 @@ dialogs: createMarker: title: Nová značka desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker markerDemoLimit: desc: V ukázce můžete vytvořit pouze dvě značky. Získejte plnou verzi pro neomezený počet značek! @@ -251,6 +251,10 @@ dialogs: Zažádal jsi o exportování své základny jako obrázek. Měj prosím na paměti, že to může zejména u větších základen dlouho trvat, nebo dokonce shodit hru! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -273,6 +277,7 @@ ingame: copySelection: Kopířovat clearSelection: Zrušit výběr pipette: Kapátko + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -388,9 +393,11 @@ ingame: cyan: Tyrkysová white: Bílá uncolored: Bez barvy + black: Black shapeViewer: title: Vrstvy empty: Prázdné + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -498,6 +505,27 @@ buildings: storage: name: Sklad description: Skladuje věci navíc až do naplnění kapacity. Může být použit na skladování surovin navíc. + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -709,11 +737,11 @@ settings: title: Režim pro barvoslepé description: Zapné různé nástroje, které vám umožní hrát hru i pokud jste barvoslepí. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. + This may be more comfortable if you frequently switch between placing + different building types. keybindings: title: Klávesové zkratky @@ -781,6 +809,11 @@ keybindings: lockBeltDirection: Zamknout směr pásu switchDirectionLockSide: Otočit strany zámku plánovače pipette: Kapátko + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: O hře diff --git a/translations/base-da.yaml b/translations/base-da.yaml index 930e5f29..a87f7587 100644 --- a/translations/base-da.yaml +++ b/translations/base-da.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Unlimited Savegames [*] Dark Mode - [*] More settings - [*] Allow me to further develop shapez.io ❤️ - [*] More features in the future! + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - This game is open source - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story mode where buildings cost shapes - [*] More levels & buildings (standalone exclusive) - [*] Different maps, and maybe map obstacles - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] More types of shapes - [*] More performance improvements (Although the game already runs pretty good!) - [*] Color blind mode + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Loading @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -135,28 +155,7 @@ mainMenu: savegameLevel: Level savegameLevelUnknown: Unknown Level - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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: @@ -260,6 +259,7 @@ dialogs: createMarker: title: New Marker desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker markerDemoLimit: desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! @@ -267,6 +267,9 @@ dialogs: exportScreenshotWarning: title: Export screenshot desc: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? ingame: # This is shown in the top left corner and displays useful keybindings in @@ -302,6 +305,7 @@ ingame: cyan: Cyan white: White uncolored: No color + black: Black # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -530,6 +534,21 @@ buildings: default: name: &energy_generator Energy Generator description: Generates energy by consuming shapes. Each energy generator requires a different shapes. + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -609,10 +628,6 @@ storyRewards: desc: >- This level gave you no reward, but the next one will!

PS: Better don't destroy your existing factory - You need all those shapes later again to unlock upgrades! - reward_wires: - title: Wires - desc: TODO - no_reward_freeplay: title: Next level desc: >- @@ -820,6 +835,9 @@ keybindings: placementDisableAutoOrientation: Disable automatic orientation placeMultiple: Stay in placement mode placeInverse: Invert automatic belt orientation + menuClose: Close Menu + advanced_processor: Color Inverter + wire: Energy Wire about: title: About this Game diff --git a/translations/base-de.yaml b/translations/base-de.yaml index 057020ea..eac6ae23 100644 --- a/translations/base-de.yaml +++ b/translations/base-de.yaml @@ -21,7 +21,10 @@ steamPage: # This is the short text appearing on the steam page - shortText: shapez.io ist ein Spiel über den Bau von Fabriken, um die Erstellung und Kombination immer komplexerer Formen zu automatisieren. + shortText: In shapez.io nutzt du die vorhandenen Ressourcen, um mit deinen Maschinen durch Kombination immer komplexere Formen zu erschaffen. + + # This is the text shown above the discord link + discordLink: Offizieller Discord - Hier kannst du mit mir schreiben! # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. # NOTICE: @@ -30,42 +33,57 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io ist ein Spiel über den Bau von Fabriken um die Erstellung und Kombination von Formen zu automatisieren. Liefere die gewünschten, stetig komplexer werdenden Formen, um im Spiel voranzukommen und schalte Upgrades frei, die deine Fabrik zu beschleunigen! + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Da die Nachfrage steigt, wirst du deine Fabrik vergrößern müssen, um den Bedürfnissen gerecht zu werden - vergiss jedoch nicht die Ressourcen, du wirst in der [b]unendlichen Karte[/b] expandieren müssen! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Da Formen natürlich langweilig werden können, musst du Farben mischen und deine Formen damit bemalen - Kombiniere rote, grüne und blaue Farbressourcen, um verschiedene Farben herzustellen und Formen damit zu bemalen, um die Nachfrage zu befriedigen. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - Dieses Spiel hat 18 verschiedene Level (Was dich schon Stunden beschäftig hält!) aber ich werde konstant neue Inhalte hinzufügen - Es ist echt viel geplant! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! - [b]Vorteile der Standalone[/b] + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. + + [b]Standalone Advantages[/b] [list] - [*] Wegpunkte - [*] Unbegrenzte Anzahl von Spielständen - [*] Dark-Mode - [*] Mehr Einstellungen - [*] Erlaube es mir weiter an shapez.io zu entwickeln ❤️ - [*] Mehr Funktionen in der Zukunft! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Geplante Funktionen & Community Vorschläge[/b] + [b]Future Updates[/b] - Diese Spiel ist open source - Jeder kann dazu beitragen! Abgesehen davon höre ich auf die Community! Ich versuche alle Vorschläge zu lesen und so viel Feedback einzubeziehen wie nur möglich. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story-Modus, in dem Gebäude Formen kosten - [*] Mehr Gebäude und Level (nur in der Standalone-Version) - [*] Mehr Karten und vielleicht auch Hindernisse - [*] Einstellbare Kartenerstellung (Ändere die Grösse und Anzahl von Ressourcenflecken, Seed, und mehr) - [*] Mehr Typen von Formen - [*] Mehr Performanceverbesserungen (Auch wenn das Spiel bereits ganz gut läuft) - [*] Farbenblind-Modus - [*] Und viel mehr! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - Schau dir auch das Trello-board für die komplette Planung an! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] global: loading: Laden error: Fehler @@ -73,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "." + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "," + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -129,28 +150,7 @@ mainMenu: savegameLevel: Level savegameLevelUnknown: Unbekanntes Level - contests: - contest_01_03062020: - title: "Contest #01" - desc: Gewinne $25 für die beste Basis! - longDesc: >- - Um euch etwas zurückzugeben dachte ich, dass es eine coole Idee ist, wöchentliche Wettbewerbe durchzuführen! -

- Thema dieser Woche: Baue die coolste Basis! -

- Hier ist ein Deal:
-
    -
  • Sende einen Screenshot deiner Basis an contest@shapez.io
  • -
  • Bonuspunkte wenn du die Basis auf sozialen Medien teilst!
  • -
  • Ich wähle 5 Screenshots und schlage dieser der Community auf Discord vor, um abzustimmen.
  • -
  • Der Gewinner bekommt $25 (Paypal, Amazon Gift Card, was du willst)
  • -
  • Einsendeschluss: 07.06.2020 12:00 AM CEST
  • -
-
- Ich freue mich deine tollen Kreationen zu sehen! - showInfo: Anschauen - contestOver: Dieser Wettbewerb ist vorbei! Tritt dem Discord Server bei, um über neue Wettbewerbe informiert zu werden! helpTranslate: Hilf beim Übersetzen! continue: Fortsetzen newGame: Neues Spiel @@ -203,7 +203,7 @@ dialogs: editKeybinding: title: Tastenbelegung ändern - desc: Drücke die Taste oder Maustaste, die du vergeben willst, oder ESC um abzubrechen. + desc: Drücke die (Maus-)Taste, die du vergeben willst, oder ESC um abzubrechen. resetKeybindingsConfirmation: title: Tastenbelegung zurücksetzen @@ -214,7 +214,7 @@ dialogs: desc: Die Tastenbelegung wurde auf den Standard zurückgesetzt! featureRestriction: - title: Demo Version + title: Demo-Version desc: Du hast ein Feature gefunden (), welches nicht in der Demo enthalten ist. Erwerbe die Standalone für das volle Erlebnis! oneSavegameLimit: @@ -254,6 +254,7 @@ dialogs: createMarker: title: Neuer Marker desc: Gib ihm einen griffigen Namen. Du kannst sogar die Abkürzung einer Form eingeben (Diese kann hier generiert werden). + titleEdit: Edit Marker markerDemoLimit: desc: Du kannst nur 2 benutzerdefinierte Marker in der Demo benutzen. Hol dir die Standalone, um unendlich viele Marker zu erstellen! @@ -267,6 +268,10 @@ dialogs: desc: >- Hier kannst du ein Bildschirmfoto von deiner ganzen Fabrik erstellen. Für extrem große Fabriken kann das jedoch sehr lange dauern und ggf. zum Spielabsturz führen! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -289,6 +294,7 @@ ingame: copySelection: Kopieren clearSelection: Auswahl aufheben pipette: Pipette + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -346,7 +352,7 @@ ingame: description: Zeigt die Menge an Formen, die im zentralen Gebäude gelagert sind. produced: title: Produziert - description: Zeigt die Menge an Formen, die deine ganze Fabrik produziert (auch Zwischenprodukte). + description: Zeigt die Menge an Formen, die deine gesamte Fabrik produziert (inkl. Zwischenprodukte). delivered: title: Abgeliefert description: Zeigt die Menge an Formen, die im zentralen Gebäude abgeliefert werden. @@ -404,9 +410,11 @@ ingame: cyan: Cyan white: Weiß uncolored: Farblos + black: Black shapeViewer: title: Ebenen empty: Leer + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -518,6 +526,27 @@ buildings: toUnlock: >- Für folgende Belohnung: levelShortcut: LVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -663,7 +692,7 @@ settings: refreshRate: title: Zielbildwiederholrate description: >- - Für z.B einen 144-Hz-Monitor kann die Bildwiederholrate hier korrekt eingestellt werden. Bei einem zu langsamen Computer kann dies die Leistung beeinträchtigen. + Für z.B. einen 144-Hz-Monitor kann die Bildwiederholrate hier korrekt eingestellt werden. Bei einem zu langsamen Computer kann dies die Leistung beeinträchtigen. alwaysMultiplace: title: Mehrfachplatzierung @@ -729,11 +758,11 @@ settings: title: Modus für Farbenblinde description: Aktiviert verschiedene Werkzeuge, die dir das Spielen trotz Farbenblindheit ermöglichen. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation pro Gebäudetyp + description: >- + Jeder Gebäudetyp merkt sich einzeln, welche Rotation ausgewählt ist. + Das fühlt sich möglicherweise besser an, wenn du häufig zwischen verschiedenen + Gebäudetypen wechselst. keybindings: title: Tastenbelegung @@ -801,6 +830,11 @@ keybindings: lockBeltDirection: Bandplaner aktivieren switchDirectionLockSide: "Planer: Seite wechseln" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: Über dieses Spiel diff --git a/translations/base-el.yaml b/translations/base-el.yaml index 3b7bec15..90430f6a 100644 --- a/translations/base-el.yaml +++ b/translations/base-el.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Unlimited Savegames [*] Dark Mode - [*] More settings - [*] Allow me to further develop shapez.io ❤️ - [*] More features in the future! + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - This game is open source - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story mode where buildings cost shapes - [*] More levels & buildings (standalone exclusive) - [*] Different maps, and maybe map obstacles - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] More types of shapes - [*] More performance improvements (Although the game already runs pretty good!) - [*] Color blind mode + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Loading @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -131,28 +151,7 @@ mainMenu: savegameLevel: Level savegameLevelUnknown: Unknown Level - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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! continue: Continue newGame: New Game madeBy: Made by @@ -255,6 +254,7 @@ dialogs: createMarker: title: New Marker desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker markerDemoLimit: desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! @@ -270,6 +270,10 @@ dialogs: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -292,6 +296,7 @@ ingame: copySelection: Copy clearSelection: Clear Selection pipette: Pipette + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -407,9 +412,11 @@ ingame: cyan: Cyan white: White uncolored: No color + black: Black shapeViewer: title: Layers empty: Empty + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -517,6 +524,27 @@ buildings: deliver: Deliver toUnlock: to unlock levelShortcut: LVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -730,11 +758,11 @@ settings: title: Color Blind Mode description: Enables various tools which allow to play the game if you are color blind. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. + This may be more comfortable if you frequently switch between placing + different building types. keybindings: title: Keybindings @@ -802,6 +830,11 @@ keybindings: lockBeltDirection: Enable belt planner switchDirectionLockSide: "Planner: Switch side" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: About this Game diff --git a/translations/base-en.yaml b/translations/base-en.yaml index 930e5f29..64b1777a 100644 --- a/translations/base-en.yaml +++ b/translations/base-en.yaml @@ -21,7 +21,10 @@ steamPage: # This is the short text appearing on the steam page - shortText: shapez.io is a game about building factories to automate the creation and combination of increasingly complex shapes within an infinite map. + shortText: shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + + # This is the text shown above the discord link + discordLink: Official Discord - Chat with me! # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. # NOTICE: @@ -30,42 +33,58 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + Upon delivering the requested shapes you'll progress within the game and unlock upgrades to speed up your factory. - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + As the demand for shapes increases, you'll have to scale up your factory to meet the demand - Don't forget about resources though, you'll have to expand across the [b]infinite map[/b]! - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Soon you'll have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with them to satisfy the demand. + This game features 18 progressive levels (Which should already keep you busy for hours!) but I'm constantly adding new content - There's a lot planned! + + Purchasing the game gives you access to the standalone version which has additional features, and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Unlimited Savegames [*] Dark Mode - [*] More settings - [*] Allow me to further develop shapez.io ❤️ - [*] More features in the future! + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - This game is open source - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game often and trying to push an update at least once every week! [list] - [*] Story mode where buildings cost shapes - [*] More levels & buildings (standalone exclusive) - [*] Different maps, and maybe map obstacles - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] More types of shapes - [*] More performance improvements (Although the game already runs pretty good!) - [*] Color blind mode + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] global: loading: Loading @@ -74,6 +93,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -135,29 +157,6 @@ mainMenu: savegameLevel: Level savegameLevelUnknown: Unknown Level - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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 @@ -167,7 +166,7 @@ dialogs: restart: Restart reset: Reset getStandalone: Get Standalone - deleteGame: I know what I do + deleteGame: I know what I am doing viewUpdate: View Update showUpgrades: Show Upgrades showKeybindings: Show Keybindings @@ -216,11 +215,11 @@ dialogs: featureRestriction: title: Demo Version - desc: You tried to access a feature () which is not available in the demo. Consider to get the standalone for the full experience! + desc: You tried to access a feature () which is not available in the demo. Consider getting the standalone version for the full experience! oneSavegameLimit: title: Limited savegames - desc: You can only have one savegame at a time in the demo version. Please remove the existing one or get the standalone! + desc: You can only have one savegame at a time in the demo version. Please remove the existing one or get the standalone version! updateSummary: title: New update! @@ -243,6 +242,11 @@ dialogs: desc: >- You are cutting a lot of buildings ( to be exact)! Are you sure you want to do this? + massCutInsufficientConfirm: + title: Confirm cut + desc: >- + You can not afford to paste this area! Are you sure you want to cut it? + blueprintsNotUnlocked: title: Not unlocked yet desc: >- @@ -259,6 +263,7 @@ dialogs: createMarker: title: New Marker + titleEdit: Edit Marker desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) markerDemoLimit: @@ -278,19 +283,19 @@ ingame: rotateBuilding: Rotate building placeMultiple: Place multiple reverseOrientation: Reverse orientation - disableAutoOrientation: Disable auto orientation + disableAutoOrientation: Disable auto-orientation toggleHud: Toggle HUD placeBuilding: Place building - createMarker: Create Marker + createMarker: Create marker delete: Delete pasteLastBlueprint: Paste last blueprint lockBeltDirection: Enable belt planner plannerSwitchSide: Flip planner side cutSelection: Cut copySelection: Copy - clearSelection: Clear Selection + clearSelection: Clear selection pipette: Pipette - switchLayers: Switch Layers + switchLayers: Switch layers # Names of the colors, used for the color blind mode colors: @@ -301,7 +306,8 @@ ingame: purple: Purple cyan: Cyan white: White - uncolored: No color + black: Black + uncolored: Gray # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -441,6 +447,11 @@ buildings: name: &belt Conveyor Belt description: Transports items, hold and drag to place multiple. + wire: + default: + name: &wire Energy Wire + description: Allows you to transport energy. + miner: # Internal name for the Extractor default: name: &miner Extractor @@ -453,11 +464,11 @@ buildings: underground_belt: # Internal name for the Tunnel default: name: &underground_belt Tunnel - description: Allows to tunnel resources under buildings and belts. + description: Allows you to tunnel resources under buildings and belts. tier2: name: Tunnel Tier II - description: Allows to tunnel resources under buildings and belts. + description: Allows you to tunnel resources under buildings and belts. splitter: # Internal name for the Balancer default: @@ -475,18 +486,23 @@ buildings: cutter: default: name: &cutter Cutter - description: Cuts shapes from top to bottom and outputs both halfs. If you use only one part, be sure to destroy the other part or it will stall! + description: Cuts shapes from top to bottom and outputs both halves. If you use only one part, be sure to destroy the other part or it will stall! quad: name: Cutter (Quad) description: Cuts shapes into four parts. If you use only one part, be sure to destroy the other parts or it will stall! + advanced_processor: + default: + name: &advanced_processor Color Inverter + description: Accepts a color or shape and inverts it. + rotater: default: name: &rotater Rotate description: Rotates shapes clockwise by 90 degrees. ccw: name: Rotate (CCW) - description: Rotates shapes counter clockwise by 90 degrees. + description: Rotates shapes counter-clockwise by 90 degrees. stacker: default: @@ -512,7 +528,7 @@ buildings: description: Colors the shapes on the left inputs with the color from the top input. quad: name: Painter (Quad) - description: Allows to color each quadrant of the shape with a different color. + description: Allows you to color each quadrant of the shape with a different color. trash: default: @@ -525,11 +541,22 @@ buildings: energy_generator: deliver: Deliver - toGenerateEnergy: For energy + + # This will be shown before the amount, so for example 'For 123 Energy' + toGenerateEnergy: For default: name: &energy_generator Energy Generator - description: Generates energy by consuming shapes. Each energy generator requires a different shapes. + description: Generates energy by consuming shapes. + + wire_crossings: + default: + name: &wire_crossings Wire Splitter + description: Splits a energy wire into two. + + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -544,7 +571,7 @@ storyRewards: reward_painter: title: Painting desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a colorblind mode in the settings! reward_mixer: title: Color Mixing @@ -564,7 +591,7 @@ storyRewards: reward_rotater_ccw: title: CCW Rotating - desc: You have unlocked a variant of the rotater - It allows to rotate counter clockwise! To build it, select the rotater and press 'T' to cycle its variants! + desc: You have unlocked a variant of the rotater - It allows you to rotate shapes counter-clockwise! To build it, select the rotater and press 'T' to cycle through its variants! reward_miner_chainable: title: Chaining Extractor @@ -577,7 +604,7 @@ storyRewards: reward_splitter_compact: title: Compact Balancer desc: >- - You have unlocked a compact variant of the balancer - It accepts two inputs and merges them into one! + You have unlocked a compact variant of the balancer - It accepts two inputs and merges them into one belt! reward_cutter_quad: title: Quad Cutting @@ -589,11 +616,11 @@ storyRewards: reward_painter_quad: title: Quad Painting - desc: You have unlocked a variant of the painter - It allows to paint each part of the shape individually! + desc: You have unlocked a variant of the painter - It allows you to paint each part of the shape individually! reward_storage: title: Storage Buffer - desc: You have unlocked a variant of the trash - It allows to store items up to a given capacity! + desc: You have unlocked a variant of the trash - It allows you to store items up to a given capacity! reward_freeplay: title: Freeplay @@ -609,10 +636,6 @@ storyRewards: desc: >- This level gave you no reward, but the next one will!

PS: Better don't destroy your existing factory - You need all those shapes later again to unlock upgrades! - reward_wires: - title: Wires - desc: TODO - no_reward_freeplay: title: Next level desc: >- @@ -634,7 +657,7 @@ settings: uiScale: title: Interface scale description: >- - Changes the size of the user interface. The interface will still scale based on your device resolution, but this setting controls the amount of scale. + Changes the size of the user interface. The interface will still scale based on your device's resolution, but this setting controls the amount of scaling. scales: super_small: Super small small: Small @@ -681,12 +704,12 @@ settings: language: title: Language description: >- - Change the language. All translations are user contributed and might be incomplete! + Change the language. All translations are user-contributed and might be incomplete! enableColorBlindHelper: title: Color Blind Mode description: >- - Enables various tools which allow to play the game if you are color blind. + Enables various tools which allow you to play the game if you are color blind. fullscreen: title: Fullscreen @@ -724,17 +747,17 @@ settings: offerHints: title: Hints & Tutorials description: >- - 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. + Whether to offer hints and tutorials while playing. Also hides certain UI elements up to a given level to make it easier to get into the game. enableTunnelSmartplace: title: Smart Tunnels description: >- - When enabled, placing tunnels will automatically remove unnecessary belts. This also enables to drag tunnels and excess tunnels will get removed. + When enabled, placing tunnels will automatically remove unnecessary belts. This also enables you to drag tunnels and excess tunnels will get removed. vignette: title: Vignette description: >- - Enables the vignette which darkens the screen corners and makes text easier to read. + Enables the vignette, which darkens the screen corners and makes text easier to read. rotationByBuilding: title: Rotation by building type @@ -749,7 +772,7 @@ settings: disableCutDeleteWarnings: title: Disable Cut/Delete Warnings description: >- - Disable the warning dialogs brought up when cutting/deleting more than 100 entities. + Disables the warning dialogs brought up when cutting/deleting more than 100 entities. keybindings: title: Keybindings @@ -783,6 +806,7 @@ keybindings: menuOpenShop: Upgrades menuOpenStats: Statistics + menuClose: Close Menu toggleHud: Toggle HUD toggleFPSInfo: Toggle FPS and Debug Info @@ -793,12 +817,14 @@ keybindings: underground_belt: *underground_belt miner: *miner cutter: *cutter + advanced_processor: *advanced_processor rotater: *rotater stacker: *stacker mixer: *mixer energy_generator: *energy_generator painter: *painter trash: *trash + wire: *wire pipette: Pipette rotateWhilePlacing: Rotate @@ -832,7 +858,7 @@ about: The soundtrack was made by Peppsen - He's awesome.

- Finally, huge thanks to my best friend Niklas - Without our factorio sessions this game would never have existed. + Finally, huge thanks to my best friend Niklas - Without our factorio sessions, this game would never have existed. changelog: title: Changelog diff --git a/translations/base-es.yaml b/translations/base-es.yaml index 77273462..88156566 100644 --- a/translations/base-es.yaml +++ b/translations/base-es.yaml @@ -23,6 +23,9 @@ steamPage: # This is the short text appearing on the steam page shortText: shapez.io es un juego sobre construir fábricas para automatizar la creación y combinación de figuras cada vez más complejas en un mapa infinito. + # This is the text shown above the discord link + discordLink: Discord oficial - ¡Chatea conmigo! + # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. # NOTICE: # - Do not translate the first line (This is the gif image at the start of the store) @@ -30,41 +33,57 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io es un juego sobre construir fábricas para automatizar la creación y combinación de figuras. Entrega las cada vez más complejas figuras requeridas para progresar y desbloquea mejoras para aumentar la velocidad de tu fábrica. + shapez.io es un juego basado en la construcción de fábricas para automatizar la creación y combinación de figuras en un mapa que se expande infinitamente. + Entrega las figuras requeridas para progresar y desbloquear mejoras para aumentar la velocidad de tu fábrica. - Al aumentar la demanda, necesitaras escalar tu fábrica para ajustarte a las necesidades - ¡No te olvides de los recursos, necesitarás expandirte en el [b]mapa infinito[/b]! + Al aumentar la demanda, necesitarás escalar tu fábrica para ajustarte a las necesidades - ¡No te olvides de los recursos, necesitarás expandirte en el [b]mapa infinito[/b]! - Ya que las figuras puedes ser aburridas necesitarás mezclar colores para pintar las figuras - Combina recursos de colores rojo, verde y azul para producir diferentes colores y pintar figuras para satisfacer la demanda. + Después necesitarás mezclar colores para pintar las figuras - Combina recursos de colores rojo, verde y azul para producir diferentes colores y pintar figuras para satisfacer la demanda. Este juego cuenta con 18 niveles (¡Que te mantendrán ocupado durante horas!) pero estoy constantemente añadiendo nuevo contenido - ¡Hay mucho planeado! + Comprando el juego tendrás acceso a la versión completa con contenido adicional, además del contenido en desarrollo. [b]Ventajas del juego completo[/b] [list] - [*] Puntos de referencia en el mapa - [*] Ilimitadas partidas guardadas - [*] Modo nocturno - [*] Más opciones - [*] Permitirme seguir desarrollando shapez.io ❤️ - [*] Más características en el futuro! + [*] Modo oscuro + [*] Puntos de referencia ilimitados + [*] Partidas guardadas ilimitadas + [*] Ajustes adicionales + [*] Próximamente: ¡Cables y Energía! Aproximadamente para finales de julio de 2020. + [*] Próximamente: Más niveles + [*] Ayúdame a seguir desarrollando shapez.io ❤️ [/list] - [b]Características planeadas & sugerencias de la comunidad[/b] + [b]Futuras actualizaciones[/b] + + ¡Estoy actualizando el juego muy a menudo e intentando subir actualizaciones al menos una vez a la semana! - Este juego es de código abierto - Cualquiera puede contribuir! A parte de eso, escucho [b]mucho[/b] a la comunidad! Intento leer todas las sugerencias e intento tener en cuenta todo el foodback posible. [list] - [*] Modo historia en el que los edificios cuesten figuras - [*] Más niveles y edificios (exclusivos del juego completo) - [*] Mapas diferentes y tal vez obstáculos en el mapa - [*] Configuración en la creación del mapa (Editar el número y tamaño de los recursos, la semilla, y más) - [*] Más tipos de formas - [*] Mejoras de rendimiento (Aunque el juego ya funciona muy bien!) - [*] Modo para daltónicos - [*] Y mucho más! + [*] Diferentes mapas y desafíos (por ejemplo: mapas con obstáculos) + [*] Puzles (Entrega la forma requerida con una zona o conjunto de edificios restringidos) + [*] Modo historia en el que los edificios tengan un coste + [*] Generador de mapas configurable (Configurar recursos, forma, tamaño, densidad, semilla y más) + [*] Más tipos de figuras + [*] Mejoras de rendimiento (¡Aunque el juego ya funciona muy bien!) + [*] ¡Y mucho más! [/list] - Además asegúrate de comprobar el tablero de Trello para ver todo lo planificado! https://trello.com/b/ISQncpJP/shapezio + [b]¡Este juego es de código abierto![/b] + + Cualquiera puede contribuir, estoy activamente involucrado en la comunidad e intento leer todas las sugerencias y considerar todas las propuestas planteadas. + ¡Comprueba mi tablero de Trello para ver todo lo planificado! + + [b]Enlaces[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Discord oficial[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Hoja de ruta[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Código fuente (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Ayuda a traducir[/url] + [/list] global: loading: Cargando @@ -73,6 +92,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "." + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "," + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -96,8 +118,8 @@ global: # Short formats for times, e.g. '5h 23m' secondsShort: s - minutesAndSecondsShort: m s - hoursAndMinutesShort: h m + minutesAndSecondsShort: min s + hoursAndMinutesShort: h min xMinutes: minutos @@ -107,22 +129,23 @@ global: alt: ALT escape: ESC shift: SHIFT - space: SPACE + space: ESPACIO demoBanners: # This is the "advertisement" shown in the main menu and other various places - title: Versión de Prueba + title: Versión de prueba intro: >- - ¡Obtén el juego completo para conseguir todas las características! + ¡Obtén el juego completo para desbloquear todas las características! mainMenu: play: Jugar continue: Continuar - newGame: Nuevo Juego - changelog: Registro de cambios + newGame: Nuevo juego + changelog: Historial de cambios + subreddit: Reddit importSavegame: Importar openSourceHint: ¡Este juego es de código abierto! - discordLink: Servidor de Discord Oficial + discordLink: Servidor de Discord oficial helpTranslate: ¡Ayuda a traducirlo! madeBy: Desarrollado por @@ -133,56 +156,32 @@ mainMenu: savegameLevel: Nivel savegameLevelUnknown: Nivel desconocido - contests: - contest_01_03062020: - title: "Concurso #01" - desc: ¡Gana 25$ por la base más impresionante! - longDesc: >- - ¡Para devolveros algo a vosotros he pensado que molaría hacer consursos semanales! -

- ¡El tema de esta semana: Construye la base más chula! -

- Este es el trato:
-
    -
  • Envía una captura de pantalla de tu base a contest@shapez.io
  • -
  • Puntos extra si lo subes a redes sociales!
  • -
  • Elegiré 5 capturas de pantalla y las propondré a la comunidad de discord para que vote.
  • -
  • El ganador obtendrá 25$ (Paypal, tarjeta de regalo de Amazon, lo que prefieras)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- Estoy esperando para ver vuestras increíbles creaciones! - - showInfo: Ver - contestOver: El concurso ha terminado - Únete al discord para enterarte sobre nuevos concursos! - subreddit: Reddit - dialogs: buttons: ok: OK delete: Borrar cancel: Cancelar - later: Más Tarde - restart: Volver A Empezar - reset: Resetear - getStandalone: Obtener Juego Completo - deleteGame: Sé Lo Que Hago - viewUpdate: Ver Actualización - showUpgrades: Ver Mejoras - showKeybindings: Ver Atajos De teclado + later: Más tarde + restart: Volver a empezar + reset: Reiniciar + getStandalone: Obtener juego completo + deleteGame: Sé lo que hago + viewUpdate: Ver actualización + showUpgrades: Ver mejoras + showKeybindings: Ver atajos de teclado importSavegameError: - title: Error de Importación + title: Error de importación text: >- Fallo al importar tu partida guardada: importSavegameSuccess: - title: Partida Guardada Importada + title: Partida guardada importada text: >- Tu partida guardada ha sido importada con éxito. gameLoadFailure: - title: El juego está roto + title: Error de carga text: >- No se ha podido cargar la partida guardada: @@ -203,32 +202,33 @@ dialogs: editKeybinding: title: Cambiar atajos de teclado - desc: Presiona la tecla o botón del ratón que quieras asignar o escape para cancelar. + desc: Pulsa la tecla o botón del ratón que quieras asignar, o escape para cancelar. resetKeybindingsConfirmation: - title: Resetear atajos de teclado - desc: Esto reseteará todos los atajos de teclado a los valores por defecto. Por favor, confirma. + title: Reiniciar atajos de teclado + desc: Esto devolverá todos los atajos de teclado a los valores por defecto. Por favor, confirma. keybindingsResetOk: - title: Reseteo de los atajos de teclado - desc: ¡Los atajos de taclado han sito reseteados a los valores por defecto! + title: Atajos de teclado reiniciados + desc: ¡Los atajos de teclado han sito reiniciados a los valores por defecto! featureRestriction: - title: Versión de Prueba - desc: Has intentado acceder a una característica () que no está disponible en la demo. ¡Considera obtener el juego completo para la experiencia completa! + title: Versión de prueba + desc: Has intentado acceder a una característica () que no está disponible en la versión de prueba. ¡Considera obtener el juego completo para la experiencia completa! oneSavegameLimit: - title: partidas guardadas limitadas - desc: Solo puedes tener una partida guardada a la vez en la versión de prueba. ¡Por favor elimina la ya existente o obtén el juego completo! + title: Partidas guardadas limitadas + desc: Solo puedes tener una partida guardada a la vez en la versión de prueba. ¡Por favor, elimina la ya existente u obtén el juego completo! + updateSummary: title: ¡Nueva actualización! desc: >- Estos son los cambios desde la última vez que jugaste: upgradesIntroduction: - title: Desbloquear Mejoras + title: Desbloquear mejoras desc: >- - Todas las figuras puedes ser usadas para desbloquear mejoras - ¡No destruyas tus fábricas anteriores! + Todas las figuras se pueden usar para desbloquear mejoras - ¡No destruyas tus fábricas anteriores! La pestaña de mejoras está en la esquina superior derecha de la pantalla. massDeleteConfirm: @@ -239,34 +239,38 @@ dialogs: massCutConfirm: title: Confirmar corte desc: >- - ¡Estas cortando muchos edificios ( para ser exactos)! ¿Estas seguro de - que quieres hacer esto? + ¡Estás cortando muchos edificios ( para ser exactos)! ¿Estas seguro de que quieres hacer esto? + + massCutInsufficientConfirm: + title: Confirm cut + desc: >- + ¡No puedes permitirte pegar este área! ¿Estás seguro de que quieres cortarlo? blueprintsNotUnlocked: title: No desbloqueado todavía desc: >- - ¡Los planos no han sido desbloqueados todavía! Completa más niveles para desbloquearlos. + ¡Completa el nivel 12 para desbloquear los Planos! + keybindingsIntroduction: title: Atajos de teclado útiles desc: >- El juego tiene muchos atajos de teclado que facilitan la tarea de construir grandes fábricas. ¡Aquí hay algunos, pero asegúrate de comprobar los atajos de teclado!

- CTRL + Arrastrar: Selecciona un área para copiarla / borrarla.
- SHIFT: Mánten pulsado para colocar varias veces el mismo edificio.
+ CTRL + Arrastrar: Selecciona un área.
+ SHIFT: Mánten pulsado para colocar varias veces un edificio.
ALT: Invierte la orientación de las cintas transportadoras colocadas.
createMarker: title: Nuevo marcador - desc: Dale un nombre significativo, tambien puedes agregarle la clave de una forma (La cual puedes generar aquí) + titleEdit: Editar marcador + desc: Dale un nombre significativo, también puedes agregarle una clave de una forma (La cual puedes generar aquí) markerDemoLimit: - desc: Sólo puedes crear dos marcadores en la versión de prueba. ¡Obtén el juego completo para marcas ilimitadas! + desc: Solo puedes crear dos marcadores en la versión de prueba. ¡Obtén el juego completo para marcadores ilimitados! exportScreenshotWarning: title: Exportar captura de pantalla - desc: >- - Has pedido una captura de pantalla. Por favor ten en cuenta de que - puede tardar bastante en las bases grandes ¡He incluso crashear tu juego! + desc: Has solicitado una captura de pantalla de tu base. Por favor, ten en cuenta que puede tardar bastante en las bases grandes. ¡E incluso crashear tu juego! ingame: # This is shown in the top left corner and displays useful keybindings in @@ -274,22 +278,35 @@ ingame: keybindingsOverlay: moveMap: Mover selectBuildings: Seleccionar área - stopPlacement: Parar de colocar + stopPlacement: Dejar de colocar rotateBuilding: Rotar edificio placeMultiple: Colocar varios - reverseOrientation: Invierte la orientación - disableAutoOrientation: Desactiva la auto orientación - toggleHud: Habilita el HUD + reverseOrientation: Invertir la orientación + disableAutoOrientation: Desactivar la autoorientación + toggleHud: Habilitar el HUD placeBuilding: Colocar edificio - createMarker: Crear marca + createMarker: Crear marcador delete: Destruir pasteLastBlueprint: Pegar último plano lockBeltDirection: Activar planificador de cintas transportadoras plannerSwitchSide: Invertir giro del planificador cutSelection: Cortar copySelection: Copiar - clearSelection: Limpiar Selección + clearSelection: Limpiar selección pipette: Pipette + switchLayers: Cambiar capas + + # Names of the colors, used for the color blind mode + colors: + red: Rojo + green: Verde + blue: Azul + yellow: Amarillo + purple: Púrpura + cyan: Cian + white: Blanco + black: Negro + uncolored: Gris # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -318,12 +335,12 @@ ingame: levelTitle: Nivel completed: Completado unlockText: ¡Has desbloqueado ! - buttonNextLevel: Siguiente Nivel + buttonNextLevel: Siguiente nivel # Notifications on the lower right notifications: newUpgrade: ¡Una nueva mejora está disponible! - gameSaved: Tu partida ha sido guardada. + gameSaved: Se ha guardado la partida. # The "Upgrades" window shop: @@ -347,14 +364,14 @@ ingame: description: Muestra la cantidad de figuras guardadas en tu edificio central. produced: title: Producido - description: Muestra todas las figuras que tu fábrica entera produce, incluyendo productos intermedios. + description: Muestra todas las figuras que tu fábrica al completo produce, incluyendo productos intermedios. delivered: title: Entregados description: Muestra las figuras que son entregadas a tu edificio central. noShapesProduced: Todavía no se han producido figuras. - # Displays the shapes per minute, e.g. '523 / m' - shapesPerMinute: / m + # Displays the shapes per minute, e.g. '523 / min' + shapesPerMinute: / min # Settings menu, when you press "ESC" settingsMenu: @@ -366,12 +383,12 @@ ingame: buttons: continue: Continuar settings: Opciones - menu: Volver al Menú Principal + menu: Volver al menú principal # Bottom left tutorial hints tutorialHints: title: ¿Necesitas ayuda? - showHint: Mostrar Pista + showHint: Mostrar pista hideHint: Cerrar # When placing a blueprint @@ -385,33 +402,27 @@ ingame: description: Click izquierdo sobre un marcador para ir ahí, click derecho para borrarlo.

Pulsa para crear un marcador de la vista actual o click derecho para crear un marcador en la posición seleccionada. creationSuccessNotification: El marcador ha sido creado. + # Shape viewer + shapeViewer: + title: Capas + empty: Vacío + copyKey: Copiar + # Interactive tutorial interactiveTutorial: title: Tutorial hints: 1_1_extractor: ¡Coloca un extractor encima de un círculo para extraerlo! 1_2_conveyor: >- - ¡Conecta el extractor con una cinta transportadora a tu edificio central!

Pista: Pulsa y arrastra la cinta transportadora con el ratón! + ¡Conecta el extractor con una cinta transportadora a tu edificio central!

Pista: ¡Pulsa y arrastra la cinta transportadora con el ratón! + 1_3_expand: >- ¡Esto NO es un "juego de esperar"! Construye más extractores y cintas transportadoras para completar el objetivo más rápido.

Pista: Mantén pulsado SHIFT para colocar varios extractores y usa R para rotarlos. - colors: - red: Rojo - green: Verde - blue: Azul - yellow: Amarillo - purple: Morado - cyan: Cian - white: Blanco - uncolored: Sin color - shapeViewer: - title: Capas - empty: Vacio - # All shop upgrades shopUpgrades: belt: - name: Cintas transportadoras, Distribuidores & Túneles + name: Cintas transportadoras, Distribuidores y Túneles description: Velocidad x → x miner: name: Extracción @@ -425,10 +436,20 @@ shopUpgrades: # Buildings and their name / description buildings: + hub: + deliver: Entregar + toUnlock: para desbloquear + levelShortcut: LVL + belt: default: name: &belt Cinta Transportadora - description: Transporta elementos, mantén pulsado y arrastra para colocar múltiples. + description: Transporta elementos, mantén pulsado y arrastra para colocar varios. + + wire: + default: + name: &wire Cable + description: Te permite transportar energía miner: # Internal name for the Extractor default: @@ -445,7 +466,7 @@ buildings: description: Permite contruir un túnel para transportar los elementos por debajo de edificios y otras cintas transportadoras. tier2: - name: Túnel de nivel II + name: Túnel nivel II description: Permite contruir un túnel para transportar los elementos por debajo de edificios y otras cintas transportadoras. splitter: # Internal name for the Balancer @@ -464,39 +485,46 @@ buildings: cutter: default: name: &cutter Cortador - description: Corta las figuras de arriba a abajo y saca ambas mitades. ¡Si solo usas una parte, asegúrate de destruir la otra parte o se parará! + description: Corta las figuras de arriba abajo y saca ambas mitades. ¡Si solo usas una parte, asegúrate de destruir la otra parte o se parará! quad: name: Cortador (Cuádruple) description: Corta figuras en cuatro partes. ¡Si solo usas una parte, asegúrate de destruir las otras partes o se parará! + advanced_processor: + default: + name: &advanced_processor Inversor de color + description: Invierte un color o una figura + rotater: default: name: &rotater Rotador - description: Rota la figura en el sentido de las agujas del reloj, 90 grados. + description: Rota las figuras en sentido horario 90 grados. ccw: name: Rotador (Inverso) - description: Rota las figuras en contra de las agujas del reloj, 90 grados. + description: Rota las figuras en sentido antihorario 90 grados. stacker: default: name: &stacker Apilador - description: Junta ambos elementos. Si no pueden ser juntados, el elemento de la derecha es colocado encima del elemento de la izquierda. + description: Apila ambos elementos. Si no se pueden unir, el elemento de la derecha se coloca encima del elemento de la izquierda. mixer: default: name: &mixer Mezclador de colores - description: Junta dos colores usando mezcla aditiva. + description: Mezcla dos colores usando mezcla aditiva. painter: default: name: &painter Pintor - description: &painter_desc Colorea la figura entera con el color que entra por la izquierda. + description: &painter_desc Colorea la figura completa de la entrada izquierda con el color de la entrada de arriba. + mirrored: name: *painter description: *painter_desc + double: name: Pintor (Doble) - description: Colorea las figuras que entran por la izquierda con el color que entrapor arriba. + description: Colorea las figuras de las entradas de la izquierda con el color de la entrada de arriba. quad: name: Pintor (Cuádruple) description: Permite colorear cada cuadrante de una figura con un color distinto. @@ -504,97 +532,112 @@ buildings: trash: default: name: &trash Basurero - description: Acepta entradas desde todos los lados y los destruye. Para Siempre. + description: Acepta entradas desde todos los lados y los destruye. Para siempre. storage: name: Almacenamiento. - description: Guarda el exceso de elementos, hasta cierta cantidad. Puede ser usado para contolar el desborde de elementos. + description: Guarda el exceso de elementos, hasta cierta cantidad. Puede ser usado para controlar el desborde de elementos. - hub: - deliver: Envía - toUnlock: para desbloquear - levelShortcut: LVL + energy_generator: + deliver: Entregar + # This will be shown before the amount, so for example 'For 123 Energy' + toGenerateEnergy: Para + + default: + name: &energy_generator Generador de energía + description: Genera energía consumiendo figuras. + + wire_crossings: + default: + name: &wire_crossings Divisor de cables + description: Divide un cable en dos + + merger: + name: Fusionador de cables + description: Fusiona dos cables en uno + storyRewards: # Those are the rewards gained from completing the store reward_cutter_and_trash: - title: Cortador de Figuras - desc: Acabas de desbloquear el cortador - corta las figuras por la mitad de arriba abajo ¡Sin importar su orientación!

Estate seguro de deshacerte de lo que no vayas a usar o se parará - Para ese propósito te he dado una basura, que destruye todo lo que le pongas! + title: Cortador de figuras + desc: ¡Acabas de desbloquear el cortador - corta las figuras por la mitad de arriba abajo sin importar su orientación!

Asegúrate de deshacerte de lo que no vayas a usar o se parará - ¡Para eso te he dado un basurero, que destruye todo lo que le pongas! reward_rotater: title: Rotador - desc: ¡El rotador ha sido desbloqueado! Rota figuras en el sentido de las agujas del reloj, 90 grados. + desc: ¡El rotador se ha desbloqueado! Rota figuras en sentido horario 90 grados. reward_painter: title: Pintor desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + El pintor se ha desbloqueado - ¡Extrae vetas de color (igual que lo haces con las figuras) y combínalas con una figura en el pintor para colorearlas!

PD: Si tienes alguna forma de daltonismo, ¡hay un modo para daltónicos en los ajustes! reward_mixer: - title: Mezclador de Color - desc: El mezclador ha sido desbloqueado - ¡Combina dos colores usando mezcla aditiva con este edificio! + title: Mezclador de color + desc: El mezclador se ha desbloqueado - ¡Combina dos colores usando mezcla aditiva con este edificio! reward_stacker: title: Apilador desc: ¡Ahora puedes combinar figuras con el apilador! Ambas entradas son combinadas, y si pueden ser colocadas una junto a la otra serán fusionadas. ¡Si no, la entrada derecha será apilada encima de la entrada izquierda! reward_splitter: - title: Separador/Fusión - desc: El balanceador multiusos ha sido desbloqueado - ¡Puede ser usado para construir fábricas más grandes separando y uniendo elementos en varias cintas transportadoras!

+ title: Separador/Fusionador + desc: El balanceador multiusos se ha desbloqueado - ¡Se puede usar para construir fábricas más grandes separando y uniendo elementos en varias cintas transportadoras!

reward_tunnel: title: Túnel - desc: El tunel ha sido desbloqueado - ¡Ahora puedes transportar elementos por debajo de edificios u otras cintas! + desc: El túnel se ha desbloqueado - ¡Ahora puedes transportar elementos por debajo de edificios u otras cintas! reward_rotater_ccw: - title: Rotador Inverso + title: Rotador inverso desc: Has desbloqueado una variante del rotador - ¡Te permite rotar en sentido antihorario! Para construirlo selecciona el rotador y pulsa 'T' para ciclar por sus variantes reward_miner_chainable: - title: Extractor en Cadena - desc: ¡Has desbloqueado el extractor en cadena! Puede enviar los recursos a otros extractores, así puedes extraer recursos más eficientemente + title: Extractor en cadena + desc: ¡Has desbloqueado el extractor en cadena! Puede enviar los recursos a otros extractores, extrayendo recursos más eficientemente. reward_underground_belt_tier_2: - title: Tunel de Nivel II - desc: Has desbloqueado una nueva variante del tunel - ¡Tiene un mayor rango, ahora puedes mezclar los distintos tipos de túneles! + title: Túnel nivel II + desc: Has desbloqueado una nueva variante del túnel - ¡Tiene un mayor rango, y ahora puedes mezclar los distintos tipos de túneles! reward_splitter_compact: - title: Balanceador Compacto - desc: >- - Has desbloqueado una variante compacta del balanceador - ¡Acepta dos entradas y las junta en una salida! + title: Balanceador compacto + desc: Has desbloqueado una variante compacta del balanceador - ¡Acepta dos entradas y las junta en una salida! + reward_cutter_quad: - title: Cortador Cuádruple + title: Cortador cuádruple desc: Has desbloqueado una variante del cortador - ¡Permite cortar figuras en cuatro partes en vez de solo dos! reward_painter_double: - title: Doble Pintor - desc: Has desbloqueado una variante del pintor - ¡Funciona como un pintor regular pero procesa dos formas a la vez consumiendo solo un color en vez de dos! + title: Pintor doble + desc: Has desbloqueado una variante del pintor - ¡Funciona como un pintor normal pero procesa dos figuras a la vez, consumiendo solo un color en vez de dos! reward_painter_quad: - title: Cuádruple Pintor + title: Pintor cuádruple desc: Has desbloqueado una variante del pintor - ¡Permite pintar cada parte de una figura individualmente! reward_storage: - title: Almacenamiento Intermedio - desc: Has desbloqueado una variante de la basura - ¡Permite almacenar elementos hasta una cierta capacidad! + title: Almacenamiento intermedio + desc: Has desbloqueado una variante del basurero - ¡Permite almacenar elementos hasta una cierta capacidad! reward_freeplay: title: Juego libre - desc: ¡Lo has conseguido! ¡Has desbloqueado el Juego Libre! ¡Esto significa que las figuras son ahora generadas aleatoriamente! (¡No te preocupes, más contenido está planeado para el juego completo!) + desc: ¡Lo has conseguido! ¡Has desbloqueado el Juego Libre! ¡Esto significa que ahora las figuras se generan aleatoriamente! (¡No te preocupes, hay más contenido planeado para el juego completo!) reward_blueprints: title: Planos - desc: ¡Ahora puedes copiar y pegar partes de tu fábrica! Selecciona un área (Mantén pulsado CTRL, después arrastra con el ratón), y pulsa 'C' para copiarlo.

Pegarlo no es gratis, necesitas producir figuras de planos para poder permitírtelo (Esas que acabas de entregar). + desc: ¡Ahora puedes copiar y pegar partes de tu fábrica! Selecciona un área (mantén pulsado CTRL, después arrastra con el ratón), y pulsa 'C' para copiarlo.

Pegarlo no es gratis, necesitas producir figuras de planos para poder permitírtelo (Esas que acabas de entregar). # Special reward, which is shown when there is no reward actually no_reward: - title: Siguiente Nivel + title: Siguiente nivel desc: >- - Este nivel no da recompensa, pero el siguiente si!

PS: Mejor no destruyas la fábrica que tienes - ¡Necesitarás todas esas figuras más adelante para desbloquear mejoras! + Este nivel no da recompensa, ¡pero el siguiente sí!

PD: Es mejor que no destruyas la fábrica que tienes - ¡Necesitarás todas esas figuras más adelante para desbloquear mejoras! + no_reward_freeplay: - title: Siguiente Nivel + title: Siguiente nivel desc: >- - ¡Felicidades! ¡Por cierto, más contenido está planeado para el juego completo! + ¡Felicidades! ¡Por cierto, hay más contenido planeado para el juego completo! settings: title: Opciones @@ -604,15 +647,15 @@ settings: versionBadges: dev: Desarrollo - staging: Staging + staging: Escenificación prod: Producción buildDate: Generado labels: uiScale: - title: Escala de la Interfaz + title: Escala de la interfaz description: >- - Cambia el tamaño de la interfaz de usuario. La interfaz seguirá escalando dependiendo de la resolución de tu dispositivo, pero esta opción controla la cantidad de la escala. + Cambia el tamaño de la interfaz de usuario. La interfaz se seguirá escalando dependiendo de la resolución de tu dispositivo, pero esta opción controla la cantidad de escalado. scales: super_small: Muy pequeño small: Pequeño @@ -620,205 +663,210 @@ settings: large: Grande huge: Enorme + autosaveInterval: + title: Intervalo de autoguardado + description: >- + Controla con qué frecuencia se guarda el juego automáticamente. También se puede desactivar por completo. + + intervals: + one_minute: 1 minuto + two_minutes: 2 minutos + five_minutes: 5 minutos + ten_minutes: 10 minutos + twenty_minutes: 20 minutos + disabled: Desactivado + scrollWheelSensitivity: title: Sensibilidad del zoom description: >- - Cambia como de sensible es el zoom (Tanto la ruedo del ratón como el trackpad) + Cambia cómo de sensible es el zoom (Tanto la rueda del ratón como el panel táctil) sensitivity: - super_slow: Muy Lento + super_slow: Muy lento slow: Lento regular: Normal fast: Rápido - super_fast: Muy Rápido + super_fast: Muy rápido movementSpeed: title: Velocidad de movimiento - description: Cambia que tan rapido se mueve la camara al usar el teclado. + description: >- + Cambia cómo de rápido se mueve la vista usando el teclado. speeds: super_slow: Super lento slow: Lento - regular: Regular + regular: Normal fast: Rápido - super_fast: Super rápido + super_fast: Súper rápido extremely_fast: Extremadamente rápido language: title: Idioma description: >- - Cambia el idioma. Todas las traducciones son contribuciones de los usuarios y pueden estar incompletas! + Cambia el idioma. ¡Todas las traducciones son contribuciones de los usuarios y pueden estar incompletas! + + enableColorBlindHelper: + title: Modo para daltónicos + description: >- + Activa varias herramientas que facilitan jugar si tienes alguna forma de daltonismo. + fullscreen: title: Pantalla Completa description: >- - Es recomendado jugar en pantalla completa para conseguir la mejor experiencia. Solo disponible en el juego completo. + Se recomienda jugar en pantalla completa para conseguir la mejor experiencia. Solo disponible en el juego completo. + soundsMuted: - title: Silenciar Sonidos + title: Silenciar sonidos description: >- - Si habilitado, silencia todos los efectos de sonido. + Si está habilitado, silencia todos los efectos de sonido. musicMuted: - title: Silenciar Música + title: Silenciar música description: >- - Si habilitado, silencia toda la música. + Si está habilitado, silencia toda la música. theme: - title: Tema del Juego + title: Tema del juego description: >- - Elije el tema del juego (claro/oscuro). - + Elige el tema del juego (claro/oscuro). themes: dark: Oscuro light: Claro refreshRate: - title: Objetivo de Simulación + title: Objetivo de simulación description: >- - Si tienes un monitor de 144hz, cambia la tasa de refresco asi el juego se ejecutará correctamente a una mayor tasa de refresco. Esto puede disminuir los FPS si tu ordenador no es lo suficientemente rápido. + Si tienes un monitor de 144hz, cambia la tasa de refresco. Así el juego se ejecutará correctamente a una mayor tasa de refresco. Esto puede disminuir los FPS si tu ordenador no es lo suficientemente rápido. alwaysMultiplace: - title: Colocar Múltiples + title: Colocación múltiple description: >- - Si activado, todos los edificios quedarán seleccionados después de colocarlos hasta que lo canceles. Es equivalente a pulsar SHIFT permanentemente. + Si está activado, todos los edificios se quedarán seleccionados después de colocarlos hasta que lo canceles. Equivale a pulsar SHIFT permanentemente. offerHints: - title: Pistas & Tutorial + title: Pistas y tutoriales description: >- - Activa si recibir pistas y tutoriales mientras juegas. También oculta algunos elementos de la interfaz hasta cierto nivel para hacer más fácil la introducción al juego. + Actívalo para recibir pistas y tutoriales mientras juegas. También oculta algunos elementos de la interfaz hasta cierto nivel para hacer más fácil la introducción al juego. enableTunnelSmartplace: - title: Túneles Inteligentes + title: Túneles inteligentes description: >- - Si está activado, colocar túneles automáticamente removerá las cintas transportadoras innecesarias. Esto también permite arrastrar con el ratón y los túneles excedentes serán removidos. + Si está activado, al colocar túneles se eliminará automáticamente las cintas transportadoras innecesarias. También te permite arrastrar con el ratón y los túneles restantes serán eliminados. vignette: title: Viñeta description: >- - Activa el efecto viñeta que oscurece loas esquinas de la pantalla y hace el texto mas fácil de leer. + Activa el efecto viñeta que oscurece las esquinas de la pantalla y hace el texto más fácil de leer. - autosaveInterval: - title: Intervalo de Autoguardado - description: >- - Controla cada cuanto tiempo se guarda el juego automaticamente. Aquí tambien puedes deshabilitarlo por completo. - intervals: - one_minute: 1 Minuto - two_minutes: 2 Minutos - five_minutes: 5 Minutos - ten_minutes: 10 Minutos - twenty_minutes: 20 Minutos - disabled: Deshabilitado - compactBuildingInfo: - title: Información Compacta de Edificios - description: >- - Acorta la caja de información mostrando solo sus ratios. Si no, se mostrara una descripción y una imagen. - disableCutDeleteWarnings: - title: Deshabilitar las advertencias de Cortar/Eliminar - description: >- - Deshabilita los dialogos de advertencia que se muestran cuando se cortan/eliminan mas de 100 elementos. - - enableColorBlindHelper: - title: Modo para Daltonicos - description: Activa varias herramientas que permiten jugar si eres daltonico. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotación por tipo de edificio + description: >- + Cada tipo de edificio recuerda la última rotación que le diste individualmente. Esto puede ser más cómodo si cambias a menudo entre colocar diferentes tipos de edificio. + + compactBuildingInfo: + title: Información compacta de edificios + description: >- + Acorta la caja de información mostrando solo sus ratios. Si no, se mostrará una descripción y una imagen. + + disableCutDeleteWarnings: + title: Deshabilitar las advertencias de cortar/eliminar + description: >- + Deshabilita los diálogos de advertencia que se muestran cuando se cortan/eliminan más de 100 elementos. keybindings: - title: Atajos de Teclado + title: Atajos de teclado hint: >- - Pista: Asegúrate de usar CTRL, SHIFT y ALT! Habilitan distintas opciones de colocación. - resetKeybindings: Reestablecer Atajos de Teclado + Pista: ¡Asegúrate de usar CTRL, SHIFT y ALT! Habilitan distintas opciones de colocación. + + resetKeybindings: Reestablecer atajos de teclado categoryLabels: general: Aplicación ingame: Juego navigation: Navegación placement: Colocación - massSelect: Selección Masiva - buildings: Atajos de Edificios - placementModifiers: Modificadores de Colocación + massSelect: Selección masiva + buildings: Atajos de edificios + placementModifiers: Modificadores de colocación mappings: confirm: Confirmar back: Atrás - mapMoveUp: Mover Arriba - mapMoveRight: Mover a la Derecha - mapMoveDown: Move Abajo - mapMoveLeft: Move a la Izquierda - centerMap: Centro del Mapa + mapMoveUp: Mover arriba + mapMoveRight: Mover a la derecha + mapMoveDown: Mover abajo + mapMoveLeft: Mover a la izquierda + mapMoveFaster: Mover más rápido + centerMap: Centrar mapa mapZoomIn: Acercarse mapZoomOut: Alejarse - createMarker: Crear Marca + createMarker: Crear marcador menuOpenShop: Mejoras menuOpenStats: Estadísticas + menuClose: Cerrar menú - toggleHud: Activar interfáz - toggleFPSInfo: Activa FPS e información de depurado + toggleHud: Activar HUD + toggleFPSInfo: Activar FPS e información de depurado + switchLayers: Cambiar capas + exportScreenshot: Exportar la base completa como imagen belt: *belt splitter: *splitter underground_belt: *underground_belt miner: *miner cutter: *cutter + advanced_processor: *advanced_processor rotater: *rotater stacker: *stacker mixer: *mixer + energy_generator: *energy_generator painter: *painter trash: *trash + wire: *wire + pipette: Pipette rotateWhilePlacing: Rotar rotateInverseModifier: >- - Modificador: Rotar inversamente en su lugar + Modificador: Rotar inversamente cycleBuildingVariants: Ciclar variantes - confirmMassDelete: Confirmar Borrado Masivo - cycleBuildings: Ciclar Edificios - lockBeltDirection: Colocar en línea recta + confirmMassDelete: Borrar área + pasteLastBlueprint: Pegar último plano + cycleBuildings: Ciclar edificios + lockBeltDirection: Activar planificador de cintas transportadoras + switchDirectionLockSide: >- + Planner: Cambiar sentido massSelectStart: Mantén pulsado y arrastra para empezar massSelectSelectMultiple: Seleccionar múltiples áreas massSelectCopy: Copiar área + massSelectCut: Cortar área placementDisableAutoOrientation: Desactivar orientación automática placeMultiple: Permanecer en modo de construcción placeInverse: Invierte automáticamente la orientación de las cintas transportadoras - pasteLastBlueprint: Pegar último plano - massSelectCut: Cortar área - exportScreenshot: Exportar toda la base como imagen - mapMoveFaster: Mover más rápido - switchDirectionLockSide: "Planner: Switch side" - pipette: Pipette about: - title: Sobre el Juego + title: Sobre el juego body: >- - Este juego es de código abierto y ha sido desarrollado por Tobias Springer (Ese soy yo).

+ Este juego es de código abierto y ha sido desarrollado por Tobias Springer (Ese soy yo).

- Si quieres contribuir revisa shapez.io en github.

+ Si quieres contribuir, revisa shapez.io en github.

- Este juego no habria sido posible si no fuera por la gran comunidad de Discord - sobre mis juegos - ¡Deberías unirte al servidor de discord!

+ Este juego no habría sido posible si no fuera por la gran comunidad de Discord en mis juegos - ¡Deberías unirte al servidor de Discord!

- La banda sonora ha sido creada por Peppsen - El es genial.

+ La banda sonora ha sido creada por Peppsen - Es genial.

- Finalmente muchísimas gracias a mi amigo Niklas - Sin nuestras sesiones - de Factorio este juego nunca existiria. + Por último, muchísimas gracias a mi amigo Niklas - Sin nuestras sesiones de Factorio, este juego nunca existiría. changelog: - title: Registro de Cambios + title: Historial de cambios demo: features: restoringGames: Recuperando partidas guardadas importingGames: Importando partidas guardadas oneGameLimit: Limitado a una partida guardada - customizeKeybindings: Personalizando Atajos de Teclado - exportingBase: Exportando base entera como captura de pantalla + customizeKeybindings: Personalizando atajos de teclado + exportingBase: Exportando la base completa como imagen settingNotAvailable: No disponible en la versión de prueba. diff --git a/translations/base-fi.yaml b/translations/base-fi.yaml new file mode 100644 index 00000000..2a2c83af --- /dev/null +++ b/translations/base-fi.yaml @@ -0,0 +1,870 @@ +# +# 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: `. They are encapsulated within angle brackets. The correct +# translation for this one in German for example would be: `Taste: ` (notice +# how the placeholder stayed '' 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. +# + +steamPage: + # This is the short text appearing on the steam page + shortText: shapez.io on peli tehtaiden rakentamisesta, joiden avulla automatisoidaan yhä monimutkaisempien muotojen luonti and yhdisteleminen loputtomassa maailmassa. + + # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. + # NOTICE: + # - Do not translate the first line (This is the gif image at the start of the store) + # - Please keep the markup (Stuff like [b], [list] etc) in the same format + longText: >- + [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] + + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. + + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! + + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. + + [b]Standalone Advantages[/b] + + [list] + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ + [/list] + + [b]Future Updates[/b] + + I am updating the game very often and trying to push an update at least every week! + + [list] + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! + [/list] + + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! + +global: + loading: Ladataan + error: Virhe + + # How big numbers are rendered, e.g. "10,000" + thousandsDivider: "," + + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + + # 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: ∞ + + time: + # Used for formatting past time dates + oneSecondAgo: yksi sekunti sitten + xSecondsAgo: sekunttia sitten + oneMinuteAgo: yksi minuutti sitten + xMinutesAgo: minuuttia sitten + oneHourAgo: yksi tunti sitten + xHoursAgo: tuntia sitten + oneDayAgo: yksi päivä sitten + xDaysAgo: päivää sitten + + # Short formats for times, e.g. '5h 23m' + secondsShort: s + minutesAndSecondsShort: m s + hoursAndMinutesShort: h m + + xMinutes: minuuttia + + keys: + tab: SARKAIN + control: CTRL + alt: ALT + escape: ESC + shift: VAIHTO + space: VÄLILYÖNTI + +demoBanners: + # This is the "advertisement" shown in the main menu and other various places + title: Demoversio + intro: >- + Hanki itsenäinen peli avataksesi kaikki omunaisuudet! + +mainMenu: + play: Pelaa + continue: Jatka + newGame: Uusi Peli + changelog: Muutosloki + subreddit: Reddit + importSavegame: Tuo peli + openSourceHint: Tämä on avoimen lähdekoodin peli! + discordLink: Virallinen Discord Palvelin + helpTranslate: Auta kääntämään! + madeBy: Pelin on tehnyt + + # This is shown when using firefox and other browsers which are not supported. + browserWarning: >- + Anteeksi, mutta pelin tiedetään toimivan huonosti selaimellasi! Hanki itsenäinen versio tai lataa Chrome täyttä tukea varten. + + savegameLevel: Taso + savegameLevelUnknown: Tuntematon Taso + + + +dialogs: + buttons: + ok: OK + delete: Poista + cancel: Peruuta + later: Myöhemmin + restart: Käynnistä uudelleen + reset: Nollaa + getStandalone: Hanki itsenäinen peli + deleteGame: Tiedän mitä olen tekemässä + viewUpdate: Näytä päivitys + showUpgrades: Näytä Päivitykset + showKeybindings: Show Keybindings + + importSavegameError: + title: Tuonti Virhe + text: >- + Tallennuksen tuonti epäonnistui: + + importSavegameSuccess: + title: Tallennus tuotiin + text: >- + Tallennuksesi tuotiin onnistuneesti. + + gameLoadFailure: + title: Peli on rikki + text: >- + Tallennuksen lataus epäonnistui: + + confirmSavegameDelete: + title: Varmista poisto + text: >- + Oletko varma että haluat poistaa tallennuksen? + + savegameDeletionError: + title: Poisto epäonnistui + text: >- + Tallennuksen poisto epäonnistui: + + restartRequired: + title: Uudelleenkäynnistys vaaditaan + text: >- + Käynnistä peli uudelleen ottaaksesi asetukset käyttöön. + + editKeybinding: + title: Vaihda pikanäppäin + desc: Paina näppäintä tai hiiren nappia jonka haluat asettaa tai paina escape peruuttaaksesi. + + resetKeybindingsConfirmation: + title: Nollaa pikanäppäimet + desc: Tämä nollaa kaikki pikanäppäimet oletusarvoihin. Vahvista. + + keybindingsResetOk: + title: Pikanäppäimet nollattiin + desc: Pikanäppäimet nollattiin oletusarvoihin! + + featureRestriction: + title: Demoversio + desc: Yritit käyttää ominaisuutta () joka ei ole saatavilla demoversiossa. Harkitse itsenäisen version hankkimista avataksesi kaikki ominaisuudet! + + oneSavegameLimit: + title: Rajoitetut tallennukset + desc: Sinulla voi olla vain yksi tallennus kerrallaan demoversiossa. Poista vanha tallennus tai hanki itsenäinen versio! + + updateSummary: + title: Uusi päivitys! + desc: >- + Tässä on tulleet muutokset sen jälkeen kun viimeksi pelasit: + + upgradesIntroduction: + title: Avaa Päivitykset + desc: >- + Kaikkia muodoja joita tuotat voi käyttää päivitysten avaamiseen - Älä tuhoa vanhoja tehtaitasi! + Löydät päivitysikkunan näytön oikeasta yläkulmasta. + + massDeleteConfirm: + title: Vahvista poisto + desc: >- + Olet poistamassa paljon rakennuksia (tasan )! Oletko varma että haluat jatkaa? + + massCutConfirm: + title: Vahtista leikkaus + desc: >- + Olet leikkaamassa paljon rakennuksia (tasan )! Oletko varma että haluat jatkaa? + + blueprintsNotUnlocked: + title: Ei vielä avattu + desc: >- + Suorita taso 12 avataksesi Piirustukset! + + keybindingsIntroduction: + title: Hyödyllisiä pikanäppäimiä + desc: >- + Tässä pelissä on paljon pikanäppäimiä, jotka tekevät isojen tehtaiden rakentamisesta helpompaa. + Tässä on muutama, mutta katso kaikki pikanäppäimet!

+ CTRL + Raahaus: Valitse alue.
+ VAIHTO: Pidä pohjassa sijoittaaksesi useita samoja rakennuksia.
+ ALT: Käännä sijoitettavien hihnojen suunta.
+ + createMarker: + title: Uusi Merkki + desc: Anna merkille kuvaava nimi, voit myös sisällyttää muodon lyhyen avaimen siihen. (Lyhyen avaimen voit luoda täällä) + titleEdit: Edit Marker + + markerDemoLimit: + desc: Voit tehdä vain kaksi mukautettua merkkiä demoversiossa. Hanki itsenäinen versio saadaksesi loputtoman määrän merkkejä! + + exportScreenshotWarning: + title: Vie kuvakaappaus + desc: Pyysit tukikohtasi viemistä kuvakaappauksena. Huomaa, että tämä voi olla melko hidasta isolla tukikohdalla ja voi jopa kaataa pelisi! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + +ingame: + # This is shown in the top left corner and displays useful keybindings in + # every situation + keybindingsOverlay: + moveMap: Liiku + selectBuildings: Valitse alue + stopPlacement: Lopeta sijoittaminen + rotateBuilding: Käännä rakennusta + placeMultiple: Sijoita useita + reverseOrientation: Käänteinen suunta + disableAutoOrientation: Poista automaattinen suunta käytöstä + toggleHud: Vaihda valikon näkyvyys + placeBuilding: Sijoita rakennus + createMarker: Luo merkki + delete: Poista + pasteLastBlueprint: Liitä viimeisin piirustus + lockBeltDirection: Ota hihnojen suunnittelija käyttöön + plannerSwitchSide: Käännä suunnittelijan puoli + cutSelection: Leikkaa + copySelection: Kopioi + clearSelection: Tyhjennä Valinta + pipette: Pipetti + switchLayers: Vaihda Tasoa + + # Names of the colors, used for the color blind mode + colors: + red: Punainen + green: Vihreä + blue: Sininen + yellow: Keltainen + purple: Violetti + cyan: Syaani + white: Valkoinen + uncolored: Ei Väriä + black: Black + + # 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: Paina kiertääksesi muunnoksia. + + # Shows the hotkey in the ui, e.g. "Hotkey: Q" + hotkeyLabel: >- + Pikanäppäin: + + infoTexts: + speed: Nopeus + range: Matka + storage: Varasto + oneItemPerSecond: 1 kappale / sekunti + itemsPerSecond: kappaleita / s + itemsPerSecondDouble: (x2) + + tiles: laattaa + + # The notification when completing a level + levelCompleteNotification: + # is replaced by the actual level, so this gets 'Level 03' for example. + levelTitle: Taso + completed: Suoritettu + unlockText: Avattu ! + buttonNextLevel: Seuraava taso + + # Notifications on the lower right + notifications: + newUpgrade: Uusi päivitys on saatavilla! + gameSaved: Peli on tallennettu. + + # The "Upgrades" window + shop: + title: Päivitykset + buttonUnlock: Päivitä + + # Gets replaced to e.g. "Tier IX" + tier: Taso + + # The roman number for each tier + tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X] + + maximumLevel: SUURIN TASO (Nopeus x) + + # The "Statistics" window + statistics: + title: Tilastot + dataSources: + stored: + title: Varastoitu + description: Näyttää keskusrakennuksessa varastoitujen muotojen määrän. + produced: + title: Tuotettu + description: Näyttää kaikki muodot mitä tehtaasi tuottaa ja lisäksi myös välituotteet. + delivered: + title: Toimitettu + description: Näyttää muodot jotka on toimitettu keskusrakennukseen. + noShapesProduced: Toistaiseksi ei muotoja tuotettu. + + # Displays the shapes per minute, e.g. '523 / m' + shapesPerMinute: / m + + # Settings menu, when you press "ESC" + settingsMenu: + playtime: Peliaika + + buildingsPlaced: Rakennukset + beltsPlaced: Liukuhihnat + + buttons: + continue: Jatka + settings: Asetukset + menu: Palaa valikkoon + + # Bottom left tutorial hints + tutorialHints: + title: Tarvitsetko apua? + showHint: Näytä vihje + hideHint: Sulje + + # When placing a blueprint + blueprintPlacer: + cost: Hinta + + # Map markers + waypoints: + waypoints: Merkit + hub: Keskusrakennus + description: Paina merkkia hiiren vasemmalla mennäksesi siihen, paina oikeaa nappia poistaaksesi sen.

Paina luodaksesi merkin nykyisestä näkymästä tai varen nappi luodaksesi merkin valittuun paikkaan. + creationSuccessNotification: Merkki luotiin onnistuneesti. + + # Shape viewer + shapeViewer: + title: Tasot + empty: Tyhjä + copyKey: Kopioi avain + + # Interactive tutorial + interactiveTutorial: + title: Tutoriaali + hints: + 1_1_extractor: Laita Kaivaja ympyrämuodon päälle kaivaaksesi sen! + 1_2_conveyor: >- + Yhdistä kaivaja liukuhihnalla keskusrakennukseen!

Vihje: Paina ja raahaa liukuhihnaa hiirellä! + + 1_3_expand: >- + Tämä EI OLE tyhjäkäyntipeli! Rakenna lisää kaivajia ja hihnoja saadaksesi tavoitteen nopeammin valmiiksi.

Vihje: Pidä pohjassa VAIHTO laittaaksesi useampia kaivajia ja käytä R kääntääksesi niitä. + +# All shop upgrades +shopUpgrades: + belt: + name: Hihnat, Jakelija & Tunneli + description: Nopeus x → x + miner: + name: Kaivuu + description: Nopeus x → x + processors: + name: Leikkaus, Kääntö & Pinoaminen + description: Nopeus x → x + painting: + name: Sekoitus & Värjäys + description: Nopeus x → x + +# Buildings and their name / description +buildings: + hub: + deliver: Toimita + toUnlock: avataksesi + levelShortcut: LVL + + belt: + default: + name: &belt Liukuhihna + description: Kuljettaa esineitä, pidä pohjassa ja raahaa laittaaksesi useampia. + + wire: + default: + name: &wire Johto + description: Sallii sähkön kuljetuksen + + miner: # Internal name for the Extractor + default: + name: &miner Kaivaja + description: Laita muodon tai värin päälle kaivaaksesi sen. + + chainable: + name: Kaivaja (Sarja) + description: Laita muodon tai värin päälle kaivaaksesi sen. Voidaan kytkeä sarjaan. + + underground_belt: # Internal name for the Tunnel + default: + name: &underground_belt Tunneli + description: Sallii resurssien kuljetuksen rakennuksien ja hihnojen alta. + + tier2: + name: Tunneli Taso II + description: Sallii resurssien kuljetuksen rakennuksien ja hihnojen alta. + + splitter: # Internal name for the Balancer + default: + name: &splitter Tasaaja + description: Monikäyttöinen - Jakaa kaikki sisääntulot tasaisesti kaikkiin ulostuloihin. + + compact: + name: Yhdistäjä (Pienikokoinen) + description: Yhdistää kaksi liukuhihnaa yhdeksi. + + compact-inverse: + name: Yhdistäjä (Pienikokoinen) + description: Yhdistää kaksi liukuhihnaa yhdeksi. + + cutter: + default: + name: &cutter Leikkuri + description: Leikkaa muotoja ylhäältä alaspäin ja tuottaa muodon molemmat puoliskot. Jos käytät vain yhden puoliskon, tuhoa toinen puolisko tai se jumittaa leikkurin! + quad: + name: Leikkuri (Neliö) + description: Leikkaa muotoja ylhäältä alaspäin ja tuottaa muodon molemmat puoliskot. Jos käytät vain yhden puoliskon, tuhoa toinen puolisko tai se jumittaa leikkurin! + + advanced_processor: + default: + name: &advanced_processor Edistynyt Käsittelijä + description: Edistynyt muotojen käsittely + + rotater: + default: + name: &rotater Kääntäjä + description: Kääntää muotoja 90 astetta myötäpäivään. + ccw: + name: Rotate (Vastapäivään) + description: Kääntää muotoja 90 astetta vastapäivään. + + stacker: + default: + name: &stacker Pinoaja + description: Pinoaa molemmat tavarat. Jos niitä ei pysty yhdistämään, oikeanpuoleinen tavara laitetaan vasemmanpuoleisen päälle. + + mixer: + default: + name: &mixer Värinsekoittaja + description: Sekoittaa kaksi väriä lisäaineiden avulla. + + painter: + default: + name: &painter Värjääjä + description: &painter_desc Värjää vasemmasta sisääntulosta tulevan muodon ylemmästä sisääntulosta tulevalla värillä. + + mirrored: + name: *painter + description: *painter_desc + + double: + name: Värjääjä (Kaksinkertainen) + description: Värjää vasemmasta sisääntulosta tulevan muodon ylemmästä sisääntulosta tulevalla värillä. + quad: + name: Painter (Neljännes) + description: Sallii muodon neljäsosien värjäämisen eri väreillä. + + trash: + default: + name: &trash Roskakori + description: Sallii sisääntulot kaikilta sivuilta ja tuhoaa ne. Lopullisesti. + + storage: + name: Varasto + description: Varastoi ylimääräisia resursseja tiettyyn kapasiteettiin asti. Voidaan käyttää ylivuotoporttina. + + energy_generator: + deliver: Toimita + + # This will be shown before the amount, so for example 'For 123 Energy' + toGenerateEnergy: Kohden + + default: + name: &energy_generator Sähkögeneraattori + description: Tuottaa sähköä kuluttamalla muotoja. Jokainen sähkögeneraattori vaatii eri muotoja. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. + +storyRewards: + # Those are the rewards gained from completing the store + reward_cutter_and_trash: + title: Muotojen Leikkaus + desc: Avasit Leikkurin - se leikkaa muotoja puoliksi ylhäältä alaspäin riippumatta sen suunnasta!

Varmista, että pääset eroon jätteistä, tai muuten se jumittuu - Tätä varten saat Roskiksen, joka tuhoaa kaiken mitä laitat sinne! + + reward_rotater: + title: Kääntö + desc: Avasit Kääntäjän! Se kääntää muotoja myötäpäivään 90 astetta. + + reward_painter: + title: Värjäys + desc: >- + Avasit Värjääjän - Kaiva joitain värialueita (Samanlailla kuin muotoja) ja yhdistä se muotoon värjääjän avulla!

PS: Jos olet värisokea, asetuksissa on tila värisokeille! + + reward_mixer: + title: Värin Sekoitus + desc: Avasit Värinsekoittajan - Yhdistä kaksi väriä lisäaineiden avulla tällä rakennuksella! + + reward_stacker: + title: Yhdistäjä + desc: Nyt voit yhdistää muotoja Yhdistäjällä! Molemman sisääntulot yhdistetään, jos ne laitetaan vierekkäin, niistä tulee sulatettu. Jos ne eivät ole vierekkäin, oikeanpuoleinen sisääntulo kasataan vasemman päälle! + + reward_splitter: + title: Tasaaja + desc: Avasit monikäyttöisen Tasaajan - Sitä voidaan käyttää isompien tehtaiden rakennukseen jakamaan ja yhdistämään tavaroita monille hihnoille!

+ + reward_tunnel: + title: Tunneli + desc: Avasit Tunnelin - Nyt voit kuljettaa tavaroita liukuhihnoilla rakennusten ja liukuhihnojen alta! + + reward_rotater_ccw: + title: Vastapäivään Kääntö + desc: Avasit uuden muodon Kääntäjästä - Se sallii kääntämisen vastapäivään! Sen voi rakentaa valitsemalla kääntäjän ja painamalla 'T' vaihtaaksesi sen muotoja! + + reward_miner_chainable: + title: Sarja Kaivaja + desc: Avasit Sarja Kaivajan! Se voi välittää sen resurssit muille kaivajille, jotta voit kaivaa resursseja tehokkaammin! + + reward_underground_belt_tier_2: + title: Tunneli Taso II + desc: Avasit uuden muodon Tunnelista - Siinä on pidempi matka, ja voit myös yhdistellä ja sovitella tunneleita! + + reward_splitter_compact: + title: Pienikokoinen Yhdistäjä + desc: >- + Avasit pienikokoisen muodon Yhdistäjästä - Se ottaa kaksi sisääntuloa ja yhdistää ne yhdeksi! + + reward_cutter_quad: + title: Neljäsosa Leikkaus + desc: Avasit muodon Leikkurista - Se sallii muotojen leikkaamisen neljään osaan kahden sijaan! + + reward_painter_double: + title: Kaksinkertainen Värjäys + desc: Avasit muodon Värjääjästä - Se toimii samanlailla kuin normaali värjääjä, mutta käsittelee kaksi muotoa kerrallaan käyttäen vain yhden värin kahden sijaan! + + reward_painter_quad: + title: Neljäsosa Värjäys + desc: Avasit muodon Värjääjästä - Se sallii muodon eri osien värjäämisen erikseen! + + reward_storage: + title: Varasto Puskuri + desc: Avasit muodon Roskiksesta - Se sallii resurssien säilyttämisen tiettyyn kapasiteettiin asti! + + reward_freeplay: + title: Vapaapeli + desc: Sinä teit sen! Avasit Vapaapelitilan! Tämä tarkoittaa sitä, että muodot tehdään nyt satunnaisesti! (Ei hätää, lisää sisältöä on suunnitteilla itsenäiseen peliin!) + + reward_blueprints: + title: Piirustukset + desc: Nyt voit Kopioida ja Liittää paloja tehtaastasi! Valitse alue (pidä pohjassa CTRL ja raahaa hiirellä), ja paina 'C' kopioidaksesi.

Sen liittäminen ei ole ilmaista, sinun täytyy tuottaa piirustus muotoja jotta sinulla on varaa siihen! (Ne mitkä juuri toimitit). + + # Special reward, which is shown when there is no reward actually + no_reward: + title: Seuraava taso + desc: >- + This level gave you no reward, but the next one will!

PS: Better don't destroy your existing factory - You need all those shapes later again to unlock upgrades! + + no_reward_freeplay: + title: Seuraava taso + desc: >- + Onnittelut! Muuten, lisää sisältöä on suunniteltu itsenäiseen versioon! + +settings: + title: Asetukset + categories: + game: Peli + app: Sovellus + + versionBadges: + dev: Kehitys + staging: Näyttämö + prod: Tuotanto + buildDate: Rakennettu + + labels: + uiScale: + title: Käyttöliittymän Koko + description: >- + Muuttaa käyttöliittymän kokoa. Käyttöliittymä skaalataan silti laitteen resoluution perusteella based on your device resolution, mutta tämä asetus määrittää skaalauksen määrän. + scales: + super_small: Erittäin pieni + small: Pieni + regular: Normaali + large: Iso + huge: Valtava + + autosaveInterval: + title: Automaattitallennuksen Aikaväli + description: >- + Määrittää kuinka usein peli tallentaa automaattisesti. Voit myös poistaa automaattisen tallennuksen kokonaan käytöstä täällä. + + intervals: + one_minute: 1 Minuutin välein + two_minutes: 2 Minuutin välein + five_minutes: 5 Minuutin välein + ten_minutes: 10 Minuutin välein + twenty_minutes: 20 Minuutin välein + disabled: Pois käytöstä + + scrollWheelSensitivity: + title: Zoomausherkkyys + description: >- + Vaihtaa kuinka herkkä zoomi on (Joko hiiren rulla tai ohjauslevy). + sensitivity: + super_slow: Erittäin hidas + slow: Hidas + regular: Normaali + fast: Nopea + super_fast: Erittäin nopea + + movementSpeed: + title: Liikkumis nopeus + description: >- + Muuttaa kuinka nopeasti näkymä liikkuu kun käytetään näppäimistöä. + speeds: + super_slow: Erittäin hidas + slow: Hidas + regular: Normaali + fast: Nopea + super_fast: Erittäin nopea + extremely_fast: Hyper nopea + + language: + title: Kieli + description: >- + Vaihda kieltä. Kaikki käännökset ovat käyttäjien tekemiä ja saattavat olla puutteellisia! + + enableColorBlindHelper: + title: Värisokeatila + description: >- + Ottaa käyttöön useita työkaluja, jotka sallivat pelin pelaamisen jos olet värisokea. + + fullscreen: + title: Kokonäyttö + description: >- + On suositeltava pelata tätä peliä kokonäytön tilassa saadaksesi parhaan kokemuksen. Saatavilla vain itsenäisessä versiossa. + + soundsMuted: + title: Mykistä Äänet + description: >- + Jos käytössä, mykistää kaikki ääniefektit. + + musicMuted: + title: Mykistä Musiikki + description: >- + Jos käytössä, mykistää musiikin. + + theme: + title: Pelin Teema + description: >- + Valitse pelin teema (vaalea / tumma). + themes: + dark: Tumma + light: Kirkas + + refreshRate: + title: Simulaatiotavoite + description: >- + Jos sinulla on 144hz näyttö, muuta virkistystaajuus täällä jotta pelin simulaatio toimii oikein isommilla virkistystaajuuksilla. Tämä voi laskea FPS nopeutta jos tietokoneesi on liian hidas. + + alwaysMultiplace: + title: Monisijoitus + description: >- + Jos käytössä, kaikki rakennukset pysyvät valittuina sijoittamisen jälkeen kunnes peruutat sen. Tämä vastaa SHIFT:in pitämistö pohjassa ikuisesti. + + offerHints: + title: Vihjeet & Oppaat + description: >- + Tarjotaanko pelaamisen aikana vihjeitä ja oppaita. Myös piilottaa tietyt käyttöliittymäelementit tietyn tason mukaan, jotta alkuunpääseminen olisi helpompaa. + + enableTunnelSmartplace: + title: Älykkäät Tunnelit + description: >- + Kun käytössä, tunnelin sijoittaminen automaattisesti poistaa tarpeettomat liukuhihnat. Tämä myös ottaa käyttöön tunnelien raahaamisen ja ylimääräiset tunnelit poistetaan. + + vignette: + title: Vignetti + description: >- + Ottaa käyttöön vignetin, joka tummentaa näytön kulmia ja tekee tekstin lukemisesta helpompaa. + + rotationByBuilding: + title: Kiertäminen rakennustyypin mukaan + description: >- + Jokainen rakennustyyppi muistaa kierron, jonka viimeksi asetit yksilöllisesti. Tämä voi olla mukavampi vaihtoehto jos usein sijoitat eri rakennustyyppejä. + + compactBuildingInfo: + title: Kompaktit Rakennusten Tiedot + description: >- + Lyhentää rakennusten tietolaatikoita näyttämällä vain niiden suhteet. Muuten rakennuksen kuvaus ja kuva näytetään. + + disableCutDeleteWarnings: + title: Poista Leikkaus/Poisto Varoitukset + description: >- + Poista varoitusikkunat dialogs brought up when cutting/deleting more than 100 entities. + +keybindings: + title: Pikanäppäimet + hint: >- + Tip: Muista käyttää CTRL, VAIHTO and ALT! Ne ottavat käyttöön erilaisia sijoitteluvaihtoehtoja. + + resetKeybindings: Nollaa Pikanäppäimet + + categoryLabels: + general: Sovellus + ingame: Peli + navigation: Navigointi + placement: Sijoitus + massSelect: Massa Valinta + buildings: Rakennus Pikanäppäimet + placementModifiers: Sijoittelu Muokkaajat + + mappings: + confirm: Vahvista + back: Takaisin + mapMoveUp: Liiku Ylös + mapMoveRight: Liiku Oikealle + mapMoveDown: Liiku Alas + mapMoveLeft: Liiku Vasemmalle + mapMoveFaster: Liiku Nopeammin + centerMap: Keskitä Kartta + + mapZoomIn: Lähennä + mapZoomOut: Loitonna + createMarker: Luo merkki + + menuOpenShop: Päivitykset + menuOpenStats: Tilastot + + toggleHud: Vaihda valikon näkyvyys + toggleFPSInfo: Vaihda FPS and Virheenkorjaus tiedot + switchLayers: Vaihda tasoa + exportScreenshot: Vie koko tukikohta kuvana + belt: *belt + splitter: *splitter + underground_belt: *underground_belt + miner: *miner + cutter: *cutter + advanced_processor: *advanced_processor + rotater: *rotater + stacker: *stacker + mixer: *mixer + energy_generator: *energy_generator + painter: *painter + trash: *trash + wire: *wire + + pipette: Pipetti + rotateWhilePlacing: Käännä + rotateInverseModifier: >- + Modifier: Käännä sen sijaan vastapäivään + cycleBuildingVariants: Valitse muotoja + confirmMassDelete: Poista alue + pasteLastBlueprint: Liitä viimeisin piirustus + cycleBuildings: Valitse Rakennuksia + lockBeltDirection: Ota liukuhihnasuunnittelija käyttöön + switchDirectionLockSide: >- + Planner: Muuta sivua + + massSelectStart: Pidä pohjassa ja raahaa aloittaaksesi + massSelectSelectMultiple: Valitse useita alueita + massSelectCopy: Kopioi alue + massSelectCut: Leikkaa alue + + placementDisableAutoOrientation: Poista automaattinen suunta käytöstä + placeMultiple: Pysy sijoittamistilassa + placeInverse: Käännä automaattinen hihnan suunta + menuClose: Close Menu + +about: + title: Tietoja tästä pelistä + body: >- + Tämä peli on avoimen lähdekoodin ja kehitettä on Tobias Springer (tämä on minä).

+ + Jos haluat osallistua, tarkista shapez.io githubissa.

+ + Tämä peli ei olisi ollut mahdollinen ilman suurta discord yhteisöä pelini ympärillä - Sinun kannattaisi liittyä discord palvelimelleni!

+ + Ääniraidan on tehnyt Peppsen - Hän on mahtava.

+ + Lopuksi, isot kiitokset minun parhaalle kaverilleni Niklas - Ilman meidän factorio istuntoja tätä peliä ei olisi koskaan ollut olemassa. + +changelog: + title: Muutosloki + +demo: + features: + restoringGames: Tallennusten palautus + importingGames: Tallennettujen pelien tuonti + oneGameLimit: Rajoitettu yhteen tallennukseen + customizeKeybindings: Pikanäppäinten mukautus + exportingBase: Viedään koko tukikohta kuvana + + settingNotAvailable: Ei saatavilla demoversiossa. diff --git a/translations/base-fr.yaml b/translations/base-fr.yaml index 7140e456..83cbe026 100644 --- a/translations/base-fr.yaml +++ b/translations/base-fr.yaml @@ -30,49 +30,69 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io est un jeu ayant pour objectif d'automatiser la création et la fusion de formes à l'aide d'une usine. Livrez des formes de plus en plus complexes requises pour progresser dans le jeu et débloquez des améliorations qui accéléreront votre chaîne de production. + shapez.io est un jeu ou il faut construire des usines pour automatiser la création et la transformation de formes de plus en plus complexes sur une carte infinie. + En livrant les bonnes formes tu vas progresser dans le jeu et débloquer des améliorations pour accélerer ton usine. - La demande allant croissant, vous aurez à adapter l'échelle de votre usine afin de suivre la demande - Ne négligez pas les resources cependant, vous aurez à vous étendre sur une [b]carte infinie[/b] ! + Comme la demande de formes augmente, il vas falloir agrandir ton usine pour produire plus - N'oublie pas les resources, il vas falloir s'étendre tout autour de la [b]carte infinie[/b]! - Traiter seulement des formes pouvant devenir monotone à la longue, vous aurez aussi à mélanger des couleurs et à les utiliser pour peindre vos formes - Combinez des pigments rouges, verts ou bleus pour produire différentes couleurs et enduisez-en vos formes afin de satisfaire les demandes. + Puis il vas falloir mélanger les couleurs et peindres tes formes avec - Combine du rouge, du bleu et du vert pour produire différente couleurs et peindre des formes pour satisfaire la demande. - Ce jeu propose 18 niveaux (qui devraient d'ores et déjà vous occuper pour de nombreuses heures !) mais j'ajoute régulièrement de nouveaux contenus - Beaucoup de nouveautés sont prévues ! + Ce jeu propose 18 niveaux progressifs (qui devraient vous occuper pendant des heures!) et j'ajoute constament plus de contenu - Il y en as beaucoup qui arrive! + Acheter le jeu te donnes accès à la version hors-ligne qui as plus de contenu et tu recevras l'accès aux nouvelles fonctionnalités. - [b]Avantage de la version complète[/b] + [b]Avantages de la version hors-ligne[/b] [list] - [*] Balises - [*] Nombre illimité de sauvegardes - [*] Thème sombre - [*] Plus de paramètres de configuration - [*] Acheter la version complète m'aide à poursuivre le développement de shapez.io ❤️ - [*] Encore plus de fonctionnalités à l'avenir ! + [*] Mode sombre + [*] Balises infinies + [*] Sauvegardes infinies + [*] Plus de setting + [*] Arrive bientôt: Cables et éléctricité! Sort en Juillet 2020. + [*] Arrive bientôt: Plus de niveaux + [*] Me permet de plus déveloper le jeu ❤️ [/list] - [b]Fonctionnalités planifiées & suggestions de la communauté[/b] + [b]Mises à jours futures[/b] - Ce jeu est open source - N'importe qui peut contribuer ! En outre, Je suis [b]très attentif[/b] à ce que dit la communauté ! J'essaie de lire toutes les suggestions et de tenir compte des retours autant que possible. + Je fait souvent des mises à jours et essaye d'en sortir une part semaine! [list] - [*] Mode Histoire où les batiments ont un coût en formes - [*] Plus de niveaux et de batiments (en exclusivité dans la version complète) - [*] Différentes cartes, contenant éventuellement des obstacles - [*] Création configurable de carte (éditer le nombre et la taille des gisements de resources, édition de la graine générant la carte, et plus encore) - [*] Davantage de types de formes - [*] Performance améliorée (bien que le jeu tourne déjà de manière tout à fait décente !) - [*] Adaptation de l'affichage des couleurs à différentes formes de daltonisme - [*] Et bien plus encore ! + [*] Plusieurs cartes et challenges (e.g. carte avec des obstacles) + [*] Puzzles (Livrer les formes avec des batiments limités/une carte limitée) + [*] Un mode histoire ou les bâtiments on un coût + [*] Générateur de carte configurable (Configure les ressources/formes leur taille, densité et plus) + [*] Plus de formes + [*] Meilleures performances (Le jeu est déja très optimisé!) + [*] Et bien plus! [/list] - N'hésitez pas à consulter mon tableau trello pour avoir une vue d'ensemble de ce qui est prévu ! https://trello.com/b/ISQncpJP/shapezio + [b]Ce jeu est open source![/b] + + Tout le monde peut contribuer, je suis très impliqué dans la communeauté et essaye de regarder toutes les suggestions et prendre les retours si possible. + Vas voir mon trello pour plus d'informations! + + [b]Liens[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Discord officiel[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Trello[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Code source (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Aide à traduire[/url] + [/list] + + discordLink: Discord officiel - Parles avec moi! global: loading: Chargement error: Erreur # How big numbers are rendered, e.g. "10,000" - thousandsDivider: "." + thousandsDivider: "," + + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "," # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. cf wikipedia système international d'unité # For french: https://fr.wikipedia.org/wiki/Pr%C3%A9fixes_du_Syst%C3%A8me_international_d%27unit%C3%A9s @@ -132,28 +152,6 @@ mainMenu: savegameLevel: Niveau savegameLevelUnknown: Niveau inconnu - contests: - contest_01_03062020: - title: "Concours #01" - desc: Gagnez $25 pour l'usine la plus cool ! - longDesc: >- - Pour vous remercier, j'ai pensé qu'il serait bien de faire un concours hebdomadaire ! -

- Le sujet de cette semaine: Construire l'usine la plus cool ! -

- Voici comment faire:
-
    -
  • Envoyez une capture d'écran de votre usine à contest@shapez.io
  • -
  • Vous aurez des points bonus si vous la partagez sur les réseaux sociaux !
  • -
  • Je choisirai 5 images et les soumettrai au vote à la communauté discord.
  • -
  • Le gagnant empoche $25 (Paypal, carte cadeau Amazon, ce que vous préférez)
  • -
  • Limite: 07.06.2020 AM 12:00 CEST
  • -
-
- J'attends avec impatience de voir vos superbes créations ! - - showInfo: Voir - contestOver: Ce concours est terminé - Rejoignez le serveur discord pour être tenu au courant des prochains concours ! continue: Continuer newGame: Nouvelle partie madeBy: Créé par @@ -262,15 +260,20 @@ dialogs: createMarker: title: Nouvelle balise desc: Donnez-lui un nom, vous pouvez aussi inclure le raccourci d'une forme (Que vous pouvez générer ici) + titleEdit: Edit Marker markerDemoLimit: - desc: Vous ne pouvez créer que deux balises dans la démo. Achetez la version complète pour en faire tant que vous voulez ! + desc: Vous ne pouvez créer que deux balises dans la démo. Achetez la version complète pour en faire autant que vous voulez ! exportScreenshotWarning: title: Exporter une capture d'écran desc: >- Vous avez demandé à exporter votre base sous la forme d'une capture d'écran. Soyez conscient que cela peut s'avérer passablement lent pour une grande base, voire même planter votre jeu ! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -293,6 +296,7 @@ ingame: copySelection: Copier clearSelection: Effacer la sélection pipette: Pipette + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -407,9 +411,11 @@ ingame: cyan: Cyan white: Blanc uncolored: Non coloré + black: Black shapeViewer: title: Calques empty: Vide + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -519,6 +525,27 @@ buildings: deliver: Délivrez toUnlock: pour débloquer levelShortcut: NV + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -533,7 +560,7 @@ storyRewards: reward_painter: title: Peintre desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + Le peintre a été débloqué - Extrayez des pigments de couleur (comme vous le faites avec les formes) et combinez les avec une forme dans un peintre pour les colorier !

PS: Si vous êtes daltonien, il y a un mode daltonien paramétrable dans les préférences ! reward_mixer: title: Mélangeur de couleurs @@ -728,11 +755,10 @@ settings: title: Mode Daltonien description: Active divers outils qui permettent de jouer à ce jeu si vous êtes daltonien. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation par catégorie de bâtiment + description: >- + Chaque catégorie de bâtiment enregistre le sens de rotation que vous lui avez assigné la dernière fois, de manière individuelle. + Cela sera sans doute plus confortable si vous alternez fréquemment entre le placement de différents types de bâtiments. keybindings: title: Contrôles @@ -800,6 +826,11 @@ keybindings: lockBeltDirection: Utiliser le plannificateur de convoyeurs switchDirectionLockSide: "Plannificateur: changer de côté" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: À propos de ce jeu diff --git a/translations/base-hr.yaml b/translations/base-hr.yaml index 2cad65a1..d5858cb1 100644 --- a/translations/base-hr.yaml +++ b/translations/base-hr.yaml @@ -19,60 +19,109 @@ # the basic structure so the game also detects it. # +# +# This is a message in Croatian to all potential contributers. +# +# Za buduće prevoditelje, htio sam na jednom mjestu imati prijevode glavnih +# komponenti igre, a ovaj prostor se činio dovoljno dobro mjesto za to. +# +# Siguran sam da znate kako je naš jezik malo manje fleksibilan što se tiče +# tehničkih pojmova. Teško je naći elegantan prijevod koji se ujedno čini i +# dovoljno dobar/precizan. Zato je svaka nova ideja dobro došla. Možete mi se +# slobodno javiti na Discordu da prokomentiramo eventualne prijevode ili +# novotvorenice za ovu igru. +# +# Prijevodi glavnih elemenata igre: +# GENERALNI POJMOVI +# + Shape = Oblik +# + Upgrade = Nadogradnja +# + Waypoint = Putokaz +# + Blueprint = Nacrt +# GRAĐEVINSKI ELEMENTI +# + Extractor = Rudar (od alternativnog izraza Miner) +# + Extractor (chain) = Rudar (lančani) +# + Conveyor Belt = Pokretna Traka +# + Belt = Traka (shodno prošlom prijevodu) +# + Tunnel = Tunel +# + Merger = Sjedinitelj +# + Rotator = Obrtač (jer mi Okretač zvuči nekako krivo) +# + steamPage: # This is the short text appearing on the steam page - shortText: shapez.io is a game about building factories to automate the creation and combination of increasingly complex shapes within an infinite map. + shortText: shapez.io je igra o izradi tvornica za automatizaciju stvaranja i spajanja sve složenijih oblika unutar beskonačno velike mape. # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. # NOTICE: # - Do not translate the first line (This is the gif image at the start of the store) # - Please keep the markup (Stuff like [b], [list] etc) in the same format + # TODO longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Unlimited Savegames [*] Dark Mode - [*] More settings - [*] Allow me to further develop shapez.io ❤️ - [*] More features in the future! + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - This game is open source - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story mode where buildings cost shapes - [*] More levels & buildings (standalone exclusive) - [*] Different maps, and maybe map obstacles - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] More types of shapes - [*] More performance improvements (Although the game already runs pretty good!) - [*] Color blind mode + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: - loading: Loading - error: Error + loading: Učitavanje + error: Greška # How big numbers are rendered, e.g. "10,000" - thousandsDivider: "," + thousandsDivider: " " + + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: @@ -82,25 +131,28 @@ global: trillions: T # Shown for infinitely big numbers - infinite: inf + infinite: inf # TODO šta s ovim? time: # Used for formatting past time dates - oneSecondAgo: one second ago - xSecondsAgo: seconds ago - oneMinuteAgo: one minute ago - xMinutesAgo: minutes ago - oneHourAgo: one hour ago - xHoursAgo: hours ago - oneDayAgo: one day ago - xDaysAgo: days ago + # + # Short formats used for Croatian due to different word cases causing + # diffrerent suffixes due to declension + oneSecondAgo: prije jedne sekunde + xSecondsAgo: prije s + oneMinuteAgo: prije jedne minute + xMinutesAgo: prije min + oneHourAgo: prije sat vremena + xHoursAgo: prije h + oneDayAgo: prije jedan dan + xDaysAgo: prije dana # Short formats for times, e.g. '5h 23m' - secondsShort: s - minutesAndSecondsShort: m s - hoursAndMinutesShort: h m + secondsShort: s + minutesAndSecondsShort: min s + hoursAndMinutesShort: h min - xMinutes: minutes + xMinutes: min keys: tab: TAB @@ -112,459 +164,476 @@ global: demoBanners: # This is the "advertisement" shown in the main menu and other various places - title: Demo Version + title: Demo Verzija intro: >- - Get the standalone to unlock all features! + Nabavi samostalnu igru kako bi otključao sve značajke! mainMenu: - play: Play - continue: Continue - newGame: New Game - changelog: Changelog - importSavegame: Import - openSourceHint: This game is open source! - discordLink: Official Discord Server - helpTranslate: Help translate! - madeBy: Made by + play: Igraj + continue: Nastavi + newGame: Nova Igra + changelog: Promjene + subreddit: Reddit + importSavegame: Uvezi + openSourceHint: Ovo je igra otvorenog koda! + discordLink: Službeni Discord Server + helpTranslate: Pomogni s prevođenjem! + madeBy: Izradio # This is shown when using firefox and other browsers which are not supported. browserWarning: >- Sorry, but the game is known to run slow on your browser! Get the standalone version or download chrome for the full experience. - savegameLevel: Level - savegameLevelUnknown: Unknown Level + savegameLevel: Nivo + savegameLevelUnknown: Nepoznati Nivo - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- I'm looking forward to seeing your awesome creations! + # TODO - showInfo: View - contestOver: This contest has ended - Join the discord to get noticed about new contests! - subreddit: Reddit dialogs: buttons: ok: OK - delete: Delete - cancel: Cancel - later: Later - restart: Restart - reset: Reset - getStandalone: Get Standalone - deleteGame: I know what I do - viewUpdate: View Update - showUpgrades: Show Upgrades - showKeybindings: Show Keybindings + delete: Izbriši + cancel: Poništi + later: Kasnije + restart: Ponovno pokreni + reset: Resetiraj + getStandalone: Nabavi samostalnu igru + deleteGame: Znam što radim + viewUpdate: Pogledaj ažuriranje + showUpgrades: Pokaži Nadogradnje + showKeybindings: Pokaži tipke importSavegameError: - title: Import Error + title: Greška prilikom uvoza text: >- - Failed to import your savegame: + Neuspješan uvoz spremljene igre: importSavegameSuccess: - title: Savegame Imported + title: Uvoz spremljene igre text: >- - Your savegame has been successfully imported. + Tvoja spremljena igra je uspješno uvezena. gameLoadFailure: - title: Game is broken + title: Igra je pukla text: >- - Failed to load your savegame: + Neuspješno učitavanje spremljene igre: confirmSavegameDelete: - title: Confirm deletion + title: Potvrdi brisanje text: >- - Are you sure you want to delete the game? + Jesi li siguran da želiš izbrisati spremljenu igru? savegameDeletionError: - title: Failed to delete + title: Greška prilikom brisanja text: >- - Failed to delete the savegame: + Neuspješno brisanje spremljene igre: restartRequired: - title: Restart required + title: Potrebno ponovno pokretanje text: >- - You need to restart the game to apply the settings. + Kako bi primijenio postavke, moraš ponovno pokrenuti igru. editKeybinding: - title: Change Keybinding - desc: Press the key or mouse button you want to assign, or escape to cancel. + title: Promijeni tipku + desc: Pritisni tipku ili gumb na mišu kojeg želiš dodijeliti, ili Escape za otkazivanje. resetKeybindingsConfirmation: - title: Reset keybindings - desc: This will reset all keybindings to their default values. Please confirm. + title: Resetiraj tipke + desc: Ovo će resetirati sve tipke na njihove zadane vrijednosti. Potrebna potvrda. keybindingsResetOk: - title: Keybindings reset - desc: The keybindings have been reset to their respective defaults! + title: Tipke resetirane + desc: Tipke su resetirane na svoje zadane vrijednosti! featureRestriction: - title: Demo Version - desc: You tried to access a feature () which is not available in the demo. Consider to get the standalone for the full experience! + title: Demo Verzija + desc: Pokušao si pristupiti značajki () koja nije dostupna u demu. Za puno iskustvo, nabavi samostalnu igru! oneSavegameLimit: - title: Limited savegames - desc: You can only have one savegame at a time in the demo version. Please remove the existing one or get the standalone! + title: Ograničen broj spremljenih igara + desc: Možeš imati samo jednu spremljenu igru u demo verziji. Ukloni postojeću ili nabavi samostalnu igru. updateSummary: - title: New update! + title: Novi update! desc: >- - Here are the changes since you last played: + Evo sve promjene od zadnjeg igranja: + # TODO upgradesIntroduction: - title: Unlock Upgrades + title: Otključaj Nadogradnje desc: >- - All shapes you produce can be used to unlock upgrades - Don't destroy your old factories! - The upgrades tab can be found on the top right corner of the screen. + Svi oblici koji se prozivedu mogu se iskoristiti za otključavanje nadogradnji - Ne preporuča se uništavanje starih tvornica! + Kartica za nadogradnje se može pronaći u gornjem desnom kutu ekrana. massDeleteConfirm: - title: Confirm delete + title: Potvrdi brisanje desc: >- - You are deleting a lot of buildings ( to be exact)! Are you sure you want to do this? + građevina će biti obrisano. Jesi li siguran/na da to želiš? massCutConfirm: - title: Confirm cut + title: Potvrdi rezanje desc: >- - You are cutting a lot of buildings ( to be exact)! Are you sure you want to do this? + građevina će biti izrezano! Jesi li siguran/na da to želiš? blueprintsNotUnlocked: - title: Not unlocked yet + title: Nije otključano desc: >- - Complete level 12 to unlock Blueprints! + Dovrši 12 nivo kako bi otključao Nacrte. keybindingsIntroduction: - title: Useful keybindings + title: Korisne tipke desc: >- - This game has a lot of keybindings which make it easier to build big factories. - Here are a few, but be sure to check out the keybindings!

- CTRL + Drag: Select an area.
- SHIFT: Hold to place multiple of one building.
- ALT: Invert orientation of placed belts.
+ Igra ima mnogo korisnih tipki, koje olakšavaju izgradnju velikih tvornica. + Evo ih nekoliko, ali svakako se preporuča pogledati sve tipke!

+ CTRL + Miš: Odaberi područje.
+ SHIFT: Držati za postavljanje više istih zgrada odjednom.
+ ALT: Obrni smjer postavljenih pokretnih traka.
createMarker: - title: New Marker - desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + title: Novi Putokaz + desc: Daj mu smisleno ime. Može se uključiti i kratki kod oblika. (Koju možeš generirati ovdje) + titleEdit: Edit Marker markerDemoLimit: - desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! + desc: U demo verziji se mogu stvoriti samo dva putokaza istovremeno. Nabavi samostalnu igru za beskonačno mnogo putokaza! exportScreenshotWarning: - title: Export screenshot - desc: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game! + title: Izvezi sliku zaslona + desc: Zatražen je izvoz cijele baze u obliku slike zaslone. Ovo može biti jako sporo za velike tvornice, a može i srušiti igru! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? ingame: # This is shown in the top left corner and displays useful keybindings in # every situation keybindingsOverlay: - moveMap: Move - selectBuildings: Select area - stopPlacement: Stop placement - rotateBuilding: Rotate building - placeMultiple: Place multiple - reverseOrientation: Reverse orientation - disableAutoOrientation: Disable auto orientation - toggleHud: Toggle HUD - placeBuilding: Place building - createMarker: Create Marker - delete: Destroy - pasteLastBlueprint: Paste last blueprint - lockBeltDirection: Enable belt planner - plannerSwitchSide: Flip planner side - cutSelection: Cut - copySelection: Copy - clearSelection: Clear Selection - pipette: Pipette + moveMap: Kretanje #Move + selectBuildings: Odaberi područje #Select area + stopPlacement: Prekini postavljenje #Stop placement + rotateBuilding: Okreći građevinu #Rotate building + placeMultiple: Postavi više odjednom #Place multiple + reverseOrientation: Obrni orijentaciju #Reverse orientation + disableAutoOrientation: Onemogući automatsku orijentaciju #Disable auto orientation + toggleHud: Uključi/Isključi HUD #Toggle HUD + placeBuilding: Smjesti građevinu #Place building + createMarker: Stvori Putokaz + delete: Uništi + pasteLastBlueprint: Zalijepi zadnji nacrt # Paste last blueprint + lockBeltDirection: Onemogući planiranje traka # Enable belt planner + plannerSwitchSide: Okreni stranu planera # Flip planner side + cutSelection: Izreži + copySelection: Kopiraj + clearSelection: Očisti odabir + pipette: Pipeta + switchLayers: Promijeni sloj + # Names of the colors, used for the color blind mode + colors: + red: Crvena + green: Zelena + blue: Plava + yellow: Žuta + purple: Ljubičasta + cyan: Cijan + white: Bijela + black: Crna + uncolored: Bez boje # 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: Press to cycle variants. + cycleBuildingVariants: Pritisni za različite varijante. # Shows the hotkey in the ui, e.g. "Hotkey: Q" hotkeyLabel: >- - Hotkey: + Tipka: infoTexts: - speed: Speed - range: Range - storage: Storage - oneItemPerSecond: 1 item / second - itemsPerSecond: items / s + speed: Brzina + range: Domet + storage: Skladište + oneItemPerSecond: 1 predmet / sekundi + itemsPerSecond: predmeta / s itemsPerSecondDouble: (x2) - tiles: tiles + tiles: polja # The notification when completing a level levelCompleteNotification: # is replaced by the actual level, so this gets 'Level 03' for example. - levelTitle: Level - completed: Completed - unlockText: Unlocked ! - buttonNextLevel: Next Level + levelTitle: Nivo + completed: Dovršeno + unlockText: Otključano je ! + buttonNextLevel: Idući nivo # Notifications on the lower right notifications: - newUpgrade: A new upgrade is available! - gameSaved: Your game has been saved. + newUpgrade: Nova nadogradnja je dostupna! + gameSaved: Igra je spremljena. # The "Upgrades" window shop: - title: Upgrades - buttonUnlock: Upgrade + title: Nadogradnje + buttonUnlock: Nadogradi # Gets replaced to e.g. "Tier IX" - tier: Tier + tier: Razina # The roman number for each tier tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X] - maximumLevel: MAXIMUM LEVEL (Speed x) + maximumLevel: MAKSIMALNI LEVEL (Brzina x) # The "Statistics" window statistics: - title: Statistics + title: Statistika dataSources: stored: - title: Stored - description: Displaying amount of stored shapes in your central building. + title: Pohranjeno + description: Količine pohranjenih oblika u središnjoj građevini. produced: - title: Produced - description: Displaying all shapes your whole factory produces, including intermediate products. + title: Proizvedeno + description: Svi oblici koje proizvodi cijela tvornica, uključujući i međuproizvode. delivered: - title: Delivered - description: Displaying shapes which are delivered to your central building. - noShapesProduced: No shapes have been produced so far. + title: Dostavljeno + description: Oblici koji se dostavljaju u središnju građevinu. + noShapesProduced: Za sada nema proizvedenih oblika. # Displays the shapes per minute, e.g. '523 / m' - shapesPerMinute: / m + shapesPerMinute: / min # Settings menu, when you press "ESC" settingsMenu: - playtime: Playtime + playtime: Vrijeme igranja - buildingsPlaced: Buildings - beltsPlaced: Belts + buildingsPlaced: Građevine + beltsPlaced: Trake buttons: - continue: Continue - settings: Settings - menu: Return to menu + continue: Nastavi + settings: Postavke + menu: Vrati se u glavni izbornik # Bottom left tutorial hints tutorialHints: - title: Need help? - showHint: Show hint - hideHint: Close + title: Trebaš pomoć? + showHint: Savjet za gradnju + hideHint: Zatvori # When placing a blueprint blueprintPlacer: - cost: Cost + cost: Cijena # Map markers waypoints: - waypoints: Markers - hub: HUB - description: Left-click a marker to jump to it, right-click to delete it.

Press to create a marker from the current view, or right-click to create a marker at the selected location. - creationSuccessNotification: Marker has been created. + waypoints: Putokazi + hub: Središte + description: Klikni lijevim klikom na marker kako bi skočio na njegovu lokaciju, a izbriši ga desnim klikom.

Za stvaranje markera pritisni , ili desnim klikom stvori marker na odabranoj lokaciji. + creationSuccessNotification: Putokaz stvoren. + + # Shape viewer + shapeViewer: + title: Slojevi + empty: Prazno + copyKey: Kopiraj # TODO ispraviti ovo/correct this # Interactive tutorial interactiveTutorial: - title: Tutorial + title: Tutorijal hints: - 1_1_extractor: Place an extractor on top of a circle shape to extract it! + 1_1_extractor: Stavi Rudara na oblik kruga kako bi se izvukao iz tla! 1_2_conveyor: >- - Connect the extractor with a conveyor belt to your hub!

Tip: Click and drag the belt with your mouse! + Spoji rudara na središnju građevinu (HUB) koristeći pokretnu traku.

Savjet: Pritisni i povlači traku mišem! 1_3_expand: >- - This is NOT an idle game! Build more extractors and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them. - - colors: - red: Red - green: Green - blue: Blue - yellow: Yellow - purple: Purple - cyan: Cyan - white: White - uncolored: No color - shapeViewer: - title: Layers - empty: Empty + Ovo NIJE igra čekanja! Više rudara i pokretnih traka će ubrzati napredak do cilja.

Savjet: Drži SHIFT za postavljanje više rudara istovremeno, a pritisni R za rotaciju. # All shop upgrades shopUpgrades: belt: - name: Belts, Distributor & Tunnels - description: Speed x → x + name: Trake, Distributer i Tuneli + description: Brzina x → x miner: - name: Extraction - description: Speed x → x + name: Rudarenje + description: Brzina x → x processors: - name: Cutting, Rotating & Stacking - description: Speed x → x + name: Rezanje, Okretanje i Slaganje + description: Brzina x → x painting: - name: Mixing & Painting - description: Speed x → x + name: Miješanje i Bojanje + description: Brzina x → x # Buildings and their name / description buildings: hub: - deliver: Deliver - toUnlock: to unlock + deliver: Dostavi + toUnlock: kako bi otključao levelShortcut: LVL belt: default: - name: &belt Conveyor Belt + name: &belt Pokretna Traka description: Transports items, hold and drag to place multiple. + wire: + default: + name: &wire Žica + description: Dopušta prijenos energije + miner: # Internal name for the Extractor default: - name: &miner Extractor + name: &miner Rudar description: Place over a shape or color to extract it. chainable: - name: Extractor (Chain) + name: Rudar (Lančani) description: Place over a shape or color to extract it. Can be chained. underground_belt: # Internal name for the Tunnel default: - name: &underground_belt Tunnel + name: &underground_belt Tunel description: Allows to tunnel resources under buildings and belts. tier2: - name: Tunnel Tier II + name: Tunel razine II description: Allows to tunnel resources under buildings and belts. splitter: # Internal name for the Balancer default: - name: &splitter Balancer - description: Multifunctional - Evenly distributes all inputs onto all outputs. + name: &splitter Balanser + description: Multifunkcionalan - Jednoliko raspodijeljuje sve ulaze na sve izlaze. compact: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Sjedinitelj (kompaktni) + description: Sjedinjuje dvije pokretne trake u jednu. compact-inverse: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Sjedinitelj (kompaktni) + description: Sjedinjuje dvije pokretne trake u jednu. cutter: default: - name: &cutter Cutter - description: Cuts shapes from top to bottom and outputs both halfs. If you use only one part, be sure to destroy the other part or it will stall! + name: &cutter Rezač + description: Reže oblike od vrha prema dnu i na izlaze daje obe polovice. Ako se koristi samo jedan dio, drugi se mora uništiti da bi se spriječio zastoj! quad: - name: Cutter (Quad) - description: Cuts shapes into four parts. If you use only one part, be sure to destroy the other parts or it will stall! + name: Rezač (Četverostruki) + description: Reže oblike u četiri dijela. Ako se koristi samo jedan dio, ostali se moraju uništiti da bi se spriječio zastoj! + + advanced_processor: + default: + name: &advanced_processor Napredni Procesor + description: Napredna obrada Oblika rotater: default: - name: &rotater Rotate - description: Rotates shapes clockwise by 90 degrees. + name: &rotater Obrtač (↻) + description: Okreće oblike za 90 stupnjeva u smjeru kazaljke na satu. ccw: - name: Rotate (CCW) - description: Rotates shapes counter clockwise by 90 degrees. + name: Obrtač (↺) + description: Okreće oblike za 90 stupnjeva u smjeru suprotnom od kazaljke na satu. stacker: default: - name: &stacker Stacker - description: Stacks both items. If they can not be merged, the right item is placed above the left item. + name: &stacker Slagač + description: Slaže jedan oblik na drugi. Ako se ne mogu spojiti, desni oblik se postavlja na vrh lijevog. mixer: default: - name: &mixer Color Mixer - description: Mixes two colors using additive blending. + name: &mixer Miješalica boja + description: Spaja dvije boje koristeći aditivno miješanje. painter: default: - name: &painter Painter - description: &painter_desc Colors the whole shape on the left input with the color from the top input. + name: &painter Bojač + description: &painter_desc Boja cijeli oblik na lijevom ulazu bojom s gornjeg ulaza. mirrored: name: *painter description: *painter_desc double: - name: Painter (Double) - description: Colors the shapes on the left inputs with the color from the top input. + name: Bojač (Dupli) + description: Boja oblike na lijevom ulazu bojom s gornjeg ulaza. quad: - name: Painter (Quad) - description: Allows to color each quadrant of the shape with a different color. + name: Bojač (Četverostruki) + description: Dopušta bojanje svake četvrtine oblika različitom bojom. trash: default: - name: &trash Trash - description: Accepts inputs from all sides and destroys them. Forever. + name: &trash Smeće + description: Prima stvari sa svih strana i uništava ih. Zauvijek. storage: - name: Storage - description: Stores excess items, up to a given capacity. Can be used as an overflow gate. + name: Skladište + description: Skladišti višak stvari do određenog kapaciteta. Može se koristiti kao zaštita od preljeva. + + energy_generator: + deliver: Dostavi + + # This will be shown before the amount, so for example 'For 123 Energy' + toGenerateEnergy: Za + + default: + name: &energy_generator Generator + description: Proizvodi energiju iz oblika. Svaki generator zahtijeva različiti oblik. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store reward_cutter_and_trash: - title: Cutting Shapes - desc: You just unlocked the cutter - it cuts shapes half from top to bottom regardless of its orientation!

Be sure to get rid of the waste, or otherwise it will stall - For this purpose I gave you a trash, which destroys everything you put into it! + title: Rezanje Oblika + desc: Rezač je otključan! Ovaj stroj reže oblike od vrha prema dnu bez obzira na orijentaciju građevine!

Višak se mora odbaciti kako bi se izbjegao zastoj. - Za tu svrhu postoji smeće, koje uništava sve što u njega uđe. reward_rotater: - title: Rotating - desc: The rotater has been unlocked! It rotates shapes clockwise by 90 degrees. + title: Obrtanje + desc: Obrtač je otključan! Ovaj stroj okreće oblike za 90 stupnjeva u smjeru kazaljke na satu. reward_painter: title: Painting desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + Bojač je otključan - Boja se (kao i oblici) može rudariti i spojiti s oblikom u bojaču!

PS: Postoji opcija za daltonizam u postavkama! reward_mixer: - title: Color Mixing - desc: The mixer has been unlocked - Combine two colors using additive blending with this building! + title: Miješalica boja + desc: Miješalica boja je otključana - U ovoj se građevini dvije boje mogu spojiti koristeći aditivno miješanje! reward_stacker: - title: Combiner - desc: You can now combine shapes with the combiner! Both inputs are combined, and if they can be put next to each other, they will be fused. If not, the right input is stacked on top of the left input! + title: Slagač + desc: Sada se dva oblika mogu spojiti slagačem! Oblici s oba ulaza se spajaju - ako se mogu staviti jedan kraj drugoga, biti će spojeni. Ako ne, desni ulaz se slaže na vrh lijevog! reward_splitter: - title: Splitter/Merger - desc: The multifunctional balancer has been unlocked - It can be used to build bigger factories by splitting and merging items onto multiple belts!

+ title: Razdjeljivanje i sjedinjavanje + desc: Multifunkcionalni balancer je otključan! Može ga se iskoristiti za razdjeljivanje i sjedinjavanje oblika na više pokretnih traka!

reward_tunnel: - title: Tunnel - desc: The tunnel has been unlocked - You can now tunnel items through belts and buildings with it! + title: Tunel + desc: Tunel je otključan - Omogućava slanje stvari ispod traka i ostalih građevina! reward_rotater_ccw: - title: CCW Rotating - desc: You have unlocked a variant of the rotater - It allows to rotate counter clockwise! To build it, select the rotater and press 'T' to cycle its variants! + title: Rotacija u smjeru suprotnom od kazaljke na satu + desc: Varijanta obrtača je otključana - Omogućuje okretanje u smjeru suprotnom od kazaljke! Odaberi obrtač i pritisni 'T' za mijenjanje njegove varijante! reward_miner_chainable: - title: Chaining Extractor - desc: You have unlocked the chaining extractor! It can forward its resources to other extractors so you can more efficiently extract resources! + title: Lančani rudar + desc: Otključan je lančani rudar! Može proslijediti svoje resurse drugim rudarima za efikasnije rudarenje! reward_underground_belt_tier_2: - title: Tunnel Tier II - desc: You have unlocked a new variant of the tunnel - It has a bigger range, and you can also mix-n-match those tunnels now! + title: Tunel Razine II + desc: Otključana je nova varijanta tunela - Ima veći domet, a uz se sada mogu kombinirati vrste tunela. reward_splitter_compact: - title: Compact Balancer + title: Kompaktni Balanser desc: >- - You have unlocked a compact variant of the balancer - It accepts two inputs and merges them into one! + You have unlocked a compact variant of the balanser - It accepts two inputs and merges them into one! reward_cutter_quad: title: Quad Cutting @@ -602,10 +671,10 @@ storyRewards: Congratulations! By the way, more content is planned for the standalone! settings: - title: Settings + title: Postavke categories: - game: Game - app: Application + game: Igra + app: Aplikacija versionBadges: dev: Development @@ -615,195 +684,201 @@ settings: labels: uiScale: - title: Interface scale + title: Veličina sučelja description: >- Changes the size of the user interface. The interface will still scale based on your device resolution, but this setting controls the amount of scale. scales: - super_small: Super small - small: Small - regular: Regular - large: Large - huge: Huge + super_small: Jako maleno + small: Maleno + regular: Normalno + large: Veliko + huge: Ogromno + + autosaveInterval: + title: Interval Automatskog Spremanja + description: >- + Upravlja koliko se često pokreće automatsko spremanje igre. Također se ta funkcionalnost može u potpunosti isključiti. + + intervals: + one_minute: 1 minuta + two_minutes: 2 minute + five_minutes: 5 minuta + ten_minutes: 10 minuta + twenty_minutes: 20 minuta + disabled: Onemogući scrollWheelSensitivity: - title: Zoom sensitivity + title: Osjetljivost zumiranja description: >- Changes how sensitive the zoom is (Either mouse wheel or trackpad). sensitivity: - super_slow: Super slow - slow: Slow - regular: Regular - fast: Fast - super_fast: Super fast + super_slow: Jako sporo + slow: Sporo + regular: Normalno + fast: Brzo + super_fast: Jako brzo movementSpeed: - title: Movement speed + title: Brzina kretanja description: >- - Changes how fast the view moves when using the keyboard. + Mijenja brzinu kretanja kamere pri korištenju tipkovnice. speeds: - super_slow: Super slow - slow: Slow - regular: Regular - fast: Fast - super_fast: Super Fast - extremely_fast: Extremely Fast + super_slow: Jako Sporo + slow: Sporo + regular: Umjereno + fast: Brzo + super_fast: Jako Brzo + extremely_fast: Iznimno Brzo language: - title: Language + title: Jezik description: >- - Change the language. All translations are user contributed and might be incomplete! + Promijeni jezik igre. Sve prijevode su napravili korisnici volonteri i mogu biti nedovršeni. + + enableColorBlindHelper: + title: Opcija za daltonizam + description: >- + Omogućuje razne alate koji pomožu pri igranju igre s nekim oblikom sljepoće na boju. fullscreen: - title: Fullscreen + title: Puni zaslon description: >- - It is recommended to play the game in fullscreen to get the best experience. Only available in the standalone. + Preporuča se, radi najboljeg iskustva, igrati igru na punom zaslonu. Dostupno samo u samostalnoj igri. soundsMuted: - title: Mute Sounds + title: Utišaj Zvukove description: >- - If enabled, mutes all sound effects. + Ako je odabrano, svi zvukovi su utišani. musicMuted: - title: Mute Music + title: Utišaj Glazbu description: >- - If enabled, mutes all music. + Ako je odabrano, glazba je utišana. theme: - title: Game theme + title: Tema Igre description: >- - Choose the game theme (light / dark). + Odaberi temu igre (svijetlo/tamno). themes: - dark: Dark - light: Light + dark: Tamno + light: Svijetlo refreshRate: - title: Simulation Target + title: Simulacija za 144 Hz description: >- - If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates. This might actually decrease the FPS if your computer is too slow. + Opcija za monitore visoke frekvencije osvježavanje. Ovo može smanjiti FPS ako je računalo presporo. alwaysMultiplace: - title: Multiplace + title: Višestruko postavljanje description: >- - If enabled, all buildings will stay selected after placement until you cancel it. This is equivalent to holding SHIFT permanently. + Ako je omogućeno, sve građevine će ostati odabrane nakon što su postavljene, dok se poništenje ne odradi ručno. offerHints: - title: Hints & Tutorials + title: Savjeti i Upute description: >- - 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. + Opcija za pokazivanje savjeta i uputa za vrijeme igre. Dodatno sakriva određene elemente sučelja dok nisu otključani za lakše učenje igre. enableTunnelSmartplace: - title: Smart Tunnels + title: Pametni Tuneli description: >- - When enabled, placing tunnels will automatically remove unnecessary belts. This also enables to drag tunnels and excess tunnels will get removed. + Ako je omogućeno, postavljanje tunela automatski briše nepotrebne pokretne trake. Također omogućuje povlačenje tunela i brisanje višak tunela. vignette: - title: Vignette + title: Vinjeta description: >- - Enables the vignette which darkens the screen corners and makes text easier to read. + Omogućeva efekt vinjete - zatamnjenje rubova ekrana. - autosaveInterval: - title: Autosave Interval + rotationByBuilding: + title: Rotation by building type description: >- - Controls how often the game saves automatically. You can also disable it - entirely here. - intervals: - one_minute: 1 Minute - two_minutes: 2 Minutes - five_minutes: 5 Minutes - ten_minutes: 10 Minutes - twenty_minutes: 20 Minutes - disabled: Disabled + Each building type remembers the rotation you last set it to individually. This may be more comfortable if you frequently switch between placing different building types. + compactBuildingInfo: title: Compact Building Infos description: >- - Shortens info boxes for buildings by only showing their ratios. Otherwise a - description and image is shown. + Shortens info boxes for buildings by only showing their ratios. Otherwise a description and image is shown. + disableCutDeleteWarnings: title: Disable Cut/Delete Warnings description: >- - Disable the warning dialogs brought up when cutting/deleting more than 100 - entities. - - enableColorBlindHelper: - title: Color Blind Mode - description: Enables various tools which allow to play the game if you are color blind. - rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + Disables the warning dialogs brought up when cutting/deleting more than 100 entities. keybindings: - title: Keybindings - hint: >- - Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different placement options. + title: Tipka + hint: >- #TODO + Savjet: Be sure to make use of CTRL, SHIFT and ALT! They enable different placement options. - resetKeybindings: Reset Keybindings + resetKeybindings: Ponovno postavi sve tipke categoryLabels: - general: Application - ingame: Game - navigation: Navigating - placement: Placement - massSelect: Mass Select - buildings: Building Shortcuts - placementModifiers: Placement Modifiers + general: Aplikacija + ingame: Igra + navigation: Navigacija + placement: Smještanje + massSelect: Masovno Odabiranje + buildings: Kratice Građevina + placementModifiers: Modifikatori Smještanja + #TODO mappings: - confirm: Confirm - back: Back - mapMoveUp: Move Up - mapMoveRight: Move Right - mapMoveDown: Move Down - mapMoveLeft: Move Left - mapMoveFaster: Move Faster + confirm: Potvrdi + back: Nazad + mapMoveUp: Idi Gore + mapMoveRight: Idi Desno + mapMoveDown: Idi dolje + mapMoveLeft: Idi lijevo + mapMoveFaster: Brže kretanje centerMap: Center Map - mapZoomIn: Zoom in - mapZoomOut: Zoom out - createMarker: Create Marker + mapZoomIn: Zumiraj + mapZoomOut: Umanji + createMarker: Stvori novi Putokaz - menuOpenShop: Upgrades - menuOpenStats: Statistics + menuOpenShop: Nadogradnje + menuOpenStats: Statistika - toggleHud: Toggle HUD - toggleFPSInfo: Toggle FPS and Debug Info - exportScreenshot: Export whole Base as Image + toggleHud: Upali/Ugasi HUD + toggleFPSInfo: Upali/Ugasi informacije o traženju grešaka u kodu + switchLayers: Promijeni sloj + exportScreenshot: Izvezi cijelu Bazu kao Sliku belt: *belt splitter: *splitter underground_belt: *underground_belt miner: *miner cutter: *cutter + advanced_processor: *advanced_processor rotater: *rotater stacker: *stacker mixer: *mixer + energy_generator: *energy_generator painter: *painter trash: *trash + wire: *wire - rotateWhilePlacing: Rotate + pipette: Pipeta + rotateWhilePlacing: Rotiraj rotateInverseModifier: >- - Modifier: Rotate CCW instead - cycleBuildingVariants: Cycle Variants - confirmMassDelete: Confirm Mass Delete - pasteLastBlueprint: Paste last blueprint - cycleBuildings: Cycle Buildings - lockBeltDirection: Enable belt planner + Modifikator: Rotiraj u smjeru suprotnom od kazaljke na satu + cycleBuildingVariants: Mijenjaj Varijante + confirmMassDelete: Potvrdi Masovno Brisanje + pasteLastBlueprint: Zalijepi posljednji Nacrt + cycleBuildings: Mijenjaj građevine + lockBeltDirection: Omogući planer pokretnih traka switchDirectionLockSide: >- - Planner: Switch side + Planer: Obrni stranu - massSelectStart: Hold and drag to start - massSelectSelectMultiple: Select multiple areas - massSelectCopy: Copy area - massSelectCut: Cut area - - placementDisableAutoOrientation: Disable automatic orientation - placeMultiple: Stay in placement mode - placeInverse: Invert automatic belt orientation - pipette: Pipette + massSelectStart: Pritisni i zadrži za započinjanje + massSelectSelectMultiple: Odaberi više područja + massSelectCopy: Kopiraj područje + massSelectCut: Izreži područje + placementDisableAutoOrientation: Onemogući automatsku orijentaciju + placeMultiple: Ostani u modusu za smještanje + placeInverse: Obrni automatsku orijentaciju pokretnih traka + menuClose: Close Menu +#TODO about: - title: About this Game + title: O Igri body: >- This game is open source and developed by Tobias Springer (this is me).

@@ -816,14 +891,14 @@ about: Finally, huge thanks to my best friend Niklas - Without our factorio sessions this game would never have existed. changelog: - title: Changelog + title: Ispravci demo: features: - restoringGames: Restoring savegames - importingGames: Importing savegames - oneGameLimit: Limited to one savegame - customizeKeybindings: Customizing Keybindings - exportingBase: Exporting whole Base as Image + restoringGames: Obnavljanje spremljenih igara + importingGames: Uvoz spremeljenih igara + oneGameLimit: Ograničeno na jednu spremljenu igru + customizeKeybindings: Prilagodba Tipki + exportingBase: Izvoz cijele Baze u obliku Slike - settingNotAvailable: Not available in the demo. + settingNotAvailable: Nije dostupno u demo verziji. diff --git a/translations/base-hu.yaml b/translations/base-hu.yaml index 45a51e37..ebdf03af 100644 --- a/translations/base-hu.yaml +++ b/translations/base-hu.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Végtelen mentések - [*] Sötét Mód - [*] Több beállítás - [*] Lehetővé teszed, hogy tovább fejlesszem a shapez.io-t ❤️ - [*] More features in the future! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - Ez a játék nyílt forráskódú - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Sztori mód, ahol az épületek alakzatokba kerülnek - [*] Több szint és épület (standalone exclusive) - [*] Különböző térképek, és talán akadályok - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] Sokkal több alakzat - [*] More performance improvements (Bár a játék így is elég jól fut!) - [*] Színvak mód + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Betöltés @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: E @@ -131,28 +151,7 @@ mainMenu: savegameLevel: . szint savegameLevelUnknown: Ismeretlen szint - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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! continue: Continue newGame: New Game madeBy: Made by @@ -255,6 +254,7 @@ dialogs: createMarker: title: New Marker desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker markerDemoLimit: desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! @@ -270,6 +270,10 @@ dialogs: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -292,6 +296,7 @@ ingame: copySelection: Copy clearSelection: Clear Selection pipette: Pipette + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -407,9 +412,11 @@ ingame: cyan: Cyan white: White uncolored: No color + black: Black shapeViewer: title: Layers empty: Empty + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -516,6 +523,27 @@ buildings: deliver: Deliver toUnlock: to unlock levelShortcut: LVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -727,11 +755,11 @@ settings: title: Color Blind Mode description: Enables various tools which allow to play the game if you are color blind. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. + This may be more comfortable if you frequently switch between placing + different building types. keybindings: title: Keybindings @@ -799,6 +827,11 @@ keybindings: lockBeltDirection: Enable belt planner switchDirectionLockSide: "Planner: Switch side" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: A játékról diff --git a/translations/base-it.yaml b/translations/base-it.yaml index 412d947a..8583a102 100644 --- a/translations/base-it.yaml +++ b/translations/base-it.yaml @@ -21,7 +21,7 @@ steamPage: # This is the short text appearing on the steam page - shortText: shapez.io is a game about building factories to automate the creation and combination of increasingly complex shapes within an infinite map. + shortText: In shapez.io potrai costruire delle fabbriche per automatizzare la creazione e la combinazione di forme sempre più complesse, in una mappa infinita. # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. # NOTICE: @@ -30,50 +30,70 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Unlimited Savegames [*] Dark Mode - [*] More settings - [*] Allow me to further develop shapez.io ❤️ - [*] More features in the future! + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - This game is open source - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story mode where buildings cost shapes - [*] More levels & buildings (standalone exclusive) - [*] Different maps, and maybe map obstacles - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] More types of shapes - [*] More performance improvements (Although the game already runs pretty good!) - [*] Color blind mode + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: - loading: Loading - error: Error + loading: Caricamento + error: Errore # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -86,251 +106,236 @@ global: time: # Used for formatting past time dates - oneSecondAgo: one second ago - xSecondsAgo: seconds ago - oneMinuteAgo: one minute ago - xMinutesAgo: minutes ago - oneHourAgo: one hour ago - xHoursAgo: hours ago - oneDayAgo: one day ago - xDaysAgo: days ago + oneSecondAgo: un secondo fa + xSecondsAgo: secondi fa + oneMinuteAgo: un minuto fa + xMinutesAgo: minuti fa + oneHourAgo: un'ora fa + xHoursAgo: ore fa + oneDayAgo: un giorno fa + xDaysAgo: giorni fa # Short formats for times, e.g. '5h 23m' secondsShort: s minutesAndSecondsShort: m s - hoursAndMinutesShort: h s + hoursAndMinutesShort: h m - xMinutes: minutes + xMinutes: minuti keys: tab: TAB control: CTRL alt: ALT escape: ESC - shift: SHIFT - space: SPACE + shift: MAIUSC + space: SPAZIO demoBanners: # This is the "advertisement" shown in the main menu and other various places - title: Demo Version + title: Versione Demo intro: >- - Get the standalone to unlock all features! + Ottieni la versione standalone per sbloccare tutte le funzioni! mainMenu: play: Play changelog: Changelog - importSavegame: Import - openSourceHint: This game is open source! - discordLink: Official Discord Server - helpTranslate: Help translate! + importSavegame: Importa + openSourceHint: Questo gioco è open source! + discordLink: Server ufficiale Discord + helpTranslate: Aiutaci a tradurre! # This is shown when using firefox and other browsers which are not supported. browserWarning: >- - Sorry, but the game is known to run slow on your browser! Get the standalone version or download chrome for the full experience. + Ci spiace, ma il gioco è molto lento su questo browser! Ottieni la versione standalone oppure scarica Chrome per provare l'esperienza completa. - savegameLevel: Level - savegameLevelUnknown: Unknown Level + savegameLevel: Livello + savegameLevelUnknown: Livello sconosciuto - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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! - continue: Continue - newGame: New Game - madeBy: Made by + continue: Continua + newGame: Nuova partita + madeBy: Creato da subreddit: Reddit dialogs: buttons: ok: OK - delete: Delete - cancel: Cancel - later: Later - restart: Restart + delete: Elimina + cancel: Annulla + later: Più tardi + restart: Ricomincia reset: Reset - getStandalone: Get Standalone - deleteGame: I know what I do - viewUpdate: View Update - showUpgrades: Show Upgrades - showKeybindings: Show Keybindings + getStandalone: Ottieni la versione completa + deleteGame: So cosa sto facendo + viewUpdate: Mostra aggiornamento + showUpgrades: Mostra upgrade + showKeybindings: Mostra scorciatoie importSavegameError: - title: Import Error + title: Errore di importazione text: >- - Failed to import your savegame: + Impossibile caricare il salvataggio: importSavegameSuccess: - title: Savegame Imported + title: Salvataggio importato text: >- - Your savegame has been successfully imported. + Il tuo salvataggio è stato importato correttamente. gameLoadFailure: - title: Game is broken + title: Partita malfunzionante text: >- - Failed to load your savegame: + Impossibile caricare il salvataggio: confirmSavegameDelete: - title: Confirm deletion + title: Conferma eliminazione text: >- - Are you sure you want to delete the game? + Vuoi davvero eliminare la partita? savegameDeletionError: - title: Failed to delete + title: Impossibile eliminare text: >- - Failed to delete the savegame: + Impossibile eliminare il salvataggio: restartRequired: - title: Restart required + title: Restart richiesto text: >- - You need to restart the game to apply the settings. + Per applicare le nuove impostazioni è necessario il Restart del gioco. editKeybinding: - title: Change Keybinding - desc: Press the key or mouse button you want to assign, or escape to cancel. + title: Cambia comandi + desc: Premi un nuovo tasto o un tasto del mouse a cui vuoi assegnare questo comando, Esc per cancellarlo. resetKeybindingsConfirmation: - title: Reset keybindings - desc: This will reset all keybindings to their default values. Please confirm. - + title: Reset comandi assegnati + desc: Così riporterai tutti comandi al loro stato di default. Perfavore conferma. keybindingsResetOk: - title: Keybindings reset - desc: The keybindings have been reset to their respective defaults! + title: Successo nel reset dei comandi + desc: I comandi sono stati riassegnati ai loro rispettivi comandi di default! featureRestriction: - title: Demo Version - desc: You tried to access a feature () which is not available in the demo. Consider to get the standalone for the full experience! + title: Versione Demo + desc: Hai provato ad accedere ad una feature () che non è disponibile nella Demo. Considera di prendere la versione standalne per un'esperienza completa! oneSavegameLimit: - title: Limited savegames - desc: You can only have one savegame at a time in the demo version. Please remove the existing one or get the standalone! + title: Salvataggi limitati + desc: Puoi avere solo un salvataggio nella versione Demo. Perfavore rimuovi il salvataggio già esistente o prendi la versione standalone! updateSummary: - title: New update! + title: Nuovo update! desc: >- - Here are the changes since you last played: + Qui puoi trovare i cambiamenti dall'ultima volta che hai giocato: upgradesIntroduction: - title: Unlock Upgrades + title: Aggiornamenti sbloccati desc: >- - All shapes you produce can be used to unlock upgrades - Don't destroy your old factories! - The upgrades tab can be found on the top right corner of the screen. + Tutte le forme che produci possono essere utilizzate per i miglioramenti - Non distruggere le tue vecchie fabbriche! + Puoi trovare gli aggiornamenti nell'angolo in alto a destra dello schermo. massDeleteConfirm: - title: Confirm delete + title: Conferma la rimozione desc: >- - You are deleting a lot of buildings ( to be exact)! Are you sure you want to do this? + Stai rimuovendo molte strutture ( to be exact)! + Sei sicuro di volerlo fare? blueprintsNotUnlocked: - title: Not unlocked yet + title: Non ancora sbloccato desc: >- - Blueprints have not been unlocked yet! Complete more levels to unlock them. + I progetti non sono stati ancora sbloccati! Completa più livelli per sbloccarli. keybindingsIntroduction: - title: Useful keybindings + title: Comandi utili desc: >- - This game has a lot of keybindings which make it easier to build big factories. - Here are a few, but be sure to check out the keybindings!

- CTRL + Drag: Select area to copy / delete.
- SHIFT: Hold to place multiple of one building.
- ALT: Invert orientation of placed belts.
+ Questo gioco ha molti comandi utili che possono rendere più semplice la costruzione delle fabbriche. + Qui ce ne sono un paio, ma sii sicuro controlla i comandi!

+ CTRL + Drag: Seleziona l'area da copiare / cancella.
+ SHIFT: Tieni premuto per costruire copie dalla struttura.
+ ALT: Invert l'orientamento dei nastri trasportatori.
createMarker: - title: New Marker - desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + title: Nuovo Marker + desc: Dagli un magnifico nome, puoi anche includere short key di una figura (Che puoi generare here) + titleEdit: Edit Marker markerDemoLimit: - desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! + desc: Puoi creare solo due Marker personalizzati nella Demo. Prendi la versione standalone per Marker personalizzati illimitati! massCutConfirm: - title: Confirm cut + title: Conferma taglio desc: >- - You are cutting a lot of buildings ( to be exact)! Are you sure you - want to do this? + Stai tagliando molte strutture ( to be exact)! + Sei sicuro di volerlo fare? exportScreenshotWarning: - title: Export screenshot + title: Esportare screenshot desc: >- - You requested to export your base as a screenshot. Please note that this can - be quite slow for a big base and even crash your game! + Hai richiesto di esportare la tua base come screenshot. Perfavore tieni conto che potrebbe + essere lento per una grossa base e che potrebbe crushare il gioco! + + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? ingame: # This is shown in the top left corner and displays useful keybindings in # every situation keybindingsOverlay: - moveMap: Move - selectBuildings: Select area - stopPlacement: Stop placement - rotateBuilding: Rotate building - placeMultiple: Place multiple - reverseOrientation: Reverse orientation - disableAutoOrientation: Disable auto orientation - toggleHud: Toggle HUD - placeBuilding: Place building - createMarker: Create Marker - delete: Destroy + moveMap: Sposta + selectBuildings: Seleziona area + stopPlacement: Concludi posizionamento + rotateBuilding: Ruota costruzione + placeMultiple: Posiziona multiplo + reverseOrientation: Inverti orientamento + disableAutoOrientation: Disabilita orientamento automatico + toggleHud: Mostra/Nascondi HUD + placeBuilding: Posiziona costruzione + createMarker: Crea etichetta + delete: Distruggi pasteLastBlueprint: Paste last blueprint lockBeltDirection: Enable belt planner plannerSwitchSide: Flip planner side - cutSelection: Cut - copySelection: Copy - clearSelection: Clear Selection - pipette: Pipette + cutSelection: Taglia + copySelection: Copia + clearSelection: Annulla selezione + pipette: Contagocce + switchLayers: Switch layers # 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: Press to cycle variants. + cycleBuildingVariants: Premi per cambiare variante. # Shows the hotkey in the ui, e.g. "Hotkey: Q" hotkeyLabel: >- Hotkey: infoTexts: - speed: Speed - range: Range - storage: Storage - oneItemPerSecond: 1 item / second - itemsPerSecond: items / s + speed: Velocità + range: Raggio + storage: Spazio + oneItemPerSecond: 1 oggetto / secondo + itemsPerSecond: oggetti / s itemsPerSecondDouble: (x2) - tiles: tiles + tiles: titles # The notification when completing a level levelCompleteNotification: # is replaced by the actual level, so this gets 'Level 03' for example. - levelTitle: Level - completed: Completed - unlockText: Unlocked ! - buttonNextLevel: Next Level + levelTitle: Livello + completed: Completato + unlockText: Sbloccato ! + buttonNextLevel: Prossimo livello # Notifications on the lower right notifications: - newUpgrade: A new upgrade is available! - gameSaved: Your game has been saved. + newUpgrade: U nuovo aggiornamento è disponibile! + gameSaved: La tua partita è stata salvata. # The "Upgrades" window shop: - title: Upgrades - buttonUnlock: Upgrade + title: Aggiornamenti + buttonUnlock: Sblocca # Gets replaced to e.g. "Tier IX" tier: Tier @@ -338,17 +343,17 @@ ingame: # The roman number for each tier tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X] - maximumLevel: MAXIMUM LEVEL (Speed x) + maximumLevel: LIVELLO MASSIMO (Speed x) # The "Statistics" window statistics: - title: Statistics + title: Statistiche dataSources: stored: - title: Stored + title: Immagazzinati description: Displaying amount of stored shapes in your central building. produced: - title: Produced + title: Prodotti description: Displaying all shapes your whole factory produces, including intermediate products. delivered: title: Delivered @@ -360,25 +365,25 @@ ingame: # Settings menu, when you press "ESC" settingsMenu: - playtime: Playtime + playtime: Tempo di gioco buildingsPlaced: Buildings - beltsPlaced: Belts + beltsPlaced: Nastri buttons: - continue: Continue - settings: Settings - menu: Return to menu + continue: Continua + settings: Impostazioni + menu: Torna al menù # Bottom left tutorial hints tutorialHints: - title: Need help? - showHint: Show hint - hideHint: Close + title: Serve aiuto? + showHint: Mostra indizio + hideHint: Chiudi # When placing a blueprint blueprintPlacer: - cost: Cost + cost: Costo # Map markers waypoints: @@ -399,70 +404,72 @@ ingame: This is NOT an idle game! Build more extractors and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them. colors: - red: Red - green: Green - blue: Blue - yellow: Yellow - purple: Purple - cyan: Cyan - white: White - uncolored: No color + red: Rosso + green: Verde + blue: Blu + yellow: Giallo + purple: Viola + cyan: Azzurro + white: Bianco + uncolored: No colore + black: Black shapeViewer: - title: Layers - empty: Empty + title: Livelli + empty: Vuoto + copyKey: Copy Key # All shop upgrades shopUpgrades: belt: name: Belts, Distributor & Tunnels - description: Speed x → x + description: Velocità x → x miner: - name: Extraction - description: Speed x → x + name: Estrazione + description: Velocità x → x processors: name: Cutting, Rotating & Stacking - description: Speed x → x + description: Velocità x → x painting: name: Mixing & Painting - description: Speed x → x + description: Velocità x → x # Buildings and their name / description buildings: belt: default: - name: &belt Conveyor Belt - description: Transports items, hold and drag to place multiple. + name: &belt Nastro Trasportatore + description: Trasporta oggetti, clicca e trascina per posizionare in sequenza. miner: # Internal name for the Extractor default: - name: &miner Extractor - description: Place over a shape or color to extract it. + name: &miner Estrattore + description: Posiziona sopra una forma o un colore per estrarlo. chainable: - name: Extractor (Chain) - description: Place over a shape or color to extract it. Can be chained. + name: Estrattore (Catena) + description: Posiziona sopra una forma o un colore per estrarlo. Puoi combinarlo con altri estrattori. underground_belt: # Internal name for the Tunnel default: name: &underground_belt Tunnel - description: Allows to tunnel resources under buildings and belts. + description: Permette di far passare delle risorse sotto a costruzioni e nastri trasportatori. tier2: - name: Tunnel Tier II - description: Allows to tunnel resources under buildings and belts. + name: Tunnel Grado II + description: Permette di far passare delle risorse sotto a costruzioni e nastri trasportatori. splitter: # Internal name for the Balancer default: - name: &splitter Balancer - description: Multifunctional - Evenly distributes all inputs onto all outputs. + name: &splitter Bilanciatore + description: Multifunzionale - Distribuisce equamente tutti gli ingressi su tutte le uscite. compact: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Aggregatore (compatto) + description: Unisce due nastri trasportatori in uno solo. compact-inverse: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Aggregatore (compatto) + description: Unisce due nastri trasportatori in uno solo. cutter: default: @@ -487,18 +494,18 @@ buildings: mixer: default: - name: &mixer Color Mixer - description: Mixes two colors using additive blending. + name: &mixer Mixer Colori + description: Mescola due colori mediante sintesi additiva. painter: default: - name: &painter Painter - description: &painter_desc Colors the whole shape on the left input with the color from the right input. + name: &painter Verniciatore + description: &painter_desc Colora l'intera forma dell'ingresso sinistro con il colore dell'ingresso destro. double: - name: Painter (Double) + name: Verniciatore (Doppio) description: Colors the shapes on the left inputs with the color from the top input. quad: - name: Painter (Quad) + name: Verniciatore (Quadruplo) description: Allows to color each quadrant of the shape with a different color. mirrored: name: *painter @@ -506,17 +513,38 @@ buildings: trash: default: - name: &trash Trash - description: Accepts inputs from all sides and destroys them. Forever. + name: &trash Cestino + description: Accetta ingressi da tutti i lati e li distrugge. per sempre. storage: name: Storage description: Stores excess items, up to a given capacity. Can be used as an overflow gate. hub: - deliver: Deliver - toUnlock: to unlock + deliver: Consegna + toUnlock: per sbloccare levelShortcut: LVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -602,15 +630,15 @@ storyRewards: Congratulations! By the way, more content is planned for the standalone! settings: - title: Settings + title: Impostazioni categories: - game: Game - app: Application + game: Gioco + app: Applicazione versionBadges: - dev: Development + dev: Sviluppo staging: Staging - prod: Production + prod: Produzione buildDate: Built labels: @@ -637,9 +665,9 @@ settings: super_fast: Super fast language: - title: Language + title: Lingua description: >- - Change the language. All translations are user contributed and might be incomplete! + Cambia la lingua. Tutte le traduzioni sono realizzate dagli utenti e potrebbero essere incomplete! fullscreen: title: Fullscreen @@ -647,23 +675,23 @@ settings: It is recommended to play the game in fullscreen to get the best experience. Only available in the standalone. soundsMuted: - title: Mute Sounds + title: Silenzia Suoni description: >- - If enabled, mutes all sound effects. + Se abilitato, spegne tutti gli effetti sonori. musicMuted: - title: Mute Music + title: Silenzia Musica description: >- - If enabled, mutes all music. + Se abilitato, spegne la musica. theme: - title: Game theme + title: Tema del gioco description: >- - Choose the game theme (light / dark). + Scegli il tema (chiaro / scuro). themes: - dark: Dark - light: Light + dark: Scuro + light: Chiaro refreshRate: title: Simulation Target @@ -684,19 +712,19 @@ settings: title: Movement speed description: Changes how fast the view moves when using the keyboard. speeds: - super_slow: Super slow - slow: Slow - regular: Regular - fast: Fast - super_fast: Super Fast - extremely_fast: Extremely Fast + super_slow: Molto lento + slow: Lento + regular: Regolare + fast: Veloce + super_fast: Molto veloce + extremely_fast: Velocissimo enableTunnelSmartplace: title: Smart Tunnels description: >- When enabled, placing tunnels will automatically remove unnecessary belts. This also enables to drag tunnels and excess tunnels will get removed. vignette: - title: Vignette + title: Vignetta description: >- Enables the vignette which darkens the screen corners and makes text easier to read. @@ -728,11 +756,11 @@ settings: title: Color Blind Mode description: Enables various tools which allow to play the game if you are color blind. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. + This may be more comfortable if you frequently switch between placing + different building types. keybindings: title: Keybindings @@ -742,32 +770,32 @@ keybindings: resetKeybindings: Reset Keyinbindings categoryLabels: - general: Application - ingame: Game - navigation: Navigating - placement: Placement + general: Applicazione + ingame: Gioco + navigation: Navigazione + placement: Posizionamento massSelect: Mass Select buildings: Building Shortcuts placementModifiers: Placement Modifiers mappings: - confirm: Confirm - back: Back + confirm: Conferma + back: Indietro mapMoveUp: Move Up mapMoveRight: Move Right mapMoveDown: Move Down mapMoveLeft: Move Left - centerMap: Center Map + centerMap: Centra mappa mapZoomIn: Zoom in mapZoomOut: Zoom out createMarker: Create Marker - menuOpenShop: Upgrades - menuOpenStats: Statistics + menuOpenShop: Upgrade + menuOpenStats: Statistiche - toggleHud: Toggle HUD - toggleFPSInfo: Toggle FPS and Debug Info + toggleHud: Mostra/Nascondi HUD + toggleFPSInfo: Mostra/Nascondi FPS e info debug belt: *belt splitter: *splitter underground_belt: *underground_belt @@ -779,16 +807,16 @@ keybindings: painter: *painter trash: *trash - rotateWhilePlacing: Rotate + rotateWhilePlacing: Ruota rotateInverseModifier: >- Modifier: Rotate CCW instead - cycleBuildingVariants: Cycle Variants - confirmMassDelete: Confirm Mass Delete + cycleBuildingVariants: Cicla varianti + confirmMassDelete: Conferma eliminazione di massa cycleBuildings: Cycle Buildings massSelectStart: Hold and drag to start - massSelectSelectMultiple: Select multiple areas - massSelectCopy: Copy area + massSelectSelectMultiple: Seleziona aree multiple + massSelectCopy: Copia area placementDisableAutoOrientation: Disable automatic orientation placeMultiple: Stay in placement mode @@ -800,9 +828,14 @@ keybindings: lockBeltDirection: Enable belt planner switchDirectionLockSide: "Planner: Switch side" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: - title: About this Game + title: Riguardo questo gioco body: >- This game is open source and developed by Tobias Springer (this is me).

@@ -826,10 +859,10 @@ changelog: demo: features: - restoringGames: Restoring savegames - importingGames: Importing savegames - oneGameLimit: Limited to one savegame - customizeKeybindings: Customizing Keybindings - exportingBase: Exporting whole Base as Image + restoringGames: Recupero salvataggi + importingGames: Importazione salvataggi + oneGameLimit: Limite di un salvataggio + customizeKeybindings: Scorciatoie personalizabili + exportingBase: Esportazione dell'intera base come immagine - settingNotAvailable: Not available in the demo. + settingNotAvailable: Non disponibile nella demo. diff --git a/translations/base-ja.yaml b/translations/base-ja.yaml index 500238db..9d187de9 100644 --- a/translations/base-ja.yaml +++ b/translations/base-ja.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.ioは形の作成と合成を自動化するために工場を構築するゲームです。段々と複雑になる要件を納品していくことでゲームをすすめ、工場を高速化するためのアップグレードを解除していきます。 + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - 要件が増えてくると、ニーズに合わせて工場をスケールアップしていく必要があるでしょう。もちろん、[b]無限のマップ[/b]に展開する資源採取の拡張もお忘れなく! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - 形状だけではすぐに飽きがきますが、色素を混ぜて形を塗る工程もあります。赤、緑、青の色素の資源を組み合わせて、要件を満たす色と形状を作り出しましょう。 + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - このゲームは現在18レベルまでが実装されていますが(これだけでもかなりのボリュームです)、今後も継続的に新しい要素が追加で実装されていく予定です。 - すでに沢山計画されています! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]Web版にはないスタンドアローン版のメリット[/b] + [b]Standalone Advantages[/b] [list] - [*] マップのマーク設置とマークへの移動 - [*] 無制限のセーブデータ - [*] ダークモード - [*] 多彩な設定 - [*] shapez.ioのさらなる開発ができます ❤️ - [*] 将来の追加内容実装 + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]今後の実装予定とコミュニティの提案[/b] + [b]Future Updates[/b] - このゲームはオープンソースです。誰でも開発に参加できます! それ以外にも、私はコミュニティの意見を[b]とても[/b]よく聞いており、なるべくすべての提案を読み、できるだけ多くのフィードバックを考慮に入れるようにしています。 + I am updating the game very often and trying to push an update at least every week! [list] - [*] 建造物にコストがかかるストーリーモード - [*] 追加のレベル、及び建造物(スタンドアローン版限定) - [*] 別マップ、もしかすると障害物 - [*] 設定可能なマップ生成(数やサイズの設定、ランダム生成シード値、その他) - [*] 追加の形 - [*] パフォーマンス向上(このゲームは現状でもかなり軽いです) - [*] 色覚異常モード - [*] 他にも沢山! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - 完全なロードマップは私のTrelloボードをチェックしてみてください! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: ロード中 @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -131,28 +151,7 @@ mainMenu: savegameLevel: レベル savegameLevelUnknown: 不明なレベル - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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! continue: 続きから newGame: 新規ゲーム madeBy: Made by @@ -253,6 +252,7 @@ dialogs: createMarker: title: マーカーを設置 + titleEdit: マーカーを編集 desc: わかりやすい名前をつけてください。形を表す短いキーを含めることもできます。(ここから生成できます) markerDemoLimit: @@ -263,6 +263,11 @@ dialogs: desc: >- 多数の建造物をカットしようとしています! ( 個の選択) 続行しますか? + massCutInsufficientConfirm: + title: カット確認 + desc: >- + 設置コストが不足しています! 続行しますか? + exportScreenshotWarning: title: スクリーンショット出力 desc: >- @@ -291,6 +296,7 @@ ingame: copySelection: コピー clearSelection: 選択範囲をクリア pipette: ピペット + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -406,9 +412,11 @@ ingame: cyan: シアン white: 白 uncolored: 無色 + black: Black shapeViewer: title: レイヤー empty: 空 + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -516,6 +524,27 @@ buildings: storage: name: 格納庫 description: 余ったアイテムを指定の上限まで格納します。余剰の受け口としても使用可能です。 + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -723,11 +752,11 @@ settings: title: 色覚モード description: 色覚異常を持っていてもゲームがプレイできるようにするための各種ツールを有効化します。 rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. + This may be more comfortable if you frequently switch between placing + different building types. keybindings: title: キー設定 @@ -760,6 +789,7 @@ keybindings: menuOpenShop: アップグレード menuOpenStats: 統計情報 + menuClose: メニューを閉じる toggleHud: HUD切り替え toggleFPSInfo: FPS、デバッグ情報表示切り替え @@ -795,6 +825,10 @@ keybindings: lockBeltDirection: ベルトプランナーを有効化 switchDirectionLockSide: "プランナー: 通る側を切り替え" pipette: ピペット + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: このゲームについて diff --git a/translations/base-kor.yaml b/translations/base-kor.yaml index e9f19157..1f256dc7 100644 --- a/translations/base-kor.yaml +++ b/translations/base-kor.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io는 다양한 도형의 생산과 조합을 자동화하는 공장들을 짓는 게임입니다. 점점 복잡해지는 요구사항을 충족하고 업그레이드를 잠금 해제해서 공장의 성능을 높일 수 있습니다. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - 점점 증가하는 수요를 충족하기 위해 공장의 규모를 키워야 합니다. [b]무한한 공간[/b]으로 확장하여 도형 재료를 구하는 것도 잊지 마세요. + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - 단순한 도형은 금방 싫증이 나므로, 색을 조합하여 도형을 색칠하세요. 빨강, 초록, 파랑을 조합하여 다양한 색을 만들고 도형을 색칠하여 요구사항을 충족하세요. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - 이 게임에는 18개의 레벨이 있습니다. (이것만으로도 이미 몇시간이 걸렸을 거예요!) 하지만 저는 항상 새로운 컨텐츠를 추가하고 있습니다. 계획해 놓은 것들도 많구요! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]유료 버전의 장점[/b] + [b]Standalone Advantages[/b] [list] - [*] 마커 - [*] 제한 없는 저장 - [*] 다크 모드 - [*] 더 다양한 설정 - [*] 제가 shapez.io를 개발하는 데 도움이 됨 ❤️ - [*] 향후 더 많은 컨텐츠 + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b] 예정된 컨탠츠 및 커뮤니티 제안[/b] + [b]Future Updates[/b] - 이 게임은 오픈 소스입니다. 따라서 누구나 기여할 수 있습니다! 또한, 커뮤니티의 제안을 [b]많이[/b] 듣고 있습니다! 가능한 많이 읽고 많이 반영하도록 노력하겠습니다. + I am updating the game very often and trying to push an update at least every week! [list] - [*] 건물을 도형으로 구매해야 돼는 스토리 모드 - [*] 더 많은 레벨과 건물 (유료 버전 한정) - [*] 다양한 월드와 맵 장애물 - [*] 당신만의 맵 제작 - [*] 더 많은 종류의 도형 - [*] 성능 향상 (지금도 게임이 잘 되긴 합니다!) - [*] 색맹자용 모드 - [*] 그 외 다수! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - 저의 트렐로 보드를 확인해서 로드맵을 확인해보세요! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: 로딩중 @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -130,32 +150,10 @@ mainMenu: savegameLevel: 레벨 savegameLevelUnknown: 레벨 모름 - contests: - contest_01_03062020: - title: "콘테스트 #01" - desc: Win $25 for the coolest base! - longDesc: >- - 여러분들에게 무언가를 나눠드리고 싶어서 주간 콘테스트를 개최합니다! -

- 이번주 토픽: 가장 멋있는 공장을 만드세요! -

- 참여하는 법:
-
    -
  • 여러분 공장의 스크린샷을 여기로 보내세요: contest@shapez.io
  • -
  • 소셜 미디어에 공유하면 보너스 포인트!
  • -
  • 스크린샷 5개를 골라 디스코드 커뮤니티에서 투표를 진행할 예정입니다.
  • -
  • 우승자는 $25를 받습니다! (PayPal이나 아마존 기프트 카드 중 원하는 것으로)
  • -
  • 기한: 07.06.2020 12:00 AM CEST
  • -
-
- 당신들의 멋진 공장을 보고 싶습니다! - - showInfo: 보기 - contestOver: 이 콘테스트는 끝났습니다. 디스코드에서 새로운 콘테스트 관련 알림을 받으세요! - continue: Continue - newGame: New Game - madeBy: Made by + continue: 계속하기 + newGame: 새 게임 + madeBy: 제작 subreddit: Reddit dialogs: @@ -239,9 +237,9 @@ dialogs: 당신은 많은 건물을 삭제하려고 하고있습니다! (정확히는 개) 삭제하시겠습니까? massCutConfirm: - title: Confirm cut + title: 자르기 확인 desc: >- - You are cutting a lot of buildings ( to be exact)! Are you sure you want to do this? + 당신은 많은 건물을 자르려고 하고있습니다! (정확히는 개) 자르시겠습니까? blueprintsNotUnlocked: title: 아직 사용 불가 @@ -259,16 +257,21 @@ dialogs: createMarker: title: 새로운 마커 - desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + desc: 이 장소에 이름을 지어주세요, 당신은 원하는 모양으로 단축키를 생성할 수 있습니다. (여기에서 만들 수 있습니다.) + titleEdit: Edit Marker markerDemoLimit: desc: 데모 버전에서는 마커를 2개 까지만 놓을 수 있습니다. 유료 버전을 구입하면 마커를 무제한으로 놓을 수 있습니다! exportScreenshotWarning: - title: Export screenshot + title: 스크린샷 내보내기 desc: >- - You requested to export your base as a screenshot. Please note that this can - be quite slow for a big base and even crash your game! + 당신은 당신의 공장을 스크린샷으로 내보내려 하고있습니다. 공장이 너무 큰 경우에는 + 시간이 오래 걸리거나 게임이 꺼질 수도 있음을 알려드립니다! + + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? ingame: # This is shown in the top left corner and displays useful keybindings in @@ -285,13 +288,14 @@ ingame: placeBuilding: 건물 놓기 createMarker: 마커 놓기 delete: 삭제 - pasteLastBlueprint: Paste last blueprint - lockBeltDirection: Enable belt planner - plannerSwitchSide: Flip planner side - cutSelection: Cut - copySelection: Copy - clearSelection: Clear Selection - pipette: Pipette + pasteLastBlueprint: 마지막 청사진 붙여넣기 + lockBeltDirection: 벨트 플래너 활성화하기 + plannerSwitchSide: 벨트 플래너 방향바꾸기 + cutSelection: 선택된 부분 자르기 + copySelection: 선택된 부분 복사하기 + clearSelection: 선택된 부분 지우기 + pipette: 스포이드 + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -338,7 +342,7 @@ ingame: # The roman number for each tier tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X] - maximumLevel: MAXIMUM LEVEL (Speed x) + maximumLevel: 최대 (Speed x) # The "Statistics" window statistics: @@ -385,7 +389,7 @@ ingame: waypoints: 마커 hub: 중앙 건물 description: 마커를 좌클릭해서 그곳으로 가고, 우클릭해서 삭제합니다.

을 눌러 지금 있는 곳에 마커를 놓거나 우클릭해서 원하는 곳에 놓으세요. - creationSuccessNotification: Marker has been created. + creationSuccessNotification: 마커가 성공적으로 제작되었습니다. # Interactive tutorial interactiveTutorial: @@ -399,17 +403,19 @@ ingame: 이것은 방치형 게임이 아닙니다! 추출기를 더 놓아 목표를 빨리 달성하세요.

팁: SHIFT를 눌러 여러 개의 추출기를 놓고 R로 회전 시키세요. colors: - red: Red - green: Green - blue: Blue - yellow: Yellow - purple: Purple - cyan: Cyan - white: White - uncolored: No color + red: 빨강 + green: 초록 + blue: 파랑 + yellow: 노랑 + purple: 보라 + cyan: 청록 + white: 하양 + uncolored: 색 + black: Black shapeViewer: - title: Layers - empty: Empty + title: 층 + empty: 비었음 + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -517,6 +523,27 @@ buildings: storage: name: 저장소 description: 할당된 용량만큼 초과되는 도형을 저장한다. + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -531,15 +558,15 @@ storyRewards: reward_painter: title: 색칠기 desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + 색칠기가 잠금 해제되었습니다. - 추출한 색소(도형을 추출하는 것처럼)를 색칠기에서 도형과 합쳐 색칠된 도형을 얻으세요!

추신: 색맹이라면, 설정에서 색맹 모드를 활성화 시키세요! reward_mixer: title: 혼합기 - desc: 혼합기가 잠금 해제 되었습니다! 이 건물로 두 색소를 혼합하세요! + desc: 혼합기가 잠금 해제되었습니다! 이 건물로 두 색소를 혼합하세요! reward_stacker: title: 결합기 - desc: 결합기가 잠금 해제 되었습니다! 두 도형이 서로 옆에 놓을 수 있는 경우, 두 도형이 결합됩니다. 그렇지 않은 경우, 오른쪽 도형이 왼쪽 도형 위에 쌓이게됩니다. + desc: 결합기가 잠금 해제되었습니다! 두 도형이 서로 옆에 놓을 수 있는 경우, 두 도형이 결합됩니다. 그렇지 않은 경우, 오른쪽 도형이 왼쪽 도형 위에 쌓이게됩니다. reward_splitter: title: 배분기 @@ -594,7 +621,7 @@ storyRewards: no_reward: title: 다음 레벨 desc: >- - This level gave you no reward, but the next one will!

PS: Better don't destroy your existing factory - You need all those shapes later again to unlock upgrades! + 이 단계는 아무런 보상이 없습니다. 하지만 다음 단계에는 있죠!

추신: 현존하는 공장을 부수지 않는 것이 좋습니다. - 추후 업그레이드를 해제하기 위해 모든 도형들이 필요합니다! no_reward_freeplay: title: 다음 레벨 @@ -637,16 +664,16 @@ settings: super_fast: 매우 빠르게 movementSpeed: - title: Movement speed + title: 이동 속도 description: >- - Changes how fast the view moves when using the keyboard. + 키보드를 사용할 때, 화면 이동 속도를 설정합니다. speeds: - super_slow: Super slow - slow: Slow - regular: Regular - fast: Fast - super_fast: Super Fast - extremely_fast: Extremely Fast + super_slow: 매우 느리게 + slow: 느리게 + regular: 보통 + fast: 빠르게 + super_fast: 매우 빠르게 + extremely_fast: 극한의 속도 language: title: 언어 @@ -673,8 +700,8 @@ settings: description: >- 게임 테마를 고르세요. (밝음/어두움). themes: - dark: Dark - light: Light + dark: 어두운 테마 + light: 밝은 테마 refreshRate: title: 모니터 리프레쉬 속도 @@ -692,48 +719,45 @@ settings: 이것을 끄면 힌트와 튜토리얼이 나오지 않습니다. 또한 게임에 쉽게 들어가기 위해서 주어진 레벨에서 특정 UI 요소를 숨길 수도 있습니다. enableTunnelSmartplace: - title: Smart Tunnels + title: 스마트 터널 description: >- - When enabled, placing tunnels will automatically remove unnecessary belts. - This also enables to drag tunnels and excess tunnels will get removed. + 활성화 시키면, 터널을 설치하는 것이 자동적으로 불필요한 벨트를 없앱니다. + 또한, 터널을 당겨서 남는 터널을 없앱니다. + vignette: - title: Vignette + title: 삽화 description: >- - Enables the vignette which darkens the screen corners and makes text easier - to read. + 화면의 코너를 어둡게 만들어 텍스트를 읽기 쉽게 해주는 삽화를 활성화 시킵니다. autosaveInterval: - title: Autosave Interval + title: 자동저장 주기 description: >- - Controls how often the game saves automatically. You can also disable it - entirely here. + 자동저장을 얼마나 자주 할 것인지 정합니다. 자동저장기능을 끌 수도 있습니다. intervals: - one_minute: 1 Minute - two_minutes: 2 Minutes - five_minutes: 5 Minutes - ten_minutes: 10 Minutes - twenty_minutes: 20 Minutes - disabled: Disabled + one_minute: 1분 + two_minutes: 2분 + five_minutes: 5분 + ten_minutes: 10분 + twenty_minutes: 20분 + disabled: 기능 끄기 compactBuildingInfo: - title: Compact Building Infos + title: 간결한 건물 정보 description: >- - Shortens info boxes for buildings by only showing their ratios. Otherwise a - description and image is shown. + 건물의 정보창을 해당 건물의 능률만 보이도록 줄입니다. + 아니면, 설명과 이미지가 보입니다. disableCutDeleteWarnings: - title: Disable Cut/Delete Warnings + title: 자르기/삭제 경고기능 끄기 description: >- - Disable the warning dialogs brought up when cutting/deleting more than 100 - entities. + 100개 이상의 건물을 자르기/삭제할 때 경고창이 나오지 않게 합니다. enableColorBlindHelper: - title: Color Blind Mode - description: Enables various tools which allow to play the game if you are color blind. + title: 색맹 모드 + description: 색맹이 게임을 플레이하는데 도움을 주는 다양한 도구를 활성화 시킵니다. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: 건물 유형에 따른 방향 + description: >- + 각 건물 유형은 최근에 설정한 방향을 개별적으로 기억합니다. + 다른 유형의 건물 배치 간에 자주 방향을 전환할 경우, 이 방법이 더 편할 수 있습니다. keybindings: title: 키바인딩 @@ -747,7 +771,7 @@ keybindings: ingame: 게임 navigation: 둘러보기 placement: 놓기 - massSelect: 여러 개 선택 + massSelect: 다중 선택 buildings: 건물 쇼트컷 placementModifiers: 배치 수정기 @@ -785,42 +809,46 @@ keybindings: Modifier: 대신 반시계방향으로 회전 cycleBuildingVariants: 변형종 사용 confirmMassDelete: 대량 삭제 확인 - pasteLastBlueprint: Paste last blueprint + pasteLastBlueprint: 최근 청사진 붙여넣기 cycleBuildings: 건물 사이클 massSelectStart: 누르고 드래그해서 시작 massSelectSelectMultiple: 여러 곳 선택 massSelectCopy: 영역 복사 - massSelectCut: Cut area + massSelectCut: 영역 자르기 placementDisableAutoOrientation: 자동 회전 끄기 placeMultiple: 배치 모드에 있기 placeInverse: 자동 벨트 회전 뒤집기 - exportScreenshot: Export whole Base as Image - mapMoveFaster: Move Faster - lockBeltDirection: Enable belt planner - switchDirectionLockSide: "Planner: Switch side" - pipette: Pipette + exportScreenshot: 공장 전체를 이미지로 내보내기 + mapMoveFaster: 더 빠르게 움직이기 + lockBeltDirection: 벨트 플래너 활성화 + switchDirectionLockSide: "플래너: 방향 바꾸기" + pipette: 피펫 + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: 이 게임의 정보 body: >- - This game is open source and developed by Tobias Springer (this is me).

+ 이 게임은 오픈소스이고, Tobias Springer가 개발했습니다.

- If you want to contribute, check out shapez.io on github.

+ 이 게임을 위해 이바지하고 싶다면, shapez.io on github를 확인하세요.

- This game wouldn't have been possible without the great discord community - around my games - You should really join the discord server!

+ 이 게임은 디스코드 커뮤니티의 공헌이 없었다면 불가능했을 것입니다. + 우리 디스코드 커뮤니티에 꼭 참여해주세요! 디스코드 서버!

- The soundtrack was made by Peppsen - He's awesome.

+ 사운드 트랙 제작자는 Peppsen입니다. - 킹갓제너럴 Peppsen!

- Finally, huge thanks to my best friend Niklas - Without our - factorio sessions this game would never have existed. + 마지막으로, 나의 절친 Niklas에게 + 크나큰 감사를 표합니다 - 우리가 함께 해낸 Factorio가 아니었다면, 이 게임은 존재하지 않았을 겁니다! changelog: title: 업데이트 기록 @@ -831,6 +859,6 @@ demo: importingGames: 게임 저장 파일 불러오기 oneGameLimit: 게임 저장 파일 최대 1개 customizeKeybindings: 키바인딩 설정하기 - exportingBase: Exporting whole Base as Image + exportingBase: 공장 전체를 이미지로 내보내기 settingNotAvailable: 데모 버전에서 사용 불가 diff --git a/translations/base-lt.yaml b/translations/base-lt.yaml index bd33d5b1..134105ff 100644 --- a/translations/base-lt.yaml +++ b/translations/base-lt.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Unlimited Savegames [*] Dark Mode - [*] More settings - [*] Allow me to further develop shapez.io ❤️ - [*] More features in the future! + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - This game is open source - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story mode where buildings cost shapes - [*] More levels & buildings (standalone exclusive) - [*] Different maps, and maybe map obstacles - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] More types of shapes - [*] More performance improvements (Although the game already runs pretty good!) - [*] Color blind mode + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Loading @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -131,28 +151,7 @@ mainMenu: savegameLevel: Level savegameLevelUnknown: Unknown Level - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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! continue: Continue newGame: New Game madeBy: Made by @@ -255,6 +254,7 @@ dialogs: createMarker: title: New Marker desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker markerDemoLimit: desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! @@ -270,6 +270,10 @@ dialogs: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -292,6 +296,7 @@ ingame: copySelection: Copy clearSelection: Clear Selection pipette: Pipette + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -407,9 +412,11 @@ ingame: cyan: Cyan white: White uncolored: No color + black: Black shapeViewer: title: Layers empty: Empty + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -517,6 +524,27 @@ buildings: storage: name: Storage description: Stores excess items, up to a given capacity. Can be used as an overflow gate. + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -727,11 +755,11 @@ settings: title: Color Blind Mode description: Enables various tools which allow to play the game if you are color blind. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. + This may be more comfortable if you frequently switch between placing + different building types. keybindings: title: Keybindings @@ -799,6 +827,11 @@ keybindings: lockBeltDirection: Enable belt planner switchDirectionLockSide: "Planner: Switch side" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: About this Game diff --git a/translations/base-nl.yaml b/translations/base-nl.yaml index 2deb72b7..69072d0c 100644 --- a/translations/base-nl.yaml +++ b/translations/base-nl.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is een spel dat draait om het bouwen van fabrieken om steeds complexere vormen te produceren en deze productie te automatiseren. Lever de gevraagde, steeds complexere vormen, om verder te komen in het spel en om upgrades voor je fabrieken te ontgrendelen. + shapez.io is een spel dat draait om het bouwen van fabrieken om steeds complexere vormen te produceren en deze productie te automatiseren in een oneindig groot speelveld. + Door het leveren van de gevraagde vormen, kom je verder in het spel en ontgrendel je upgrades waar je fabriek sneller van wordt. - De vraag naar vormen wordt steeds groter, wat betekent dat je fabriek moet blijven uitbreiden om dit tegemoet te komen. Om de juiste grondstoffen te delven zul je steeds verder in het [b]oneindig grote speelveld[/b] moeten gaan werken! - - Omdat simpele vormen snel saai worden, moet je kleuren mengen om de vormen te verven - combineer rode, groene en blauwe grondstoffen om verschillende kleuren te produceren en gebruik deze om de vormen te verven, zodat je de vraag hiernaar tegemoet kan komen. + De vraag naar vormen wordt steeds groter, wat betekent dat je de fabriek moet uitbreiden om de vraag tegemoet te komen. Om de juiste grondstoffen te delven zul je steeds verder in het [b]oneindig grote speelveld[/b] moeten gaan werken! + + Omdat simpele vormen snel saai worden, moet je kleuren mengen om de vormen te verven - Combineer rode, groene en blauwe grondstoffen om verschillende kleuren te produceren en gebruik deze om de vormen te verven, zodat je de vraag hiernaar tegemoet kan komen. Dit spel bevat 18 levels (Waar je al uren mee bezig zal zijn!), maar ik ben continu bezig om het spel uit te breiden - er staat veel in de planning! + Wanneer je het spel koopt dan krijg je toegang tot de standalone versie. Deze heeft extra functies en je krijgt ook toegang tot nieuwe ontwikkelingen. - [b]Standalone voordelen[/b] + [b]Standalone Voordelen[/b] [list] - [*] Markeringen - [*] Oneindig veel Savegames [*] Donkere modus - [*] Meer opties - [*] Met jouw steun kan ik shapez.io verder ontwikkelen ❤️ - [*] Meer functies in de toekomst! + [*] Oneindig veel markeringen + [*] Oneindig veel savegames + [*] Extra opties + [*] Binnenkort: Kabels & Energie! Hopelijk vanaf eind juli 2020. + [*] Binnenkort: Meer Levels + [*] Helpt mij om shapez.io verder te ontwikkelen ❤️ [/list] - [b]Geplande functies & suggesties van de community[/b] + [b]Geplande Updates[/b] - Dit spel is open source - Iedereen kan bijdragen! Daarnaast luister ik [b]erg veel[/b] naar de community! Ik probeer alle suggesties te lezen en gebruik feedback zo veel als mogelijk. + Ik update het spel regelmatig en probeer dit zeker eenmaal per week te doen! [list] - [*] Verhaalmodus, waar gebouwen specifieke vormen kosten om te bouwen - [*] Meer levels & gebouwen (exclusief in de standalone) - [*] Verschillende mappen en misschien obstakels in mappen - [*] Aangepaste mappen aanmaken (Het kiezen van de hoeveelheid en de grootte van de grondstofbronnen, seeds, en meer) + [*] Verschillende speelvelden en uitdagingen (bijv. obstakels) + [*] Puzzels (Bezorg de gevraagde vorm binnen een afgesloten gebied of met bepaalde gebouwen) + [*] Een verhaalmodus waar gebouwen iets kosten + [*] Aanpasbare speelveldgenerator (Kies de hoeveelheid en grootte van grondstoffen, seed en meer) [*] Meer soorten vormen - [*] Meer prestatieverbeteringen (Hoewel het spel al vrij goed loopt!) - [*] Kleurenblind-modus + [*] Prestatieverbeteringen (Het spel loopt al vrij goed!) [*] En nog veel meer! [/list] - Bekijk mijn trello-bord voor het volledige stappenplan! https://trello.com/b/ISQncpJP/shapezio + [b]Dit spel is open source![/b] + + Iedreen kan bijdragen. Ik ben actief in de community en probeer naar alle suggesties en feedback te kijken en deze mee te nemen in de ontwikkeling. + Bekijk mijn trello-bord voor het volledige stappenplan! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Stappenplan[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help met vertalen[/url] + [/list] + + discordLink: Officiële Discord - Chat met mij! global: loading: Laden @@ -73,6 +90,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "." + + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "," # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: @@ -131,28 +151,7 @@ mainMenu: savegameLevel: Level savegameLevelUnknown: Onbekend Level - contests: - contest_01_03062020: - title: "Competitie #01" - desc: Win $25 voor de meest coole basis! - longDesc: >- - Om wat aan jullie terug te geven leek het me leuk om wekelijkse competities te houden! -

- Het onderwerp van deze week: Bouw de meest coole basis! -

- Dit is hoe het zit:
-
    -
  • Stuur een screenshot van jouw basis naar contest@shapez.io
  • -
  • Bonuspunten als je het deelt op social media!
  • -
  • Ik kies 5 screenshots en presenteer deze aan de discord community om te stemmen.
  • -
  • De winnaar krijgt $25 (Paypal, Amazon Gift Card, wat jij het liefste hebt)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- Ik kijk er naar uit om jullie geweldige creaties te zien! - showInfo: Laat zien - contestOver: Deze competitie is voorbij - word lid van de discord (engelstalig) om berichten te krijgen van nieuwe competities! continue: Verder newGame: Nieuw Spel madeBy: Gemaakt door @@ -170,7 +169,7 @@ dialogs: deleteGame: Ik weet wat ik doe viewUpdate: Zie Update showUpgrades: Zie Upgrades - showKeybindings: Zie sneltoetsen + showKeybindings: Zie Sneltoetsen importSavegameError: title: Import Error @@ -255,6 +254,7 @@ dialogs: createMarker: title: Nieuwe markering desc: Geef het een betekenisvolle naam. Je kunt ook een icoontje van een vorm toevoegen (die je hier kunt maken) + titleEdit: Edit Marker markerDemoLimit: desc: Je kunt maar twee markeringen plaatsen in de demo. Koop de standalone voor een ongelimiteerde hoeveelheid markeringen! @@ -268,6 +268,10 @@ dialogs: desc: >- Je hebt aangegeven dat je jouw basis wil exporteren als screenshot. Als je een grote basis hebt kan dit proces langzaam zijn en er zelfs voor zorgen dat je spel crasht! + massCutInsufficientConfirm: + title: Bevestig knippen + desc: Je kunt het je niet veroorloven om de selectie te plakken! Weet je zeker dat je het wil knippen? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -283,13 +287,14 @@ ingame: placeBuilding: Plaats gebouw createMarker: Plaats markering delete: Vernietig - pasteLastBlueprint: Plak de laatst gekopiëerde blauwdruk - lockBeltDirection: Maak gebruik van de lopende band planner + pasteLastBlueprint: Plak laatst gekopiëerde blauwdruk + lockBeltDirection: Gebruik lopende band planner plannerSwitchSide: Draai de richting van de planner cutSelection: Knip copySelection: Kopieer - clearSelection: Cancel selectie + clearSelection: Annuleer selectie pipette: Pipet + switchLayers: Wissel lagen # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -366,7 +371,7 @@ ingame: buttons: continue: Verder spelen settings: Opties - menu: Terug naar het menu + menu: Terug naar het Menu # Bottom left tutorial hints tutorialHints: @@ -405,9 +410,11 @@ ingame: cyan: Cyaan white: Wit uncolored: Geen kleur + black: Zwart shapeViewer: title: Lagen empty: Leeg + copyKey: Kopiëer sleutel # All shop upgrades shopUpgrades: @@ -486,7 +493,7 @@ buildings: mixer: default: name: &mixer Kleurenmenger - description: Mengt twee kleuren. + description: Mengt twee kleuren met behulp van additieve kleurmenging. painter: default: @@ -515,6 +522,27 @@ buildings: deliver: Lever toUnlock: om te ontgrendelen levelShortcut: LVL + wire: + default: + name: Energiekabel + description: Voor transport van energie. + advanced_processor: + default: + name: Kleur-omkeerder + description: Keert de kleur om van een voorwerp. + energy_generator: + deliver: Lever + toGenerateEnergy: Voor + default: + name: Energiegenerator + description: Wekt energie op door vormen te consumeren. + wire_crossings: + default: + name: Kabelsplijter + description: Splijt één kabel in twee. + merger: + name: Kabelvoeger + description: Voegt twee kabels samen tot één. storyRewards: # Those are the rewards gained from completing the store @@ -529,11 +557,11 @@ storyRewards: reward_painter: title: Verven desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + De verver is ontgrendeld - Onttrek wat kleur (op dezelfde manier hoe je vormen onttrekt) en combineer het met een vorm in de verver om ze te kleuren!

PS: Als je kleurenblind bent, is er een kleurenblindmodus in de instellingen! reward_mixer: title: Kleuren mengen - desc: De menger is ontgrendeld - gebruik dit gebouw om twee kleuren te mengen via 'additive blending'! + desc: De menger is ontgrendeld - Gebruik dit gebouw om twee kleuren te mengen met behulp van additieve kleurmenging! reward_stacker: title: Stapelaar @@ -565,7 +593,7 @@ storyRewards: Je hebt een compacte variant van de verdeler ontgrendeld - Dit voegt twee lopende banden samen tot één. reward_cutter_quad: - title: Quad Cutting + title: Quad Knippen desc: Je hebt een variant van de knipper ontgrendeld - Dit knipt vormen in vier stukken in plaats van twee! reward_painter_double: @@ -577,7 +605,7 @@ storyRewards: desc: Je hebt een variant van de verver ontgrendeld - Het verft elk kwadrant van de vorm een andere kleur! reward_storage: - title: Opslag buffer + title: Opslagbuffer desc: Je hebt een variant van de vuilnisbak ontgrendeld - Het slaat voorwerpen op tot een zekere hoeveelheid! reward_freeplay: @@ -694,7 +722,7 @@ settings: Wanneer dit aan staat zullen tunnels automatisch onnodige lopende banden verwijderen. Ook kun je dan tunnels slepen en onnodige tunnels worden ook verwijderd. vignette: - title: Vignette + title: Vignet description: >- Schakelt de vignet in, wat de hoeken van het scherm donkerder maakt zodat de tekst makkelijker te lezen is. @@ -712,24 +740,24 @@ settings: twenty_minutes: 20 Minuten disabled: Uitgeschakeld compactBuildingInfo: - title: Combacte gebouwinformatie + title: Compacte gebouwinformatie description: >- Informatie weergeven bij gebouwen wordt beperkt tot alleen hun 'ratios'. Anders zie je een beschrijving en een afbeelding. disableCutDeleteWarnings: - title: Schakel knip/delete waarschuwingen uit. + title: Schakel knip/verwijder waarschuwingen uit description: >- Schakelt de waarschuwing uit die wordt weergegeven wanneer je meer dan 100 dingen probeert te - knippen/deleten. + knippen/verwijderen. enableColorBlindHelper: title: Kleurenblindmodus description: Schakelt verschillende hulpmiddelen in zodat je het spel alsnog kunt spelen wanneer je kleurenblind bent. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotatie per type gebouw + description: >- + Elk type gebouw onthoud apart de rotatie waarin je het voor het laatst geplaatst hebt. + Dit kan handig zijn wanneer je vaak tussen verschillende + soorten gebouwen wisselt. keybindings: title: Sneltoetsen @@ -797,6 +825,11 @@ keybindings: lockBeltDirection: Schakel lopende band-planner in switchDirectionLockSide: "Planner: Wissel van richting" pipette: Pipet + menuClose: Sluit Menu + switchLayers: Lagen omwisselen + advanced_processor: Kleur-omvormer + energy_generator: Energiegenerator + wire: Energiekabel about: title: Over dit spel diff --git a/translations/base-no.yaml b/translations/base-no.yaml index b3c1bc84..ae49885e 100644 --- a/translations/base-no.yaml +++ b/translations/base-no.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io er et spill som handler om å bygge fabrikker for å automatisere byggeprosessen og kombinere forskjellige former og fasonger. Lever objektene som øker i kompleskitet og fasonger for å progressere i spillet og åpne opp nye oppgraderinger til din fabrikk. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Siden forespørselen øker, må du skalere opp fabrikken din for å tilpasse deg til behovet - Men ikke glem tilgangen du har til ressurser, du må utvide på det [b]uendelige brettet[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Siden figurer i seg selv kan bli kjedelig, må du snart mikse farger og fargelegge dine figurer - Kombiner rød, grønn og blå farge-ressurser for å produsere forskjellige farger, og fargelegg figurene for å tilfredsstille behovet. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - Spillet har 18 nivåer (Som bør holde deg opptatt i mange timer!) men jeg legger konstant til nytt innhold - Det er mye som er planlagt! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]Frittstående Fordeler[/b] + [b]Standalone Advantages[/b] [list] - [*] Kartmarkering - [*] Uendelige lagringsfiler - [*] Mørk Modus - [*] Flere instillinger - [*] Tillater meg å videreutvikle shapez.io ❤️ - [*] Flere funksjoner i fremtiden! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planlagte funksjoner & Forslag fra samfunnet[/b] + [b]Future Updates[/b] - Spillet er åpen kildekode - Alle kan bidra! Utenom det, så lytter jeg [b]veldig[/b] til samfunnet! Jeg prøver å lese alle forslag og ta imot så mye tilbakemeldinger som mulig. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Kampanje - [*] Flere nivåer & bygninger (Frittstående eksklusivt) - [*] Forskjellige brett, og kanskje hinder på brettet - [*] Konfigurerbart brett-generasjon (Endre antall og størrelse på ressursfelt, seed, med mer) - [*] Flere forskjellige type former - [*] Mer forbedring av ytelse (Selv om spillet allerede kjører ganske bra!) - [*] Fargeblind modus - [*] Og mye mer! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - Sjekk ut min trello tavle for hele planen! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Laster @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -131,28 +151,7 @@ mainMenu: savegameLevel: Nivå savegameLevelUnknown: Ukjent Nivå - contests: - contest_01_03062020: - title: "Konkurranse #01" - desc: Vinn $25 for den kuleste basen! - longDesc: >- - For å gi noe tilbake til deg, tenkte jeg det ville vært kult med ukentlige konkurranser! -

- Denne ukens tema: Bygg den kuleste basen! -

- Her er tingen:
-
    -
  • Send et skjermbilde av basen din til contest@shapez.io
  • -
  • Bonus poeng om du deler på sosiale medier!
  • -
  • Jeg velger 5 skjermbilder og foreslår de på discord for samfunnet til å stemme.
  • -
  • Vinneren får $25 (Paypal, Amazon Gift Card, eller hva du foretrekker)
  • -
  • Frist: 07.06.2020 00:00 Sentraleuropeisk sommertid
  • -
-
- Jeg ser fram til å se dine kule skapninger! - showInfo: Vis - contestOver: Denne konkurransen er ferdig - Bli med på discord for å få varsel om nye konkurranser! continue: Fortsett newGame: Nytt Spill madeBy: Laget av @@ -260,6 +259,7 @@ dialogs: createMarker: title: Ny Markør desc: Gi markøren et meningsfullt navn, du kan også inkludere "short key" av et objekt (Som du kan generere her) + titleEdit: Edit Marker markerDemoLimit: desc: Du kan kun ha to markører i demo verjsonen. Skaff deg frittstående versjon for ubegrensede markører! @@ -267,6 +267,9 @@ dialogs: exportScreenshotWarning: title: Eksporter skjermbilde desc: Du forespurte å eksportere bilde av basen din som et skjermbilde. Vær obs på at dette kan ta lang tid for en stor base, og i verste fall kræsje spillet ditt (Husk å lagre først)! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? ingame: # This is shown in the top left corner and displays useful keybindings in @@ -290,6 +293,7 @@ ingame: copySelection: Kopier clearSelection: Fjern Valgte pipette: Pipette + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -405,9 +409,11 @@ ingame: cyan: Cyan white: Hvit uncolored: Ingen farge + black: Black shapeViewer: title: Lag empty: Tom + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -515,6 +521,27 @@ buildings: storage: name: Lagringsboks description: Lagrer overflødige objekter, opp til en viss kapasitet. Kan bli brukt som mellomlagring for overflyt. + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -529,7 +556,7 @@ storyRewards: reward_painter: title: Maling desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + Maleren har blitt tilgjengelig - Hent ut fargeressurser (på samme måte som du gjør med objekter) og kombiner det med et objekt i maleren for å male de!

PS: Hvis du er fargeblind, så er det en modus for fargeblinde i instillinger! reward_mixer: title: Fargemikser @@ -727,11 +754,11 @@ settings: title: Fargeblind Modus description: Aktiverer forskjellige verktøy som lar deg spille spillet om du er fargeblind. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Roter basert på bygningstype + description: >- + Hver bygning type husker rotasjonen du sist brukte individuelt. + Dette kan være mer komfortabelt hvis du ofte veksler mellom plassering + av forskjellige bygninger. keybindings: title: Hurtigtaster @@ -799,6 +826,11 @@ keybindings: lockBeltDirection: Enable belt planner switchDirectionLockSide: "Planlegger: Bytt side" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: Om dette spillet diff --git a/translations/base-pl.yaml b/translations/base-pl.yaml index 8f66d2a0..a28d244c 100644 --- a/translations/base-pl.yaml +++ b/translations/base-pl.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io jest grą o budowaniu i automatyzacji fabryki różnych kształtów. Dostarczaj coraz bardziej skomplikowane kształty, żeby odblokować nowe ulepszenia i przyspieszyć produkcję w twojej fabryce. + shapez.io to gra o budowie fabryk, która automatyzuje tworzenie i przetwarzanie coraz bardziej złożonych kształtów na nieskończenie powiększającej się mapie. + Po dostarczeniu wymaganych kształtów będziesz postępować w grze i odblokowywać ulepszenia, aby przyspieszyć fabrykę. - Będziesz potrzebował coraz więcej elementów, więc również sporo miejsca na powiększanie fabryki. [b]Nieskończona mapa[/b] to coś co ułatwi Ci ten proces! + Wraz ze wzrostem zapotrzebowania na kształty, będziesz musiał powiększyć swoją fabrykę, aby zaspokoić popyt - Nie zapominaj jednak o zasobach, będziesz musiał rozwinąć się na [b] nieskończonej mapie [/ b]! - Same kształty mogą z czasem być nudne, dlatego gra będzie wymagała od Ciebie malowania ich różnymi kolorami - połącz czerwoną, zieloną i niebieską farbę, a powstanie nowa o innym kolorze. Korzystaj z farb, by móc ukończyć kolejne poziomy. + Wkrótce będziesz musiał mieszać kolory i malować nimi kształty - Połącz zasoby kolorów czerwonego, zielonego i niebieskiego, aby uzyskać różne kolory i pomalować kształty, aby zaspokoić popyt. - Na tę chwilę gra oferuje 18 poziomów (które powinny zagwarantować rozrywkę na co najmniej kilka godzin!), ale bez przerwy dodaję nowe - jest naprawdę wiele do dodania! + Ta gra oferuje 18 poziomów progresywnych (które powinny być zajęte przez wiele godzin!), Ale ciągle dodam nowe treści - Wiele jest zaplanowanych! + Zakup gry daje dostęp do samodzielnej wersji, która ma dodatkowe funkcje, a także dostęp do nowo opracowanych funkcji. - [b]Zalety pełnej wersji[/b] + [b]Samodzielne zalety[/b] [list] - [*] Znaczniki - [*] Nielimitowana ilość zapisanych gier - [*] Ciemny motyw gry - [*] Więcej ustawień - [*] Pomożesz mi w dalszym rozwijaniu shapez.io ❤️ - [*] Więcej zawartości niedługo! + [*] Tryb ciemny + [*] Nieograniczone punkty trasy + [*] Nieograniczona liczba zapisanych gier + [*] Dodatkowe ustawienia + [*] Wkrótce: przewody i energia! Dążenie do (z grubsza) końca lipca 2020 r. + [*] Wkrótce: Więcej poziomów + [*] Pozwala mi dalej rozwijać shapez.io ❤️ [/list] - [b]Zaplanowana zawartość & Sugestie społeczności[/b] + [b]Przyszłe aktualizacje[/b] - Ta gra jest open-source - Każdy może pomóc w rozwoju! Poza tym słucham tego, co społeczność ma do powiedzenia w kwestii gry! Staram się czytać wszystkie sugestie i odbierać jak najwięcej informacji zwrotnych na temat gry. + Aktualizuję grę bardzo często i staram się przesyłać aktualizacje przynajmniej co tydzień! [list] - [*] Kampania, gdzie do budowy potrzeba kształtów - [*] Więcej poziomów i budynków (tylko w pełnej wersji) - [*] Inne mapy, może z przeszkodami - [*] Możliwość modyfikowania parametrów generowanej mapy (ilość i rozmiar surowców, ziarno świata, itd.) - [*] Więcej rodzajów kształtów - [*] Optymalizacja (mimo wszystko gra już działa dość płynnie!) - [*] Tryb dla ślepoty barw + [*] Różne mapy i wyzwania (np. Mapy z przeszkodami) + [*] Puzzle (Dostarcz żądany kształt z ograniczonym obszarem / zestawem budynków) + [*] Tryb fabularny, w którym budynki kosztują + [*] Konfigurowalny generator map (Konfiguruj rozmiar / gęstość zasobu / kształtu, ziarno i więcej) + [*] Dodatkowe typy kształtów + [*] Ulepszenia wydajności (gra działa już całkiem dobrze!) [*] I wiele więcej! [/list] - Sprawdź tablicę trello i zobacz nad czym teraz pracuję! https://trello.com/b/ISQncpJP/shapezio + [b]Ta gra jest open source![/b] + + Każdy może się przyłączyć, jestem aktywnie zaangażowany w społeczność i staram się przejrzeć wszystkie sugestie i wziąć pod uwagę opinie tam, gdzie to możliwe. + Zapoznaj się z moją tablicą trello, aby zobaczyć pełną mapę drogową! + + [b]Linki[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Oficjalna Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Kod źródłowy (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Pomóż w tłumaczeniu[/url] + [/list] + + discordLink: Oficjalna Discord - Porozmawiaj ze mną! global: loading: Ładowanie @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: " " + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. # Translator note: We don't use SI size units for common speak, but if you want to keep it SI # ...also, Polish has wierd nature of diffrent number naming, we have "million" and "milliard"-thing wich actually is billion in English @@ -136,29 +156,7 @@ mainMenu: savegameLevel: Poziom savegameLevelUnknown: Nieznany poziom - contests: - contest_01_03062020: - title: "Konkurs #01" - desc: Wygraj 25$ za najciekawszą bazę! - #Translator note: We don't use AM/PM, we mainly use 24 hour clock system, older generations use 12h - longDesc: >- - Żeby dać wam coś od siebie, pomyślałem, że było by fajnie robić tygodniowe konkursy! -

- Temat tego tygodnia: Zbuduj najciekawszą fabrykę! -

- Zasady:
-
    -
  • Wyślij zrzut ekranu fabryki na adres contest@shapez.io
  • -
  • Dodatkowe punkty za udostępnianie na mediach społecznościowych!
  • -
  • Wybiorę 5 najlepszych moim zdaniem projektów i pozwolę społeczności discord głosować.
  • -
  • Wygrany dostaje $25 (Paypal, Amazon Gift Card, którekolwiek wolisz).
  • -
  • Termin: 07.06.2020 12:00 CEST
  • -
-
- Nie mogę się doczekać, by zobaczyć Wasze fabryki! - showInfo: Wyświetl - contestOver: Ten konkurs już się skończył - Dołącz do serwera Discord by nie przegapić kolejnych! madeBy: Gra wykonana przez subreddit: Reddit @@ -259,7 +257,7 @@ dialogs: createMarker: title: Nowy Znacznik desc: Podaj nazwę znacznika. Możesz w niej zawrzeć kod kształtu, który możesz wygenerować tutaj. - + titleEdit: Edytuj Znacznik markerDemoLimit: desc: Możesz stworzyć tylko dwa własne znaczniki w wersji demo. Zakup pełną wersję gry dla nielimitowanych znaczników! @@ -275,6 +273,10 @@ dialogs: fabryki ta akcja może być bardzo wolna, a nawet może spowodować zawieszenie się lub awarię gry! Czy na pewno chcesz kontynuować? + massCutInsufficientConfirm: + title: Potwierdź cięcie + desc: Nie możesz sobie pozwolić na wklejenie tego obszaru! Czy na pewno chcesz to wyciąć? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -297,6 +299,7 @@ ingame: copySelection: Skopiuj clearSelection: Wyczyść zaznaczenie pipette: Wybierz obiekt z mapy + switchLayers: Switch layers # Names of the colors, used for the color blind mode colors: @@ -308,6 +311,7 @@ ingame: cyan: Cyjanowy white: Biały uncolored: Brak koloru + black: Black # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -353,7 +357,7 @@ ingame: # 2nd translator's note: I think translating this to "level" is better (and that's how Google Translate translates it :)) tier: Poziom - # The roman number for each tier + # The roman numeral for each tier tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X] maximumLevel: POZIOM MAKSYMALNY (Szybkość x) @@ -410,6 +414,7 @@ ingame: shapeViewer: title: Poziomy empty: Puste + copyKey: Copy Key # Interactive tutorial interactiveTutorial: @@ -529,6 +534,27 @@ buildings: storage: name: Magazyn description: Magazynuje obiekty, do określonego limitu. Może zostać użyty jako bramka przepełnienia. + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -546,7 +572,7 @@ storyRewards: reward_painter: title: Malowanie desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + Odblokowano nową maszynę: Maszyna Malująca - wydobądź kilka pigmentów (identycznie jak kształty) i połącz je z kształtami aby je pomalować!

PS: Jeśli nie widzisz kolorów, w ustawieniach znajduje się color blind mode! reward_mixer: title: Mieszanie @@ -750,14 +776,14 @@ settings: 100 budynków. enableColorBlindHelper: - title: Color Blind Mode - description: Enables various tools which allow to play the game if you are color blind. + title: Tryb ślepy na kolory + description: Włącza różne narzędzia, które pozwalają ci grać, jeśli jesteś daltonistą. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Obrót według typu budynku + description: >- + Każdy typ budynku pamięta obrót, który ostatnio ustawiłeś indywidualnie. + Może to być wygodniejsze, jeśli często przełączasz się między umieszczaniem + różne typy budynków. keybindings: title: Klawiszologia @@ -825,6 +851,11 @@ keybindings: switchDirectionLockSide: >- Planowanie taśmociągu: Zmień stronę pipette: Wybieranie obiektów z mapy + menuClose: Zamknij Menu + switchLayers: zamknij menu + advanced_processor: Kolor Falownika + energy_generator: Generator Energii + wire: Drut Energetyczny about: title: O Grze diff --git a/translations/base-pt-BR.yaml b/translations/base-pt-BR.yaml index e53c845f..5f7a8948 100644 --- a/translations/base-pt-BR.yaml +++ b/translations/base-pt-BR.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io é um jogo sobre construir fábricas para automatizar a criação e combinação de formas. Entregue formas cada vez mais complexas pedidas pelo jogo para progredir e desbloquear melhorias que aceleram sua fábrica. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Como a demanda é crescente, será necessário dimensionar uma fábrica que atenda a necessidade - Não se esqueça dos recursos à sua disposição, você poderá expandir em um [b]mapa infinito[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Formas podem ficar entediantes por si só, logo você terá que misturar cores e pintá-las - Combine os recursos vermelho, verde e azul para produzir cores diferentes e pintar as formas com elas pra atender a demanda. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - Esse jogo apresenta 18 níveis (que já devem mantê-lo ocupado por horas!) mas estou constantemente adicionado conteúdo novo - Muito já está planejado! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]Vantagens da Versão Standalone[/b] + [b]Standalone Advantages[/b] [list] - [*] Marcações no mapa - [*] Jogos salvos ilimitados - [*] Modo escuro - [*] Mais opções no menu - [*] Me ajuda a desenvolver mais o shapez.io ❤️ - [*] Ainda mais recursos no futuro! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Melhoras Planejadas & Sugestões da Comunidade[/b] + [b]Future Updates[/b] - Esse jogo tem código aberto - Qualquer um pode contribuir! Além disso, eu ouço [b]muito[/a] a comunidade! Tento ler todas as sugestões e levar o máximo possível de comentários sobre o jogo em consideração. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Modo história, onde construir custará formas - [*] Mais níves & construções (exclusivo da versão standalone) - [*] Mapas diferentes, e talvez obstáculos no mapa - [*] Criação de mapa configurável (Número e tamanho de recursos, seed, e mais) - [*] Mais tipos de formas - [*] Mais melhoras no desempenho (Mesmo que o jogo já esteja rodando bem rápido!) - [*] Acessibilidade para daltonismo - [*] E muito mais! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - Não deixe de conferir na minha página no trello o planejamento completo! (em inglês) https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Carregando @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "." + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "," + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: K @@ -130,32 +150,11 @@ mainMenu: savegameLevel: Nível savegameLevelUnknown: Nível desconhecido - contests: - contest_01_03062020: - title: "Concurso #01" - desc: Ganhe $25 pela melhor base! - longDesc: >- - Para retribuir, pensei que seria legal fazer concursos semanais! -

- Tópico dessa semana: Construa a base mais legal! -

- Esse é o plano:
-
    -
  • Envie uma captura de tela da sua base para contest@shapez.io
  • -
  • Pontos bônus se você o compartilhar nas mídias sociais!
  • -
  • Vou escolher 5 capturas de tela e propor à votação a comunidade discord.
  • -
  • o vencedor recebe $25 (Paypal, Amazon Gift Card, o que você preferir)
  • -
  • Até 07.06.2020 12:00 CEST
  • -
-
- Estou ansioso para ver suas criações incríveis! - showInfo: Participar - contestOver: Esse concurso está encerrado - Entre no discord para ser informado sobre novos concursos! helpTranslate: Ajude a traduzir! - continue: Continue - newGame: New Game - madeBy: Made by + continue: Continuar + newGame: Novo jogo + madeBy: Feito por subreddit: Reddit dialogs: @@ -255,6 +254,7 @@ dialogs: createMarker: title: Nova Marcação desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker markerDemoLimit: desc: >- Você só pode criar dois marcadores na versão demo. Adquira a versão completa para marcadores ilimitados! @@ -269,6 +269,10 @@ dialogs: desc: >- Você está prestes a exportar uma captura de tela da sua base. Note que isso pode ser bastante lento para uma base grande, e até mesmo pode travar o jogo! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -292,6 +296,7 @@ ingame: copySelection: Copy clearSelection: Clear Selection pipette: Pipette + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -406,9 +411,11 @@ ingame: cyan: Cyan white: White uncolored: No color + black: Black shapeViewer: title: Layers empty: Empty + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -518,6 +525,27 @@ buildings: deliver: Entregue toUnlock: para desbloquear levelShortcut: LVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -609,9 +637,9 @@ settings: versionBadges: dev: Desenvolvedor - staging: Staging + staging: Teste prod: Produção - buildDate: Built + buildDate: Compilado labels: uiScale: @@ -691,48 +719,47 @@ settings: super_fast: Super Rápido extremely_fast: Extremamente Rápido enableTunnelSmartplace: - title: Smart Tunnels + title: Túneis inteligentes description: >- - When enabled, placing tunnels will automatically remove unnecessary belts. - This also enables to drag tunnels and excess tunnels will get removed. + Quando colocados, irão remover automaticamente esteiras desnecessárias. + Isso também permite arrastar túneis e túneis em excesso serão removidos. vignette: title: Vignette description: >- - Enables the vignette which darkens the screen corners and makes text easier - to read. + Permite o modo vinheta que escurece os cantos da tela e facilita a + leitura do texto. autosaveInterval: - title: Autosave Interval + title: Intervalo de gravação automática description: >- - Controls how often the game saves automatically. You can also disable it - entirely here. + Controla a frequência com que o jogo salva automaticamente. + Você também pode desativá-lo totalmente aqui. intervals: - one_minute: 1 Minute - two_minutes: 2 Minutes - five_minutes: 5 Minutes - ten_minutes: 10 Minutes - twenty_minutes: 20 Minutes - disabled: Disabled + one_minute: 1 Minuto + two_minutes: 2 Minutos + five_minutes: 5 Minutos + ten_minutes: 10 Minutos + twenty_minutes: 20 Minutos + disabled: Desativado compactBuildingInfo: - title: Compact Building Infos + title: Informações compactas sobre edifícios description: >- - Shortens info boxes for buildings by only showing their ratios. Otherwise a - description and image is shown. + Reduz as caixas de informações dos edifícios, mostrando apenas suas proporções. + Caso contrário, uma descrição e imagem são mostradas. disableCutDeleteWarnings: - title: Disable Cut/Delete Warnings + title: Desativar avisos de recorte / exclusão description: >- - Disable the warning dialogs brought up when cutting/deleting more than 100 - entities. + Desative as caixas de diálogo de aviso exibidas ao cortar / excluir + mais de 100 entidades. enableColorBlindHelper: - title: Color Blind Mode - description: Enables various tools which allow to play the game if you are color blind. + title: Modo daltônico. + description: Permite várias ferramentas que permitem jogar se você é daltônico. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotação por tipo de construção + description: >- + Cada tipo de construção lembra a rotação que você definiu pela última vez individualmente. + Isso pode ser mais confortável se você alternar frequentemente entre a colocação de diferentes tipos de construção. keybindings: title: Controles @@ -796,10 +823,15 @@ keybindings: pasteLastBlueprint: Colar último projeto massSelectCut: Cortar área exportScreenshot: Exportar base inteira como imagem - mapMoveFaster: Move Faster - lockBeltDirection: Enable belt planner - switchDirectionLockSide: "Planner: Switch side" - pipette: Pipette + mapMoveFaster: Mover mais rápido + lockBeltDirection: Ativar planejador de correia + switchDirectionLockSide: "Planejador: Mudar de lado" + pipette: Pipeta + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: Sobre o jogo @@ -822,7 +854,7 @@ about: esse jogo nunca teria existido. changelog: - title: Changelog + title: Alterações demo: features: diff --git a/translations/base-pt-PT.yaml b/translations/base-pt-PT.yaml index a9f93efc..b04c2c90 100644 --- a/translations/base-pt-PT.yaml +++ b/translations/base-pt-PT.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io é um jogo cujo objetivo é construir fábricas para automatizar a criação e fusão de formas geométricas. Entrega as formas pedidas, que são cada vez mais complexas, de modo a progredir no jogo e desbloquear melhorias para acelerar a produção da tua fábrica + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Uma vez que a procura aumenta a cada nível, terás de aumentar a tua fábrica para fazer face às necessidades - Para isso, terás de te expandir no [b]mapa infinito[/b] para explorar todos os recursos! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Como produzir formas se tornará aborrecido rapidamente, não tardará até precisares de misturar cores e pintá-las com elas - Combina os recursos de cores vermelha, verde e azul para produzir diferentes cores e usá-las para pintar as formas geométricas com o intuito de satisfazer a procura. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - Este jogo conta com 18 níveis (Que deverão manter-te ocupado durante horas!) mas estou constantemente a adicionar novos conteúdos - Há muitas coisas planedas! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]Vantagens do jogo completo[/b] + [b]Standalone Advantages[/b] [list] - [*] Marcos - [*] Savegames infinitos - [*] Modo escuro - [*] Mais definições - [*] Possibilita-me desenvolver ainda mais o shapez.io ❤️ - [*] Mais conteúdo no futuro! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Conteúdo planeado & Sugestões da comunidade[/b] + [b]Future Updates[/b] - Este jogo é open source (código aberto) - Qualquer pessoa pode contribuir! Adicionalmente, Eu ouço [b]muito[/b] a comunidade! Eu tento ler todas as sugestões e retirar delas tanto feedback quanto possível. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Modo história onde as construções custam formas geométricas - [*] Mais níveis & construções (exclusivo do jogo completo) - [*] Mapas diferentes, e talvez com obstáculos - [*] Criação de mapas configuráveis (Editar o número e tamanho das minas, semente, e mais) - [*] Mais tipos de formas geométricas - [*] Mais melhorias de performance (Apesar do jogo já correr bastante bem!) - [*] Modo daltónico - [*] E muito mais! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - Segue o meu trello board para veres todo o roteiro de desenvolvimento! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: A carregar @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -114,7 +134,7 @@ demoBanners: # This is the "advertisement" shown in the main menu and other various places title: Versão Demo intro: >- - Compra a versão completa para desbloquear todas as funcionalidades! + Compra a versão completa para desbloqueares todas as funcionalidades! mainMenu: play: Jogar @@ -126,33 +146,12 @@ mainMenu: # This is shown when using firefox and other browsers which are not supported. browserWarning: >- - Desculpa, mas este jogo parece correr mais lentamente no teu navegador! Compra o jogo completo ou baixa o chrome para a melhorares a tua experiência. + Desculpa, mas este jogo parece correr mais lentamente no teu navegador! Compra o jogo completo ou baixa o chrome para melhorares a tua experiência. savegameLevel: Nível savegameLevelUnknown: Nível desconhecido - contests: - contest_01_03062020: - title: "Concurso #01" - desc: Ganha $25 para a base mais cool! - longDesc: >- - Para retribuir o teu apoio, pensei que seria bom fazer concursos semanais! -

- O tópico desta semana: Construir a base mais cool! -

- Como fazer:
-
    -
  • Envia uma captura de ecrã da tua base para contest@shapez.io
  • -
  • Bónus se o partilhares nas redes sociais!
  • -
  • Eu irei escolher 5 capturas de ecrã e propô-las-ei à comunidade do discord para votar.
  • -
  • O vencedor ganha $25 (Paypal, Amazon Gift Card, ou o que preferires)
  • -
  • Prazo: 07.06.2020 12:00 AM CEST
  • -
-
- Estou ansioso por ver as vossas fantásticas criações! - showInfo: Ver - contestOver: Este concurso terminou - Entra no discord para seres notificado quando abrirem novos concursos! continue: Continuar newGame: Novo Jogo madeBy: Criado por @@ -231,12 +230,12 @@ dialogs: title: Desbloqueia upgrades desc: >- Todas as formas geométricas que produzes podem ser usadas para desbloquear upgrades - Não destruas as tuas fábricas antigas! - A tab dos upgrades pode ser encontrada no canto superior direito do ecrã. + A aba dos upgrades pode ser encontrada no canto superior direito do ecrã. massDeleteConfirm: - title: Confirma a eliminação + title: Confirmar eliminação desc: >- - Estás a apagar muitas construções ( para ser exato)! Tens a certeza? + Estás a apagar muitas construções, ( para ser exato)! Tens a certeza? blueprintsNotUnlocked: title: Ainda não está desbloqueado @@ -255,6 +254,7 @@ dialogs: createMarker: title: Novo marco desc: Dá-lhe um nome com significado, também poderás adicionar um pequeno código de uma forma. (Pode ser gerado aqui) + titleEdit: Edit Marker markerDemoLimit: desc: Apenas podes criar dois marcos na versão Demo. Adquire o jogo completo para colocar marcos infinitos! @@ -269,6 +269,10 @@ dialogs: Tu estás a pedir pra exportar a tua base como uma captura de ecrã. Por favor tem em atenção que isto pode ser um pouco lento para uma base muito grande até mesmo bloquear o teu jogo! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -291,6 +295,7 @@ ingame: copySelection: Copiar clearSelection: Cancelar pipette: Pipeta + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -324,7 +329,7 @@ ingame: # Notifications on the lower right notifications: newUpgrade: Está disponível um novo upgrade! - gameSaved: O teu jogo foi gravado. + gameSaved: O teu jogo foi guardado. # The "Upgrades" window shop: @@ -403,12 +408,14 @@ ingame: blue: Azul yellow: Amarelo purple: Roxo - cyan: Azul-bebé + cyan: Ciano white: Branco uncolored: Sem cor + black: Black shapeViewer: title: Camadas empty: Vazio + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -466,10 +473,10 @@ buildings: cutter: default: name: &cutter Cortador - description: Corta as formas geométricas de cima para baixo e produz duas metades. Se apenas usares uma parte, certifica-te de que destrois a outra parte de forma a não encravar a produção! + description: Corta as formas, de cima para baixo, em duas partes. Se apenas usares uma parte, destrói a outra para não encravar a produção! quad: - name: Cortador (Quádruplo) - description: Corta as formas geométricas em quatro partes. Se apenas usares uma parte, certifica-te de que destrois as outras partes de forma a não encravar a produção! + name: Cortador (Quad) + description: Corta as formas geométricas em quatro partes. Se apenas usares uma parte, destrói as outras partes para não encravar a produção! rotater: default: @@ -515,6 +522,27 @@ buildings: deliver: Entrega toUnlock: para desbloquear levelShortcut: NVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -529,7 +557,7 @@ storyRewards: reward_painter: title: Pintura desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + O Pintor foi desbloqueado - Extrai alguns pigmentos coloridos (tal como fazes com as formas) e combina-os com uma forma no pintor para a colorir!

PS: Se fores daltónico, existe um modo daltónico nas definições! reward_mixer: title: Mistura de Cores @@ -691,8 +719,8 @@ settings: enableTunnelSmartplace: title: Túneis inteligentes description: >- - Quando ativo, a colocação de túneis removerá tapetes desnecessários automaticamente. - Isto também permite arrastar túneis e túneis supérfluos serão removidos. + Quando ativado, a colocação de túneis removerá tapetes desnecessários automaticamente. + Isto também permite arrastar túneis e túneis em excesso serão removidos. vignette: title: Vinheta description: >- @@ -714,7 +742,7 @@ settings: compactBuildingInfo: title: Informações de construções compactas description: >- - Encurta caixas de informação mostrando apenas os respetivos rácios. Caso contrário + Encurta caixas de informação e apenas mostra os respetivos rácios. Caso contrário é mostrada a descrição e a imagem. disableCutDeleteWarnings: title: Desativar Avisos de Corte/Eliminação @@ -724,13 +752,13 @@ settings: enableColorBlindHelper: title: Modo Daltónico - description: Ativa várias ferramentas para daltónicos. + description: Ativa várias ferramentas que te permitirão jogar o jogo se fores daltónico. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotação por tipo de construção + description: >- + Cada tipo construção lembra-se da última rotação que definiste. + Esta definição pode ser mais confortável se alterares frequentemente + a colocação de diferentes tipos de construções. keybindings: title: Atalhos @@ -798,6 +826,11 @@ keybindings: lockBeltDirection: Ativa o planeamento de tapetes switchDirectionLockSide: "Planeador: Troca o lado" pipette: Pipeta + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: Sobre o jogo body: >- diff --git a/translations/base-ro.yaml b/translations/base-ro.yaml index 48b29af4..d7b7a8fc 100644 --- a/translations/base-ro.yaml +++ b/translations/base-ro.yaml @@ -21,7 +21,7 @@ steamPage: # This is the short text appearing on the steam page - shortText: shapez.io is a game about building factories to automate the creation and combination of increasingly complex shapes within an infinite map. + shortText: shapez.io este un joc despre construirea fabricilor pentru a automatiza crearea și combinarea a din ce in ce mai complexe forme într-o hartă infinită. # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. # NOTICE: @@ -30,50 +30,70 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Unlimited Savegames [*] Dark Mode - [*] More settings - [*] Allow me to further develop shapez.io ❤️ - [*] More features in the future! + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - This game is open source - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story mode where buildings cost shapes - [*] More levels & buildings (standalone exclusive) - [*] Different maps, and maybe map obstacles - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] More types of shapes - [*] More performance improvements (Although the game already runs pretty good!) - [*] Color blind mode + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: - loading: Loading - error: Error + loading: Se Încarcă + error: Eroare # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -86,21 +106,21 @@ global: time: # Used for formatting past time dates - oneSecondAgo: one second ago - xSecondsAgo: seconds ago - oneMinuteAgo: one minute ago - xMinutesAgo: minutes ago - oneHourAgo: one hour ago - xHoursAgo: hours ago - oneDayAgo: one day ago - xDaysAgo: days ago + oneSecondAgo: acum o secundă + xSecondsAgo: acum secunde + oneMinuteAgo: acum un minut + xMinutesAgo: acum minute + oneHourAgo: acum o oră + xHoursAgo: acum ore + oneDayAgo: acum o zi + xDaysAgo: acum zile # Short formats for times, e.g. '5h 23m' secondsShort: s minutesAndSecondsShort: m s - hoursAndMinutesShort: h s + hoursAndMinutesShort: h m - xMinutes: minutes + xMinutes: minute keys: tab: TAB @@ -112,224 +132,207 @@ global: demoBanners: # This is the "advertisement" shown in the main menu and other various places - title: Demo Version + title: Versiunea Demo intro: >- - Get the standalone to unlock all features! + Ia versiunea Standalone pentru a debloca toate funcțiile! mainMenu: - play: Play + play: Joacă changelog: Changelog importSavegame: Import - openSourceHint: This game is open source! - discordLink: Official Discord Server - helpTranslate: Help translate! + openSourceHint: Acest joc este open source! + discordLink: Serverul oficial de Discord + helpTranslate: Ajută să traducem! # This is shown when using firefox and other browsers which are not supported. browserWarning: >- - Sorry, but the game is known to run slow on your browser! Get the standalone version or download chrome for the full experience. + Scuze dar, jocul este știut să ruleze încet pe browser-ul tău! Ia versiunea standalone sau descarcă chrome pentru experiența completă. - savegameLevel: Level - savegameLevelUnknown: Unknown Level + savegameLevel: Nivelul + savegameLevelUnknown: Nivel necunoscut - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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! - continue: Continue - newGame: New Game - madeBy: Made by + continue: Continuă + newGame: Joc nou + madeBy: Făcut de subreddit: Reddit dialogs: buttons: ok: OK - delete: Delete - cancel: Cancel - later: Later - restart: Restart - reset: Reset - getStandalone: Get Standalone - deleteGame: I know what I do - viewUpdate: View Update - showUpgrades: Show Upgrades - showKeybindings: Show Keybindings + delete: Șterge + cancel: Anulează + later: Mai târziu + restart: Restartează + reset: Resetează + getStandalone: Ia Standalone-ul + deleteGame: Știu ce fac + viewUpdate: Vezi Update-ul + showUpgrades: Vezi Upgrade-urile + showKeybindings: Arată tastele configurate importSavegameError: - title: Import Error + title: Eroare la Import text: >- - Failed to import your savegame: + Încercarea de import a eșuat: importSavegameSuccess: - title: Savegame Imported + title: Savegame importat text: >- - Your savegame has been successfully imported. + Savegame-ul tău a fost importat cu succes. gameLoadFailure: - title: Game is broken + title: Jocul este stricat text: >- - Failed to load your savegame: + Încercarea de încărcat savegame-ul a eșuat: confirmSavegameDelete: - title: Confirm deletion + title: Confirmă ștergerea text: >- - Are you sure you want to delete the game? + Ești sigur că vrei să ștergi acest joc? savegameDeletionError: - title: Failed to delete + title: Eroare la ștergere text: >- - Failed to delete the savegame: + Nu a reușit să se ștearga savegame-ul: restartRequired: - title: Restart required + title: Restartare necesară text: >- - You need to restart the game to apply the settings. + Trebuie să restartezi jocul pentru a aplica setările. editKeybinding: - title: Change Keybinding - desc: Press the key or mouse button you want to assign, or escape to cancel. + title: Schimbă Tastele configurate + desc: Apasă tasta sau butonul mouse-ului pe care vrei să îl atribui, sau escape pentru a anula. resetKeybindingsConfirmation: - title: Reset keybindings - desc: This will reset all keybindings to their default values. Please confirm. + title: Resetează Tastele configurate + desc: Acesta va reseta toate tastele configurate la valorile obișnuite. Vă rog să confirmați. keybindingsResetOk: - title: Keybindings reset - desc: The keybindings have been reset to their respective defaults! + title: Tastele configurate se resetează + desc: Tastele configurate au fost resetate la valorile lor obișnuite! featureRestriction: title: Demo Version - desc: You tried to access a feature () which is not available in the demo. Consider to get the standalone for the full experience! + desc: Ai încercat să accesezi o funcție () care nu este disponibilă în demo. Consideră să iei standalone-ul pentru experiența completă! oneSavegameLimit: - title: Limited savegames - desc: You can only have one savegame at a time in the demo version. Please remove the existing one or get the standalone! + title: Savegame-uri limitate + desc: Poți avea doar un savegame în același timp în versiunea demo. Te rugăm șterge-o pe cea existentă sau ia standalone-ul! updateSummary: - title: New update! + title: Update nou! desc: >- - Here are the changes since you last played: + Aici sunt schimbările de când ai jucat ultima oară: upgradesIntroduction: - title: Unlock Upgrades + title: Deblochează Upgrade-uri desc: >- - All shapes you produce can be used to unlock upgrades - Don't destroy your old factories! - The upgrades tab can be found on the top right corner of the screen. + Toate formele pe care le produci pot fi folosite să deblochezi upgrade-uri - Nu îți distruge vechile fabrici! + Fila upgrade-urilor poate fi găsită în colțul din dreapta sus al ecranului. massDeleteConfirm: - title: Confirm delete + title: Confirmă ștergerea desc: >- - You are deleting a lot of buildings ( to be exact)! Are you sure you want to do this? + Stergeți multe construcții ( pentru a fi exact)! Sunteți sigur că vreți să faceți asta? blueprintsNotUnlocked: - title: Not unlocked yet + title: Nu este deblocat încă desc: >- - Blueprints have not been unlocked yet! Complete more levels to unlock them. + Planurile nu au fost deblocate încă! Completează mai multe nivele să le deblochezi. keybindingsIntroduction: - title: Useful keybindings + title: Taste configurate folositoare desc: >- - This game has a lot of keybindings which make it easier to build big factories. - Here are a few, but be sure to check out the keybindings!

- CTRL + Drag: Select area to copy / delete.
- SHIFT: Hold to place multiple of one building.
- ALT: Invert orientation of placed belts.
+ Acest joc are multe taste configurate care fac construitul fabricilor mari mai ușor. + Aici sunt câteva dar, fii sigur să verifici tastele configurate!

+ CTRL + Drag: Selectează o zonă pentreu a copia / delete.
+ SHIFT: Ține apăsat pentru a plasa mai multe dintr-o clădire.
+ ALT: Inversează orientația a benzilor rulante.
createMarker: - title: New Marker - desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + title: Nou waypoint + desc: Dă-i un nume plin de înțeles, de asemenea poți include a codul scurt al unei forme (Pe care îl poți genera here) + titleEdit: Edit Marker markerDemoLimit: - desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! + desc: Poți crea decât două waypoint-uri personalizate în demo. Ia standalone-ul pentru Waypoint-uri nelimitate! massCutConfirm: - title: Confirm cut + title: Confirmă tăierea desc: >- - You are cutting a lot of buildings ( to be exact)! Are you sure you - want to do this? + Tu tai multe construcții ( pentru a fi precis)! Sunteți sigur că vreți să faceți asta? exportScreenshotWarning: - title: Export screenshot + title: Exportează captură de ecran desc: >- - You requested to export your base as a screenshot. Please note that this can - be quite slow for a big base and even crash your game! + Ai solicitat să exportezi baza ta ca o captură de ecran. Vă rugăm să rețineți că asta poate fi destul de lent pentru o bază mare și poate chiar să blocheze jocul! + + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? ingame: # This is shown in the top left corner and displays useful keybindings in # every situation keybindingsOverlay: moveMap: Move - selectBuildings: Select area - stopPlacement: Stop placement - rotateBuilding: Rotate building - placeMultiple: Place multiple - reverseOrientation: Reverse orientation - disableAutoOrientation: Disable auto orientation - toggleHud: Toggle HUD - placeBuilding: Place building - createMarker: Create Marker - delete: Destroy - pasteLastBlueprint: Paste last blueprint - lockBeltDirection: Enable belt planner - plannerSwitchSide: Flip planner side - cutSelection: Cut - copySelection: Copy - clearSelection: Clear Selection + selectBuildings: Selectează zona + stopPlacement: Oprește plasarea + rotateBuilding: Rotește construcția + placeMultiple: Plasează mai multe + reverseOrientation: Întoarce orientarea + disableAutoOrientation: Dezactivați auto orientarea + toggleHud: Comută Interfața + placeBuilding: Plasează construcția + createMarker: Crează Waypoint + delete: Distruge + pasteLastBlueprint: Lipește ultimul plan + lockBeltDirection: Activează planificator de benzi + plannerSwitchSide: Întoarce partea planificatorului + cutSelection: Taie + copySelection: Copiază + clearSelection: Golește Secțiunea pipette: Pipette + switchLayers: Switch layers # 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: Press to cycle variants. + cycleBuildingVariants: Apasă pentru a cicla variantele. # Shows the hotkey in the ui, e.g. "Hotkey: Q" hotkeyLabel: >- - Hotkey: + Tasta: infoTexts: - speed: Speed - range: Range - storage: Storage - oneItemPerSecond: 1 item / second - itemsPerSecond: items / s + speed: Viteză + range: Distanță + storage: Capacitate + oneItemPerSecond: 1 obiect / second + itemsPerSecond: obiecte / s itemsPerSecondDouble: (x2) - tiles: tiles + tiles: Câmpuri # The notification when completing a level levelCompleteNotification: # is replaced by the actual level, so this gets 'Level 03' for example. - levelTitle: Level - completed: Completed - unlockText: Unlocked ! - buttonNextLevel: Next Level + levelTitle: Nivelul + completed: Completat + unlockText: Ai deblocat ! + buttonNextLevel: Nivelul următor # Notifications on the lower right notifications: - newUpgrade: A new upgrade is available! - gameSaved: Your game has been saved. + newUpgrade: Un upgrade nou este disponibil! + gameSaved: Jocul tău a fost salvat. # The "Upgrades" window shop: - title: Upgrades + title: Upgrade-uri buttonUnlock: Upgrade # Gets replaced to e.g. "Tier IX" @@ -338,435 +341,452 @@ ingame: # The roman number for each tier tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X] - maximumLevel: MAXIMUM LEVEL (Speed x) + maximumLevel: NIVELUL MAXIM (Speed x) # The "Statistics" window statistics: - title: Statistics + title: Statistici dataSources: stored: - title: Stored - description: Displaying amount of stored shapes in your central building. + title: Stocate + description: Afișează numărul de forme stocate în construcția centrală . produced: - title: Produced - description: Displaying all shapes your whole factory produces, including intermediate products. + title: Produse + description: Afișează toate formele pe care fabrica ta le produce, incluzând produsele intermediate. delivered: - title: Delivered - description: Displaying shapes which are delivered to your central building. - noShapesProduced: No shapes have been produced so far. + title: Livrate + description: Afișează formele care sunt livrate la construcția centrală. + noShapesProduced: Nicio formă nu a fost produsă până acum. # Displays the shapes per minute, e.g. '523 / m' shapesPerMinute: / m # Settings menu, when you press "ESC" settingsMenu: - playtime: Playtime + playtime: Timp jucat - buildingsPlaced: Buildings - beltsPlaced: Belts + buildingsPlaced: Construcții + beltsPlaced: Benzi buttons: - continue: Continue - settings: Settings - menu: Return to menu + continue: Continuă + settings: Setări + menu: Întoarce-te în meniu # Bottom left tutorial hints tutorialHints: - title: Need help? - showHint: Show hint - hideHint: Close + title: Ai nevoie de ajutor? + showHint: Arată o idee + hideHint: Închide # When placing a blueprint blueprintPlacer: - cost: Cost + cost: Preț # Map markers waypoints: - waypoints: Markers - hub: HUB - description: Left-click a marker to jump to it, right-click to delete it.

Press to create a marker from the current view, or right-click to create a marker at the selected location. - creationSuccessNotification: Marker has been created. + waypoints: Waypointuri + hub: Interfață + description: Click-stânga pe un waypoint pentru a merge la el, click-dreapta pentru a îl șterge.

Apasă pentru a crea un waypoint din perspectiva actuală, sau click-dreapta pentru a crea un waypoint. + creationSuccessNotification: Waypointul a fost creat. # Interactive tutorial interactiveTutorial: title: Tutorial hints: - 1_1_extractor: Place an extractor on top of a circle shape to extract it! + 1_1_extractor: Plasează un extractor pe o formă de cerc pentru a o extrage! 1_2_conveyor: >- - Connect the extractor with a conveyor belt to your hub!

Tip: Click and drag the belt with your mouse! + Conectează extractorul cu obandă rulantă până la centru!

Sfat: Click și trage banda cu mouse-ul tău! 1_3_expand: >- - This is NOT an idle game! Build more extractors and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them. + Acesta NU este un joc idle! Construiește mai multe extractoare și benzi pentru a finaliza scopul mai rapid.

Sfat: Ține apăsat SHIFT pentru a plasa mai multe extractoare, și flosește R pentru a le roti. colors: - red: Red - green: Green - blue: Blue - yellow: Yellow - purple: Purple + red: Roșu + green: Verde + blue: Albastru + yellow: Galben + purple: Mov cyan: Cyan - white: White - uncolored: No color + white: Alb + uncolored: Necolorat + black: Black shapeViewer: - title: Layers - empty: Empty + title: Start + empty: Gol + copyKey: Copy Key # All shop upgrades shopUpgrades: belt: - name: Belts, Distributor & Tunnels - description: Speed x → x + name: Benzi, Distribuitor & Tunele + description: Viteza x → x miner: - name: Extraction - description: Speed x → x + name: Extractoare + description: Viteza x → x processors: - name: Cutting, Rotating & Stacking - description: Speed x → x + name: Tăiere, Rotație & Presare + description: Viteza x → x painting: - name: Mixing & Painting - description: Speed x → x + name: Amestecare & Pictare + description: Viteza x → x # Buildings and their name / description buildings: belt: default: - name: &belt Conveyor Belt - description: Transports items, hold and drag to place multiple. + name: &belt Benzi Rulante + description: Transportă obiecte, ține apăsat și trage pentru a plasa mai multe. miner: # Internal name for the Extractor default: name: &miner Extractor - description: Place over a shape or color to extract it. + description: Plasează peste o formă sau culoare pentru a o extrage. chainable: - name: Extractor (Chain) - description: Place over a shape or color to extract it. Can be chained. + name: Extractor (lanț) + description: Plasează peste o formă sau culoare pentru a o extrage. Poate fi înlănțuit. underground_belt: # Internal name for the Tunnel default: - name: &underground_belt Tunnel - description: Allows to tunnel resources under buildings and belts. + name: &underground_belt Tunel + description: Permite transportarea resurselor pe sub construcții și benzi. tier2: name: Tunnel Tier II - description: Allows to tunnel resources under buildings and belts. + description: Permite transportarea resurselor pe sub construcții și benzi. splitter: # Internal name for the Balancer default: - name: &splitter Balancer - description: Multifunctional - Evenly distributes all inputs onto all outputs. + name: &splitter Distribuitor + description: Multifuncțional - Distribuie egal toate input-urile pe toate output-urile. compact: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Combinator (compact) + description: Combină două benzi rulante în una. compact-inverse: - name: Merger (compact) - description: Merges two conveyor belts into one. + name: Combinator (compact) + description: Combină două benzi rulante în una. cutter: default: - name: &cutter Cutter - description: Cuts shapes from top to bottom and outputs both halfs. If you use only one part, be sure to destroy the other part or it will stall! + name: &cutter Tăietor + description: Taie forme de sus în jos și scoate ambele jumătăți. Dacă folosești doar o parte, ține minte să o distrugi pe cealaltă sau producția se va opri! quad: - name: Cutter (Quad) - description: Cuts shapes into four parts. If you use only one part, be sure to destroy the other part or it will stall! + name: Tăietor (Quad) + description: Taie formele în patru părți. Dacă folosești doar o parte, ține minte să o distrugi pe cealaltă sau producția se va opri! rotater: default: name: &rotater Rotate - description: Rotates shapes clockwise by 90 degrees. + description: Rotește formele în sensul acelor de ceasornic la 90 de grade. ccw: name: Rotate (CCW) - description: Rotates shapes counter clockwise by 90 degrees. + description: Rotește formele în inversul sensului acelor de ceasornic la 90 de grade. stacker: default: - name: &stacker Stacker - description: Stacks both items. If they can not be merged, the right item is placed above the left item. + name: &stacker Mașină de presat + description: Unește ambele obiecte. Dacă ele nu poti fi unite, obiectul drept va fi pus peste obiectul stâng. mixer: default: - name: &mixer Color Mixer - description: Mixes two colors using additive blending. + name: &mixer Mixer de culori + description: Amestecă două culori folosind amestecuri aditive. painter: default: - name: &painter Painter - description: &painter_desc Colors the whole shape on the left input with the color from the right input. + name: &painter Mașină de pictat + description: &painter_desc Colorează întreaga formă din input-ul stâng folosind culoarea din input-ul drept. double: - name: Painter (Double) - description: Colors the shapes on the left inputs with the color from the top input. + name: Mașină de pictat (Dublu) + description: Colorează formele din input-urile din stânga folosind culoarea din input-ul de sus. quad: - name: Painter (Quad) - description: Allows to color each quadrant of the shape with a different color. + name: Mașină de pictat (Quad) + description: Permite colorarea fiecărui cadrant al formei cu o culoare diferită . mirrored: name: *painter description: *painter_desc trash: default: - name: &trash Trash - description: Accepts inputs from all sides and destroys them. Forever. + name: &trash Gunoi + description: Acceptă input-uri din toate părțile și le distruge. Pentru totdeauna. storage: - name: Storage - description: Stores excess items, up to a given capacity. Can be used as an overflow gate. + name: Depozit + description: Depozitează obiectele in exces, până la o capacitate dată. Poate fi folosit ca un overflow gate. hub: deliver: Deliver - toUnlock: to unlock + toUnlock: pentru a debloca levelShortcut: LVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store reward_cutter_and_trash: - title: Cutting Shapes - desc: You just unlocked the cutter - it cuts shapes half from top to bottom regardless of its orientation!

Be sure to get rid of the waste, or otherwise it will stall - For this purpose I gave you a trash, which destroys everything you put into it! + title: Tăierea formelor + desc: Tocmai ai deblocat tăietorul - taie forme pe jumate de jos în sus indiferent de orientație!

Ține minte să scapi de deșeuri, altfel se va opri - În acest scop ți-am dat un gunoi, care distruge tot ce pui în el! reward_rotater: - title: Rotating - desc: The rotater has been unlocked! It rotates shapes clockwise by 90 degrees. + title: Rotitul + desc: rotater-ul a fost deblocat! El rotește formele la 90 de grade. reward_painter: - title: Painting + title: Pictatul desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + The Mașina de pictat a fost deblocată - Extrage niște culori (la fel cum faci și cu formele) și combină-le cu o formă în mașina de pictat pentru a le colora!

PS: Dacă ești orb, acolo este un mod pentru orbi în setări! reward_mixer: - title: Color Mixing - desc: The mixer has been unlocked - Combine two colors using additive blending with this building! + title: Amestecatul culorilor + desc: Mixerul a fost deblocat - Combină două culori folosind amestecul de aditivi cu această clădire! reward_stacker: - title: Combiner - desc: You can now combine shapes with the combiner! Both inputs are combined, and if they can be put next to each other, they will be fused. If not, the right input is stacked on top of the left input! + title: Mașina de presat + desc: Acum poți combina forme cu mașina de presat! Ambele input-uri vor fi combinate, iar dacă ele pot fi puse alături, ele vor fi sudate. Dacă nu, input-ul drept este pus peste input-ul stâng! reward_splitter: - title: Splitter/Merger - desc: The multifunctional balancer has been unlocked - It can be used to build bigger factories by splitting and merging items onto multiple belts!

+ title: Distribuitor/Combinator + desc: Multifuncționalul distribuitor a fost deblocat - El poate fi folosit pentru a construi fabrici mai mari prin distribuirea și combinarea obiectelor pe benzi multiple!

reward_tunnel: - title: Tunnel - desc: The tunnel has been unlocked - You can now pipe items through belts and buildings with it! + title: Tunel + desc: Tunelul a fost deblocat - Acum poți deplasa obiecte prin benzi și construcții cu el! reward_rotater_ccw: - title: CCW Rotating - desc: You have unlocked a variant of the rotater - It allows to rotate counter clockwise! To build it, select the rotater and press 'T' to cycle its variants! + title: Rotarea CCW + desc: Ai deblocat o variantă a rotater-ului - El permite rotația în sensul invers al acelor de ceasornic! Pentru a îț construi, selectează rotater-ul și apasă 'T' pentru a cicla printre variante! reward_miner_chainable: title: Chaining Extractor - desc: You have unlocked the chaining extractor! It can forward its resources to other extractors so you can more efficiently extract resources! + desc: Ai deblocat Extractorul în lanț! El își poate transmite resursele la alte extractoare ca tu să poți extrage resurse mai eficient! reward_underground_belt_tier_2: title: Tunnel Tier II - desc: You have unlocked a new variant of the tunnel - It has a bigger range, and you can also mix-n-match those tunnels now! + desc: Ai deblocat o variantă nouă a tunelului - El are distanță mai mare, iar tu poți de asemenea să alternezi acele tunele acum! reward_splitter_compact: - title: Compact Balancer + title: Distribuitor compact desc: >- - You have unlocked a compact variant of the balancer - It accepts two inputs and merges them into one! + Ai deblocat o variantă compactă a distribuitorului - El acceptă două input-uri și le combină intr-una! reward_cutter_quad: - title: Quad Cutting - desc: You have unlocked a variant of the cutter - It allows you to cut shapes in four parts instead of just two! + title: Tăiatul quadriplu + desc: Ai deblocat o variantă a tăietorului - El îți permite să tai forme în patru părți în loc de doar două! reward_painter_double: - title: Double Painting - desc: You have unlocked a variant of the painter - It works as the regular painter but processes two shapes at once consuming just one color instead of two! + title: Pictatul dublu + desc: Ai deblocat o variantă a Mașini de pictat - Funcționează la fel ca o mașină de pictat normală dar, procesează două forme odată consumând doar o culoare în loc de două! reward_painter_quad: - title: Quad Painting - desc: You have unlocked a variant of the painter - It allows to paint each part of the shape individually! + title: Pictatul quadruplu + desc: Ai deblocat o variantă a Mașini de pictat - Ea permite să pictezi fiecare parte a formei individual! reward_storage: - title: Storage Buffer - desc: You have unlocked a variant of the trash - It allows to store items up to a given capacity! + title: Depozitul + desc: Ai deblocat o variantă a gunoiului - El permite să depoziți obiecte până într-o capacitate dată! reward_freeplay: - title: Freeplay - desc: You did it! You unlocked the free-play mode! This means that shapes are now randomly generated! (No worries, more content is planned for the standalone!) + title: Jocul liber + desc: Ai făcut-o! Ai deblocat modul de joc liber! Asta înseamnă că formele sunt acum generate aleatoriu! (Fără griji, mai mult conținut este planificat pentru versiunea standalone!) reward_blueprints: - title: Blueprints - desc: You can now copy and paste parts of your factory! Select an area (Hold CTRL, then drag with your mouse), and press 'C' to copy it.

Pasting it is not free, you need to produce blueprint shapes to afford it! (Those you just delivered). + title: Planuri + desc: Acum poți copia și lipi părți ale fabrici tale! Selectează o zonă (Ține apăsat CTRL, apoi trage cu mouse-ul tău), și apasă 'C' pentru a o copia.

Lipitul nu este gratis, ai nevoie să produci forme de planuri pentru a ți le permite! (Acelea pe care tocmai le-ai livrat). # Special reward, which is shown when there is no reward actually no_reward: - title: Next level + title: Nivelul următor desc: >- - This level gave you no reward, but the next one will!

PS: Better don't destroy your existing factory - You need all those shapes later again to unlock upgrades! + Acest nivel nu ți-a dat nimic dar, următor îți va da!

PS: Mai bine nu îți distruge fabricile construite - Ai nevoie de toate acele forme mai târziu din nou pentru a debloca upgrade-uri! no_reward_freeplay: - title: Next level + title: Nivelul următor desc: >- - Congratulations! By the way, more content is planned for the standalone! + Felicitări! Apropo, mai mult conținut este planificat pentru versiunea standalone! settings: - title: Settings + title: Setări categories: - game: Game - app: Application + game: Joc + app: Aplicație versionBadges: - dev: Development - staging: Staging - prod: Production - buildDate: Built + dev: Dezvoltare + staging: Beta + prod: Producere + buildDate: Construit labels: uiScale: - title: Interface scale + title: Scala de interfață description: >- - Changes the size of the user interface. The interface will still scale based on your device resolution, but this setting controls the amount of scale. + Schimbă dimensiunea interfeței utilizatorului. Această interfață tot se va scala bazată pe rezoluția dispozitivului dumneavoastră dar, această setare controlează cantitatea scalări. scales: - super_small: Super small - small: Small - regular: Regular - large: Large - huge: Huge + super_small: Foarte mică + small: Mică + regular: Normal + large: Mare + huge: Imens scrollWheelSensitivity: - title: Zoom sensitivity + title: Sensitivitatea Zoom-ului description: >- - Changes how sensitive the zoom is (Either mouse wheel or trackpad). + Schimbă cât de sensitiv zoom-ul este (Fie roata mouse-ului ori trackpadlui). sensitivity: - super_slow: Super slow - slow: Slow - regular: Regular - fast: Fast - super_fast: Super fast + super_slow: Foarte încet + slow: Încet + regular: Regulat + fast: Rapid + super_fast: Foarte rapid language: - title: Language + title: Limba description: >- - Change the language. All translations are user contributed and might be incomplete! + Schimbă limba. Toate traducerile sunt contribuite de utilizatori și pot fi incomplete! fullscreen: title: Fullscreen description: >- - It is recommended to play the game in fullscreen to get the best experience. Only available in the standalone. + Este recomandat ca jocul să fie jucat în fullscreen pentru a aveam cea mai bună experiență. Doar disponibil în versiunea standalone. soundsMuted: - title: Mute Sounds + title: Oprește sunetele description: >- - If enabled, mutes all sound effects. + Dacă este activat, oprește toate efectele sonore. musicMuted: - title: Mute Music + title: Oprește muzica description: >- - If enabled, mutes all music. + Dacă este activat, oprește toată muzica. theme: - title: Game theme + title: Tema jocului description: >- - Choose the game theme (light / dark). + Alege tema jocului (luminoasă / întunecată). themes: - dark: Dark - light: Light + dark: Întunecată + light: Luminoasă refreshRate: title: Simulation Target description: >- - If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates. This might actually decrease the FPS if your computer is too slow. + Dacă ai un monitor cu 144hz, schimbă refresh rate-ul aici și jocul va simula la refresh rate-uri mai mari. Acesta poate de fapt scădea FPS-urile dacă calculatorul dumneavoastră este prea lent. alwaysMultiplace: - title: Multiplace + title: Plasare multiplă description: >- - If enabled, all buildings will stay selected after placement until you cancel it. This is equivalent to holding SHIFT permanently. + Dacă este activat, toate construcțiile vor sta selectate până le anulezi. Asta este echivalent cu ținutul SHIFT-ului apăsat permanent. offerHints: - title: Hints & Tutorials + title: Indicii & Tutoriale description: >- - 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. + Dacă este activat, oferă indicii și tutoriale în timpul jocului. De asemenea ascunde anumite elemente ale interfeței utilizatorului certain UI pâna la anumite nivele pentru a ușura înțelegerea jocului. movementSpeed: - title: Movement speed - description: Changes how fast the view moves when using the keyboard. + title: Viteza de deplasare + description: Modifică viteza cât de rapid se mișcă vederea folosind tastatura. speeds: - super_slow: Super slow - slow: Slow - regular: Regular - fast: Fast - super_fast: Super Fast - extremely_fast: Extremely Fast + super_slow: Foarte încet + slow: Încet + regular: Normal + fast: Rapid + super_fast: Foarte Rapid + extremely_fast: Extrem de Rapid enableTunnelSmartplace: - title: Smart Tunnels + title: Tunele Inteligente description: >- - When enabled, placing tunnels will automatically remove unnecessary belts. - This also enables to drag tunnels and excess tunnels will get removed. + Când este activat, plasarea tunelelor va elimina automat benzile nefolositoare. + Aceasta permite de asemenea tragerea tunelelor și tunelele în exces vor fi șterse. vignette: title: Vignette description: >- - Enables the vignette which darkens the screen corners and makes text easier - to read. + Dacă este activat, înnegrește colțurile ecranului și face textul mai ușor de citit. autosaveInterval: - title: Autosave Interval + title: Intervalul de salvare automată description: >- - Controls how often the game saves automatically. You can also disable it - entirely here. + Controlează cât de des jocul se salvează automat. Poți de asemenea să o dezactivezi total aici. intervals: - one_minute: 1 Minute - two_minutes: 2 Minutes - five_minutes: 5 Minutes - ten_minutes: 10 Minutes - twenty_minutes: 20 Minutes - disabled: Disabled + one_minute: 1 Minut + two_minutes: 2 Minute + five_minutes: 5 Minute + ten_minutes: 10 Minute + twenty_minutes: 20 Minute + disabled: Dezactivat compactBuildingInfo: - title: Compact Building Infos + title: Informații ale construcțiilor compacte description: >- - Shortens info boxes for buildings by only showing their ratios. Otherwise a - description and image is shown. + Shortens info boxes for buildings by only showing their ratios. Otherwise adescription and image is shown. disableCutDeleteWarnings: - title: Disable Cut/Delete Warnings + title: Dezactivre Avertizări Tăiere/Ștergere description: >- - Disable the warning dialogs brought up when cutting/deleting more than 100 - entities. + Dezactivează avertizările dialogului adus când sunt șterse mai mult de 100 de entități. enableColorBlindHelper: - title: Color Blind Mode - description: Enables various tools which allow to play the game if you are color blind. + title: Modul pentru orbi de culoare + description: Activează diferite unelte care îți permit să joci jocul chiar dacă ești orb de culoare. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotație după tipul clădirii + description: >- + Fiecare tip de clădire ține minte ultima rotație pe care i-ai setat-o individual. Aceasta poate fi mai confortabil dacă schimbi frecvent între tipurile clădirilor. keybindings: - title: Keybindings + title: Tastele setate hint: >- - Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different placement options. + Indiciu: Asigură-te că foloseșto CTRL, SHIFT și ALT! Ele activează diferite opțiuni de plasare. resetKeybindings: Reset Keyinbindings categoryLabels: - general: Application - ingame: Game - navigation: Navigating - placement: Placement - massSelect: Mass Select - buildings: Building Shortcuts - placementModifiers: Placement Modifiers + general: Aplicație + ingame: Joc + navigation: Navigație + placement: Plasare + massSelect: Selectare în masă + buildings: Comenzi rapide pentru clădiri + placementModifiers: Modificatori de plasare mappings: confirm: Confirm - back: Back - mapMoveUp: Move Up - mapMoveRight: Move Right - mapMoveDown: Move Down - mapMoveLeft: Move Left - centerMap: Center Map + back: Înapoi + mapMoveUp: Mută în sus + mapMoveRight: Mută în dreapta + mapMoveDown: Mută în joc + mapMoveLeft: Mută în stânga + centerMap: Centrează harta - mapZoomIn: Zoom in - mapZoomOut: Zoom out - createMarker: Create Marker + mapZoomIn: Mărește imaginea + mapZoomOut: Micșorează imaginea + createMarker: Creează waypoint - menuOpenShop: Upgrades - menuOpenStats: Statistics + menuOpenShop: Upgrade-uri + menuOpenStats: Statistici - toggleHud: Toggle HUD - toggleFPSInfo: Toggle FPS and Debug Info + toggleHud: Comută interfața + toggleFPSInfo: Comută FPS and Debug Info belt: *belt splitter: *splitter underground_belt: *underground_belt @@ -778,57 +798,62 @@ keybindings: painter: *painter trash: *trash - rotateWhilePlacing: Rotate + rotateWhilePlacing: Rotește rotateInverseModifier: >- - Modifier: Rotate CCW instead - cycleBuildingVariants: Cycle Variants - confirmMassDelete: Confirm Mass Delete - cycleBuildings: Cycle Buildings + Modifier: Rotește CCW în schimb + cycleBuildingVariants: Ciclează Variante + confirmMassDelete: Confirmă ștergere în masă + cycleBuildings: Ciclează clădiri - massSelectStart: Hold and drag to start - massSelectSelectMultiple: Select multiple areas - massSelectCopy: Copy area + massSelectStart: Ține apăsat și trage pentru a începe + massSelectSelectMultiple: Selectează zone multiple + massSelectCopy: Copiază zona - placementDisableAutoOrientation: Disable automatic orientation - placeMultiple: Stay in placement mode - placeInverse: Invert automatic belt orientation - pasteLastBlueprint: Paste last blueprint - massSelectCut: Cut area - exportScreenshot: Export whole Base as Image - mapMoveFaster: Move Faster - lockBeltDirection: Enable belt planner - switchDirectionLockSide: "Planner: Switch side" + placementDisableAutoOrientation: Dezactivați orientarea automată + placeMultiple: Rămâneți în modul de plasare + placeInverse: Inversați orientarea automată a benzii + pasteLastBlueprint: Lipește ultimul plan + massSelectCut: Taie zona + exportScreenshot: Exportați întreaga bază ca imagine + mapMoveFaster: Deplasează-te mai repede + lockBeltDirection: Activează planificator de benzi + switchDirectionLockSide: "Planificator: Schimbă direcția" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: - title: About this Game + title: Despre acest joc body: >- - This game is open source and developed by Tobias Springer (this is me).

+ Acest joc este open source și dezvoltat de Tobias Springer (acesta sunt eu).

- If you want to contribute, check out shapez.io on github.

+ Dacă vrei să contribui, verifică shapez.io pe github.

- This game wouldn't have been possible without the great discord community - around my games - You should really join the discord server!

+ Acest joc nu ar fi fost posibil fără minunata comunitate de pe discord + pe lângă jocurile mele - Chiar ar trebui să te alături server-ului de discord!

- The soundtrack was made by Peppsen - He's awesome.

+ Coloana sonoră a fost făcută de Peppsen - Este uimitor.

- Finally, huge thanks to my best friend Niklas - Without our - factorio sessions this game would never have existed. + În final, mii de mulțumiri prietenului meu Niklas - Fără sesiunile noastre de + factorio acest joc nu ar fi existat niciodată. changelog: - title: Changelog + title: Lista de schimbări demo: features: - restoringGames: Restoring savegames - importingGames: Importing savegames - oneGameLimit: Limited to one savegame - customizeKeybindings: Customizing Keybindings - exportingBase: Exporting whole Base as Image + restoringGames: Restabilirea savegame-urilor + importingGames: Importarea savegame-urilor + oneGameLimit: Limitat la un savegame + customizeKeybindings: Taste customizabile + exportingBase: Exportul întregii baze ca imagine - settingNotAvailable: Not available in the demo. + settingNotAvailable: Nu este valabil în demo. diff --git a/translations/base-ru.yaml b/translations/base-ru.yaml index 73679e16..9166fed8 100644 --- a/translations/base-ru.yaml +++ b/translations/base-ru.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io — это игра о строительстве фабрик для автоматизации создания и объединения фигур. Доставляйте запрошенные, все более сложные фигуры, чтобы развиваться в игре и разблокировать улучшения, чтобы ускорить работу вашей фабрики. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Поскольку спрос растет, вам придется увеличивать свою фабрику, чтобы соответствовать потребностям. Однако, не забывайте о ресурсах, несмотря на то что вы будете расширятся на [b]бесконечной карте[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Поскольку фигуры вскоре могут наскучить, вам потребуется смешивать цвета и раскрашивать свои фигуры ими. Комбинируйте красный, зеленый и синий красители для получения разных цветов и красте ими фигуры, чтобы удовлетворить спрос. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - Эта игра имеет 18 уровней (но и они займут вас на часы!). Я постоянно добавляю новый контент - там много чего запланировано! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]Преимущества полной версии[/b] + [b]Standalone Advantages[/b] [list] - [*] Метки - [*] Неограниченное количество сохранений - [*] Темный режим - [*] Больше настроек - [*] Позволит мне быстрее разрабатывать shapez.io ❤️ - [*] Больше возможностей в будущем! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Планируемые функции & Предложения сообщества[/b] + [b]Future Updates[/b] - Это игра с открытым исходным кодом - любой может внести свой вклад! Кроме того, я во [b]многом[/b] прислушиваюсь к сообществу! Я стараюсь прочитать все предложения и учту как можно больше отзывов. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Режим истории, где здания стоят фигур - [*] Больше уровней & зданий (эксклюзивно для полной версии) - [*] Различные карты и, возможно, карта препятствий - [*] Настраиваемое создание карт (редактирование количества и размера участков, семя и т. д.) - [*] Больше видов фигур - [*] Больше улучшений производительности (хотя игра уже работает довольно хорошо!) - [*] Режим дальтоника - [*] И многое другое! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - Не забудьте проверить мою доску trello со всеми планами! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Загрузка @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -132,28 +152,7 @@ mainMenu: savegameLevel: Уровень savegameLevelUnknown: Неизвестный уровень - contests: - contest_01_03062020: - title: "Конкурс №01" - desc: Выиграй $25 за лучшую базу! - longDesc: >- - Чтобы вернуть вам что-то, я подумал, что было бы здорово проводить еженедельные конкурсы! -

- Тема этой недели: Постройка самой классной базы! -

- Вот что нужно сделать:
-
    -
  • Отправить скриншот вашей базы сюда: contest@shapez.io
  • -
  • Бонусные баллы, если вы поделитесь этим в социальных сетях!
  • -
  • Я выберу 5 скриншотов и предложу сообществу в дискорде проголосовать.
  • -
  • Победитель получит $25 (Paypal, Amazon Gift Card, что вы предпочитаете)
  • -
  • Крайний срок: 07.06.2020 12:00 AM CEST
  • -
-
- Я с нетерпением жду, чтобы увидеть ваши удивительные творения! - showInfo: Посмотреть - contestOver: Этот конкурс закончился - присоединяйтесь в дискорде, чтобы получать уведомления о новых конкурсах! continue: Продолжить newGame: Новая Игра madeBy: Создал @@ -256,6 +255,7 @@ dialogs: createMarker: title: Новый маркер desc: Дайте ему содержательное имя, также можно добавить сокращение в виде фигуры (Которое можно сгенерировать здесь) + titleEdit: Edit Marker markerDemoLimit: desc: Вы можете создать только 2 своих маркера в демо-версии. Приобретите полную версию для безлимитных маркеров. @@ -272,6 +272,10 @@ dialogs: что это может быть довольно медленным процессом для большой базы и даже привести к аварийному завершению игры! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -294,6 +298,7 @@ ingame: copySelection: Копировать clearSelection: Отменить pipette: Пипетка + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -409,9 +414,11 @@ ingame: cyan: Бирюзовый white: Белый uncolored: Бесцветный + black: Black shapeViewer: title: Слои empty: Пусто + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -518,6 +525,27 @@ buildings: deliver: Доставить toUnlock: чтобы открыть levelShortcut: Ур. + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -728,11 +756,11 @@ settings: title: Режим Дальтоника description: Включает различные инструменты, которые позволяют играть в игру дальтоникам. rotationByBuilding: - title: Поворот по типу здания - description: >- - Каждый тип здания запоминает поворот, который в последний раз был установлен. - С этой настройкой может быть удобнее, при частом переключении между - различными типами зданий. + title: Поворот по типу здания + description: >- + Каждый тип здания запоминает поворот, который в последний раз был установлен. + С этой настройкой может быть удобнее, при частом переключении между + различными типами зданий. keybindings: title: Настройки управления @@ -800,6 +828,11 @@ keybindings: lockBeltDirection: Включает конвейерный планировщик switchDirectionLockSide: "Планировщик: Переключение сторон" pipette: Пипетка + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: Об игре diff --git a/translations/base-sl.yaml b/translations/base-sl.yaml new file mode 100644 index 00000000..ce2a0ae4 --- /dev/null +++ b/translations/base-sl.yaml @@ -0,0 +1,870 @@ +# +# 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: `. They are encapsulated within angle brackets. The correct +# translation for this one in German for example would be: `Taste: ` (notice +# how the placeholder stayed '' 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. +# + +steamPage: + # This is the short text appearing on the steam page + shortText: shapez.io je igra grajenja tovarne katere cilj je avtomatiziranje kreiranja in procesiranja vse bolj zapletenih oblik na neskončni ravnini. + + # This is the text shown above the discord link + discordLink: Uradni Discord - Pridruži se klepetu! + + # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. + # NOTICE: + # - Do not translate the first line (This is the gif image at the start of the store) + # - Please keep the markup (Stuff like [b], [list] etc) in the same format + longText: >- + [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] + + shapez.io je igra grajenja tovarne katere cilj je avtomatiziranje kreiranja in procesiranja vse bolj zapletenih oblik na neskončni ravnini. + Ob dostavi zahtevanih oblik boste napredovali v igri in odklenili nadgradnje, da boste pospešili tovarno. + + Ko se bo povpraševanje po oblikah povečalo, boste morali prilagoditi svojo tovarno, da bo zadostilo povpraševanju. Ne pozabite na vire, morali pa se boste razširiti čez [b]neskončno ravnino[/b]! + + Kmalu boste morali mešati barve in z njimi barvati svoje oblike - Združite rdeče, zelene in modre barvne vire, da ustvarite različne barve in z njimi barvate oblike, da zadostite povpraševanju. + + V tej igri je 18 progresivnih stopenj (ki vas bodo zaposlile za več ur!), Vendar nenehno dodajam novo vsebino - načrtovanih novosti je veliko! + Nakup igre vam omogoča dostop do samostojne različice, ki ima dodatne funkcije, prav tako pa boste imeli dostop do novo razvitih funkcij. + + [img]{STEAM_APP_IMAGE}/extras/header_standalone_advantages.png[/img] + + [list] + [*] Temna tema + [*] Neomejeno označb + [*] Neomejeno shranjenih tovarn + [*] Dodatne nastavitve + [*] Prihaja kmalu: Žice in energija! Prihajajo (približno) konec julija 2020. + [*] Prihaja kmalu: Več stopenj + [*] Omogoča mi nadaljni razvoj shapez.io ❤️ + [/list] + + [img]{STEAM_APP_IMAGE}/extras/header_future_updates.png[/img] + + Igro posodabljam zelo pogosto in poskušam dodati novosti vsaj vsak teden! + + [list] + [*] Različni zemljevidi in izzivi (npr. Zemljevidi z ovirami) + [*] Izzivi (vnesite želeno obliko z omejenim območjem / nizom zgradb) + [*] Način zgodbe, kjer imajo stavbe stroške/cene + [*] Nastavljiv generator zemljevidov (konfigurirajte velikost / gostoto oblik /, seme in več) + [*] Dodatne vrste oblik + [*] Izboljšanje zmogljivosti (igra že sedaj deluje zelo dobro!) + [*] In veliko več! + [/list] + + [img]{STEAM_APP_IMAGE}/extras/header_open_source.png[/img] + + Vsakdo lahko prispeva, aktivno sem vključen v skupnost in poskušam pregledati vse predloge in upoštevati povratne informacije, kjer je to mogoče. + Bodite prepričani, da si oglejte mojo Trello ploščo za celoten načrt! + + [img]{STEAM_APP_IMAGE}/extras/header_links.png[/img] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Uradni Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Načrtovane posodobitve[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Izvorna Koda (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Pomagaj pri prevodu[/url] + [/list] + +global: + loading: Loading + error: Error + + # How big numbers are rendered, e.g. "10,000" + thousandsDivider: "," + + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + + # 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: one second ago + xSecondsAgo: seconds ago + oneMinuteAgo: one minute ago + xMinutesAgo: minutes ago + oneHourAgo: one hour ago + xHoursAgo: hours ago + oneDayAgo: one day ago + xDaysAgo: days ago + + # Short formats for times, e.g. '5h 23m' + secondsShort: s + minutesAndSecondsShort: m s + hoursAndMinutesShort: h m + + xMinutes: minutes + + keys: + tab: TAB + control: CTRL + alt: ALT + escape: ESC + shift: SHIFT + space: SPACE + +demoBanners: + # This is the "advertisement" shown in the main menu and other various places + title: Demo Version + intro: >- + Get the standalone to unlock all features! + +mainMenu: + play: Play + continue: Continue + newGame: New Game + changelog: Changelog + subreddit: Reddit + importSavegame: Import + openSourceHint: This game is open source! + discordLink: Official Discord Server + helpTranslate: Help translate! + madeBy: Made by + + # This is shown when using firefox and other browsers which are not supported. + browserWarning: >- + Sorry, but the game is known to run slow on your browser! Get the standalone version or download chrome for the full experience. + + savegameLevel: Level + savegameLevelUnknown: Unknown Level + +dialogs: + buttons: + ok: OK + delete: Delete + cancel: Cancel + later: Later + restart: Restart + reset: Reset + getStandalone: Get Standalone + deleteGame: I know what I am doing + viewUpdate: View Update + showUpgrades: Show Upgrades + showKeybindings: Show Keybindings + + importSavegameError: + title: Import Error + text: >- + Failed to import your savegame: + + importSavegameSuccess: + title: Savegame Imported + text: >- + Your savegame has been successfully imported. + + gameLoadFailure: + title: Game is broken + text: >- + Failed to load your savegame: + + confirmSavegameDelete: + title: Confirm deletion + text: >- + Are you sure you want to delete the game? + + savegameDeletionError: + title: Failed to delete + text: >- + Failed to delete the savegame: + + restartRequired: + title: Restart required + text: >- + You need to restart the game to apply the settings. + + editKeybinding: + title: Change Keybinding + desc: Press the key or mouse button you want to assign, or escape to cancel. + + resetKeybindingsConfirmation: + title: Reset keybindings + desc: This will reset all keybindings to their default values. Please confirm. + + keybindingsResetOk: + title: Keybindings reset + desc: The keybindings have been reset to their respective defaults! + + featureRestriction: + title: Demo Version + desc: You tried to access a feature () which is not available in the demo. Consider getting the standalone version for the full experience! + + oneSavegameLimit: + title: Limited savegames + desc: You can only have one savegame at a time in the demo version. Please remove the existing one or get the standalone version! + + updateSummary: + title: New update! + desc: >- + Here are the changes since you last played: + + upgradesIntroduction: + title: Unlock Upgrades + desc: >- + All shapes you produce can be used to unlock upgrades - Don't destroy your old factories! + The upgrades tab can be found on the top right corner of the screen. + + massDeleteConfirm: + title: Confirm delete + desc: >- + You are deleting a lot of buildings ( to be exact)! Are you sure you want to do this? + + massCutConfirm: + title: Confirm cut + desc: >- + You are cutting a lot of buildings ( to be exact)! Are you sure you want to do this? + + massCutInsufficientConfirm: + title: Confirm cut + desc: >- + You can not afford to paste this area! Are you sure you want to cut it? + + blueprintsNotUnlocked: + title: Not unlocked yet + desc: >- + Complete level 12 to unlock Blueprints! + + keybindingsIntroduction: + title: Useful keybindings + desc: >- + This game has a lot of keybindings which make it easier to build big factories. + Here are a few, but be sure to check out the keybindings!

+ CTRL + Drag: Select an area.
+ SHIFT: Hold to place multiple of one building.
+ ALT: Invert orientation of placed belts.
+ + createMarker: + title: New Marker + desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker + + markerDemoLimit: + desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! + + exportScreenshotWarning: + title: Export screenshot + desc: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game! + +ingame: + # This is shown in the top left corner and displays useful keybindings in + # every situation + keybindingsOverlay: + moveMap: Move + selectBuildings: Select area + stopPlacement: Stop placement + rotateBuilding: Rotate building + placeMultiple: Place multiple + reverseOrientation: Reverse orientation + disableAutoOrientation: Disable auto-orientation + toggleHud: Toggle HUD + placeBuilding: Place building + createMarker: Create marker + delete: Delete + pasteLastBlueprint: Paste last blueprint + lockBeltDirection: Enable belt planner + plannerSwitchSide: Flip planner side + cutSelection: Cut + copySelection: Copy + clearSelection: Clear selection + pipette: Pipette + switchLayers: Switch layers + + # Names of the colors, used for the color blind mode + colors: + red: Red + green: Green + blue: Blue + yellow: Yellow + purple: Purple + cyan: Cyan + white: White + black: Black + uncolored: No color + + # 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: Press to cycle variants. + + # Shows the hotkey in the ui, e.g. "Hotkey: Q" + hotkeyLabel: >- + Hotkey: + + infoTexts: + speed: Speed + range: Range + storage: Storage + oneItemPerSecond: 1 item / second + itemsPerSecond: items / s + itemsPerSecondDouble: (x2) + + tiles: tiles + + # The notification when completing a level + levelCompleteNotification: + # is replaced by the actual level, so this gets 'Level 03' for example. + levelTitle: Level + completed: Completed + unlockText: Unlocked ! + buttonNextLevel: Next Level + + # Notifications on the lower right + notifications: + newUpgrade: A new upgrade is available! + gameSaved: Your game has been saved. + + # The "Upgrades" window + shop: + title: Upgrades + buttonUnlock: Upgrade + + # Gets replaced to e.g. "Tier IX" + tier: Tier + + # The roman number for each tier + tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X] + + maximumLevel: MAXIMUM LEVEL (Speed x) + + # The "Statistics" window + statistics: + title: Statistics + dataSources: + stored: + title: Stored + description: Displaying amount of stored shapes in your central building. + produced: + title: Produced + description: Displaying all shapes your whole factory produces, including intermediate products. + delivered: + title: Delivered + description: Displaying shapes which are delivered to your central building. + noShapesProduced: No shapes have been produced so far. + + # Displays the shapes per minute, e.g. '523 / m' + shapesPerMinute: / m + + # Settings menu, when you press "ESC" + settingsMenu: + playtime: Playtime + + buildingsPlaced: Buildings + beltsPlaced: Belts + + buttons: + continue: Continue + settings: Settings + menu: Return to menu + + # Bottom left tutorial hints + tutorialHints: + title: Need help? + showHint: Show hint + hideHint: Close + + # When placing a blueprint + blueprintPlacer: + cost: Cost + + # Map markers + waypoints: + waypoints: Markers + hub: HUB + description: Left-click a marker to jump to it, right-click to delete it.

Press to create a marker from the current view, or right-click to create a marker at the selected location. + creationSuccessNotification: Marker has been created. + + # Shape viewer + shapeViewer: + title: Layers + empty: Empty + copyKey: Copy Key + + # Interactive tutorial + interactiveTutorial: + title: Tutorial + hints: + 1_1_extractor: Place an extractor on top of a circle shape to extract it! + 1_2_conveyor: >- + Connect the extractor with a conveyor belt to your hub!

Tip: Click and drag the belt with your mouse! + + 1_3_expand: >- + This is NOT an idle game! Build more extractors and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them. + +# All shop upgrades +shopUpgrades: + belt: + name: Belts, Distributor & Tunnels + description: Speed x → x + miner: + name: Extraction + description: Speed x → x + processors: + name: Cutting, Rotating & Stacking + description: Speed x → x + painting: + name: Mixing & Painting + description: Speed x → x + +# Buildings and their name / description +buildings: + hub: + deliver: Deliver + toUnlock: to unlock + levelShortcut: LVL + + belt: + default: + name: &belt Conveyor Belt + description: Transports items, hold and drag to place multiple. + + wire: + default: + name: &wire Wire + description: Allows you to transport energy + + miner: # Internal name for the Extractor + default: + name: &miner Extractor + description: Place over a shape or color to extract it. + + chainable: + name: Extractor (Chain) + description: Place over a shape or color to extract it. Can be chained. + + underground_belt: # Internal name for the Tunnel + default: + name: &underground_belt Tunnel + description: Allows you to tunnel resources under buildings and belts. + + tier2: + name: Tunnel Tier II + description: Allows you to tunnel resources under buildings and belts. + + splitter: # Internal name for the Balancer + default: + name: &splitter Balancer + description: Multifunctional - Evenly distributes all inputs onto all outputs. + + compact: + name: Merger (compact) + description: Merges two conveyor belts into one. + + compact-inverse: + name: Merger (compact) + description: Merges two conveyor belts into one. + + cutter: + default: + name: &cutter Cutter + description: Cuts shapes from top to bottom and outputs both halves. If you use only one part, be sure to destroy the other part or it will stall! + quad: + name: Cutter (Quad) + description: Cuts shapes into four parts. If you use only one part, be sure to destroy the other parts or it will stall! + + advanced_processor: + default: + name: &advanced_processor Advanced Processor + description: Advanced shape processing + + rotater: + default: + name: &rotater Rotate + description: Rotates shapes clockwise by 90 degrees. + ccw: + name: Rotate (CCW) + description: Rotates shapes counter-clockwise by 90 degrees. + + stacker: + default: + name: &stacker Stacker + description: Stacks both items. If they can not be merged, the right item is placed above the left item. + + mixer: + default: + name: &mixer Color Mixer + description: Mixes two colors using additive blending. + + painter: + default: + name: &painter Painter + description: &painter_desc Colors the whole shape on the left input with the color from the top input. + + mirrored: + name: *painter + description: *painter_desc + + double: + name: Painter (Double) + description: Colors the shapes on the left inputs with the color from the top input. + quad: + name: Painter (Quad) + description: Allows you to color each quadrant of the shape with a different color. + + trash: + default: + name: &trash Trash + description: Accepts inputs from all sides and destroys them. Forever. + + storage: + name: Storage + description: Stores excess items, up to a given capacity. Can be used as an overflow gate. + + energy_generator: + deliver: Deliver + + # This will be shown before the amount, so for example 'For 123 Energy' + toGenerateEnergy: For + + default: + name: &energy_generator Energy Generator + description: Generates energy by consuming shapes. Each energy generator requires a different shape. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. + +storyRewards: + # Those are the rewards gained from completing the store + reward_cutter_and_trash: + title: Cutting Shapes + desc: You just unlocked the cutter - it cuts shapes half from top to bottom regardless of its orientation!

Be sure to get rid of the waste, or otherwise it will stall - For this purpose I gave you a trash, which destroys everything you put into it! + + reward_rotater: + title: Rotating + desc: The rotater has been unlocked! It rotates shapes clockwise by 90 degrees. + + reward_painter: + title: Painting + desc: >- + The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a colorblind mode in the settings! + + reward_mixer: + title: Color Mixing + desc: The mixer has been unlocked - Combine two colors using additive blending with this building! + + reward_stacker: + title: Combiner + desc: You can now combine shapes with the combiner! Both inputs are combined, and if they can be put next to each other, they will be fused. If not, the right input is stacked on top of the left input! + + reward_splitter: + title: Splitter/Merger + desc: The multifunctional balancer has been unlocked - It can be used to build bigger factories by splitting and merging items onto multiple belts!

+ + reward_tunnel: + title: Tunnel + desc: The tunnel has been unlocked - You can now tunnel items through belts and buildings with it! + + reward_rotater_ccw: + title: CCW Rotating + desc: You have unlocked a variant of the rotater - It allows you to rotate shapes counter-clockwise! To build it, select the rotater and press 'T' to cycle through its variants! + + reward_miner_chainable: + title: Chaining Extractor + desc: You have unlocked the chaining extractor! It can forward its resources to other extractors so you can more efficiently extract resources! + + reward_underground_belt_tier_2: + title: Tunnel Tier II + desc: You have unlocked a new variant of the tunnel - It has a bigger range, and you can also mix-n-match those tunnels now! + + reward_splitter_compact: + title: Compact Balancer + desc: >- + You have unlocked a compact variant of the balancer - It accepts two inputs and merges them into one belt! + + reward_cutter_quad: + title: Quad Cutting + desc: You have unlocked a variant of the cutter - It allows you to cut shapes in four parts instead of just two! + + reward_painter_double: + title: Double Painting + desc: You have unlocked a variant of the painter - It works as the regular painter but processes two shapes at once consuming just one color instead of two! + + reward_painter_quad: + title: Quad Painting + desc: You have unlocked a variant of the painter - It allows you to paint each part of the shape individually! + + reward_storage: + title: Storage Buffer + desc: You have unlocked a variant of the trash - It allows you to store items up to a given capacity! + + reward_freeplay: + title: Freeplay + desc: You did it! You unlocked the free-play mode! This means that shapes are now randomly generated! (No worries, more content is planned for the standalone!) + + reward_blueprints: + title: Blueprints + desc: You can now copy and paste parts of your factory! Select an area (Hold CTRL, then drag with your mouse), and press 'C' to copy it.

Pasting it is not free, you need to produce blueprint shapes to afford it! (Those you just delivered). + + # Special reward, which is shown when there is no reward actually + no_reward: + title: Next level + desc: >- + This level gave you no reward, but the next one will!

PS: Better don't destroy your existing factory - You need all those shapes later again to unlock upgrades! + + no_reward_freeplay: + title: Next level + desc: >- + Congratulations! By the way, more content is planned for the standalone! + +settings: + title: Settings + categories: + game: Game + app: Application + + versionBadges: + dev: Development + staging: Staging + prod: Production + buildDate: Built + + labels: + uiScale: + title: Interface scale + description: >- + Changes the size of the user interface. The interface will still scale based on your device's resolution, but this setting controls the amount of scaling. + scales: + super_small: Super small + small: Small + regular: Regular + large: Large + huge: Huge + + autosaveInterval: + title: Autosave Interval + description: >- + Controls how often the game saves automatically. You can also disable it entirely here. + + intervals: + one_minute: 1 Minute + two_minutes: 2 Minutes + five_minutes: 5 Minutes + ten_minutes: 10 Minutes + twenty_minutes: 20 Minutes + disabled: Disabled + + scrollWheelSensitivity: + title: Zoom sensitivity + description: >- + Changes how sensitive the zoom is (Either mouse wheel or trackpad). + sensitivity: + super_slow: Super slow + slow: Slow + regular: Regular + fast: Fast + super_fast: Super fast + + movementSpeed: + title: Movement speed + description: >- + Changes how fast the view moves when using the keyboard. + speeds: + super_slow: Super slow + slow: Slow + regular: Regular + fast: Fast + super_fast: Super Fast + extremely_fast: Extremely Fast + + language: + title: Language + description: >- + Change the language. All translations are user-contributed and might be incomplete! + + enableColorBlindHelper: + title: Color Blind Mode + description: >- + Enables various tools which allow you to play the game if you are color blind. + + fullscreen: + title: Fullscreen + description: >- + It is recommended to play the game in fullscreen to get the best experience. Only available in the standalone. + + soundsMuted: + title: Mute Sounds + description: >- + If enabled, mutes all sound effects. + + musicMuted: + title: Mute Music + description: >- + If enabled, mutes all music. + + theme: + title: Game theme + description: >- + Choose the game theme (light / dark). + themes: + dark: Dark + light: Light + + refreshRate: + title: Simulation Target + description: >- + If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates. This might actually decrease the FPS if your computer is too slow. + + alwaysMultiplace: + title: Multiplace + description: >- + If enabled, all buildings will stay selected after placement until you cancel it. This is equivalent to holding SHIFT permanently. + + offerHints: + title: Hints & Tutorials + description: >- + Whether to offer hints and tutorials while playing. Also hides certain UI elements up to a given level to make it easier to get into the game. + + enableTunnelSmartplace: + title: Smart Tunnels + description: >- + When enabled, placing tunnels will automatically remove unnecessary belts. This also enables you to drag tunnels and excess tunnels will get removed. + + vignette: + title: Vignette + description: >- + Enables the vignette, which darkens the screen corners and makes text easier to read. + + rotationByBuilding: + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. This may be more comfortable if you frequently switch between placing different building types. + + compactBuildingInfo: + title: Compact Building Infos + description: >- + Shortens info boxes for buildings by only showing their ratios. Otherwise a description and image is shown. + + disableCutDeleteWarnings: + title: Disable Cut/Delete Warnings + description: >- + Disables the warning dialogs brought up when cutting/deleting more than 100 entities. + +keybindings: + title: Keybindings + hint: >- + Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different placement options. + + resetKeybindings: Reset Keybindings + + categoryLabels: + general: Application + ingame: Game + navigation: Navigating + placement: Placement + massSelect: Mass Select + buildings: Building Shortcuts + placementModifiers: Placement Modifiers + + mappings: + confirm: Confirm + back: Back + mapMoveUp: Move Up + mapMoveRight: Move Right + mapMoveDown: Move Down + mapMoveLeft: Move Left + mapMoveFaster: Move Faster + centerMap: Center Map + + mapZoomIn: Zoom in + mapZoomOut: Zoom out + createMarker: Create Marker + + menuOpenShop: Upgrades + menuOpenStats: Statistics + menuClose: Close Menu + + toggleHud: Toggle HUD + toggleFPSInfo: Toggle FPS and Debug Info + switchLayers: Switch layers + exportScreenshot: Export whole Base as Image + belt: *belt + splitter: *splitter + underground_belt: *underground_belt + miner: *miner + cutter: *cutter + advanced_processor: *advanced_processor + rotater: *rotater + stacker: *stacker + mixer: *mixer + energy_generator: *energy_generator + painter: *painter + trash: *trash + wire: *wire + + pipette: Pipette + rotateWhilePlacing: Rotate + rotateInverseModifier: >- + Modifier: Rotate CCW instead + cycleBuildingVariants: Cycle Variants + confirmMassDelete: Delete area + pasteLastBlueprint: Paste last blueprint + cycleBuildings: Cycle Buildings + lockBeltDirection: Enable belt planner + switchDirectionLockSide: >- + Planner: Switch side + + massSelectStart: Hold and drag to start + massSelectSelectMultiple: Select multiple areas + massSelectCopy: Copy area + massSelectCut: Cut area + + placementDisableAutoOrientation: Disable automatic orientation + placeMultiple: Stay in placement mode + placeInverse: Invert automatic belt orientation + +about: + title: About this Game + body: >- + This game is open source and developed by Tobias Springer (this is me).

+ + If you want to contribute, check out shapez.io on github.

+ + This game wouldn't have been possible without the great discord community around my games - You should really join the discord server!

+ + The soundtrack was made by Peppsen - He's awesome.

+ + Finally, huge thanks to my best friend Niklas - Without our factorio sessions, this game would never have existed. + +changelog: + title: Changelog + +demo: + features: + restoringGames: Restoring savegames + importingGames: Importing savegames + oneGameLimit: Limited to one savegame + customizeKeybindings: Customizing Keybindings + exportingBase: Exporting whole Base as Image + + settingNotAvailable: Not available in the demo. diff --git a/translations/base-sv.yaml b/translations/base-sv.yaml index 2aebe2ff..69d6a1a0 100644 --- a/translations/base-sv.yaml +++ b/translations/base-sv.yaml @@ -30,42 +30,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io är ett spel som går ut på att automatisera skapandet av former. Leverera de efterfrågade, alltmer komplexa formerna för att utvecklas genom spelet och skaffa uppgraderingar för att öka hastigheten i fabriken. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Eftersom efterfrågan ökar behöver du bygga ut fabriken för att möta behoven - Glöm bara inte bort resurserna, du kommer behöva expadera fabriken över den [b]oändligt stora världen[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Eftersom former kan bli tråkiga kommer du behöva blanda färger och måla dina former med dem - Kombinera röd, grön, och blå för att producera olika färger och måla former med dem för att tillfredställa efterfrågan. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - Detta spel innehåller just nu 18 nivåer (Vilket borde hålla dig upptagen i några timmar!) men jag lägger konstant till fler saker - Det finns mycket planerat! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]Fristående Fördelar[/b] + [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Oändligt antal sparfiler - [*] Mörkt tema - [*] Fler inställningar - [*] Tillåter mig att vidare utveckla shapez.io ❤️ - [*] Fler funktioner i framtiden! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planerade tillägg & Gruppförslag[/b] + [b]Future Updates[/b] - Detta spel är open source - Vem som helst kan hjälpa! Förutom det lyssnar jag [b]ofta[/b] på min community! Jag försöker läsa alla förslag och ta till mig så mycket feedback som möjligt. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story mode däri byggnader kostar former - [*] Fler nivåer & och byggnader (exklusivt för den fristående versionen) - [*] Olika världar, och kanske världshinder - [*] Konfigurerbar världskapande (Ändra antal och storlek på resursfläckar, seed, med mera) - [*] Fler sorters former - [*] Fler prestandaförbättringar (Även om spelet redan spelar ganska väl!) - [*] Färgblint läge - [*] Och mycket mer! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - Se till att kolla min trello för en full framtidskarta! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: Laddar @@ -74,6 +91,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "." + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "," + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: k @@ -131,28 +151,7 @@ mainMenu: savegameLevel: Nivå savegameLevelUnknown: Okänd Nivå - contests: - contest_01_03062020: - title: "Tävling #01" - desc: Vinn $25 för den coolaste fabriken! - longDesc: >- - För att ge något åter till dig, tänkte jag att det skulle vara coolt att skapa veckovisa tävlingar! -

- Denna veckas tema: Bygg den coolaste fabriken! -

- Så här går det till:
-
    -
  • Skicka in en skärmdump av din fabrik till contest@shapez.io
  • -
  • Bonuspoäng om du delar den på sociala medier!
  • -
  • Jag kommer välja 5 skärmdumpar och framföra dem tilldiscordgruppen och låta dem rösta.
  • -
  • Vinnaren får $25 (Paypal, Amazon Gift Card, Vilket du än föredrar)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- Jag ser fram emot att se era grymma skapelser! - showInfo: Se - contestOver: Tävlingen är avslutad - Gå med i discordservern för att bli notifierad kring nya tävlingar! continue: Fortsätt newGame: Nytt spel madeBy: Skapad av @@ -203,23 +202,23 @@ dialogs: Du behöver starta om spelet för att applicera inställningar. editKeybinding: - title: Ändra tangentbindningar + title: Ändra snabbtangenter desc: Tryck ned tangenten eller musknappen du vill tillsätta, eller escape för att avbryta. resetKeybindingsConfirmation: - title: Återställ tangentbindningar + title: Återställ snabbtangenter desc: Detta kommer att återställa alla tangentbindningar till deras standardtangenter. Var snäll och bekräfta. keybindingsResetOk: - title: Återställning av tangentbindningar - desc: Tangentbindningar har återställts! + title: Återställning av snabbtangenter + desc: Snabbtangenterna har återställts! featureRestriction: title: Demoversion - desc: Du försökte nå en funktion () som inte är tillgänglig i demversionen. Överväg att skaffa den fristående versionen för den fulla upplevelsen! + desc: Du försökte nå en funktion () som inte är tillgänglig i demoversionen. Överväg att skaffa den fristående versionen för den fulla upplevelsen! oneSavegameLimit: - title: Limiterad mängd sparfiler + title: Begränsad mängd sparfiler desc: Du kan bara ha en sparfil åt gången i demoversionen. Var snäll och ta bort det existerande eller skaffa den fristående versionen! updateSummary: @@ -231,7 +230,7 @@ dialogs: title: Lås upp Uppgraderingar desc: >- Alla former du producerar kan användas för att låsa upp uppgraderingar - Förstör inte dina gamla fabriker! - Uppgraderingsmenyn kan finnas i det övre högra hörnet på skärmen. + Uppgraderingsmenyn finns i det övre högra hörnet på skärmen. massDeleteConfirm: title: Bekräfta borttagning @@ -239,7 +238,7 @@ dialogs: Du tar nu bort ganska många byggnader ( för att vara exakt)! Är du säker på att du vill göra detta? blueprintsNotUnlocked: - title: Inte än upplåst + title: Inte upplåst än desc: >- Ritningar är inte än upplåsta! Klara fler nivåer för att låsa upp dem. @@ -255,6 +254,7 @@ dialogs: createMarker: title: Ny Markör desc: Ge den ett meningsfullt namn, du kan också inkludera en kort kod av en form (Vilket du kan generera här ) + titleEdit: Edit Marker markerDemoLimit: desc: Du kan endast skapa två markörer i demoversionen. Skaffa den fristående versionen för ett oändligt antal! @@ -268,7 +268,11 @@ dialogs: title: Exportera skärmdump desc: >- Du efterfrågade att exportera din fabrik som en skärmdump. - Var snäll och notera att detta kan ta ett tag för en stor bas och i vissa fall till och med krascha ditt spel + Vänligen notera att detta kan ta ett tag för en stor bas och i vissa fall till och med krascha ditt spel + + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? ingame: # This is shown in the top left corner and displays useful keybindings in @@ -286,19 +290,20 @@ ingame: createMarker: Skapa Markör delete: Förstör pasteLastBlueprint: Klistra in ritning - lockBeltDirection: Sätt på rullbandsplannerare + lockBeltDirection: Aktivera rullbandsplanerare plannerSwitchSide: Vänd planerarsidan cutSelection: Klipp copySelection: Kopiera clearSelection: Rensa vald pipette: Pipett + switchLayers: Switch layers # 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: Tryck ned För att cykla igenom varianter. + cycleBuildingVariants: Tryck ned För att bläddra igenom varianter. # Shows the hotkey in the ui, e.g. "Hotkey: Q" hotkeyLabel: >- @@ -393,10 +398,10 @@ ingame: hints: 1_1_extractor: Placera en extraktor över en cirkel för att extrahera den! 1_2_conveyor: >- - Koppla extraktorn med ettrullband till din hub!

Tips: Clicka och dra rullbandet med musen! + Koppla extraktorn med ettrullband till din hub!

Tips: Klicka och dra rullbandet med musen! 1_3_expand: >- - Detta är INTE ett idle-spel! Bygg fler extraktörer för att klara målet snabbare.

Tips: Håll SHIFT för att placera flera extraktörer, och använd R för att rotera dem. + Detta är INTE ett idle-spel! Bygg fler extraktörer för att klara målet snabbare.

Tips: Håll SKIFT för att placera flera extraktörer, och använd R för att rotera dem. colors: red: Röd @@ -407,9 +412,11 @@ ingame: cyan: Turkos white: Vit uncolored: Ofärgad + black: Black shapeViewer: title: Lager empty: Tom + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -420,7 +427,7 @@ shopUpgrades: name: Extraktion description: Hastighet x → x processors: - name: Klippning, Rotationg & Stapling + name: Klippning, Rotering & Stapling description: Hastighet x → x painting: name: Blandning & Färgning @@ -431,7 +438,7 @@ buildings: belt: default: name: &belt Rullband - description: Transporterar obejekt, håll in och dra för att placera flera. + description: Transporterar objekt, håll in och dra för att placera flera. miner: # Internal name for the Extractor default: @@ -467,10 +474,10 @@ buildings: cutter: default: name: &cutter Klippare - description: Klipper former från topp till botten och outputtar båda halver.Om du bara använder en halva, se till att förstöra den andra, annars kommer den uppehålla fabrkien! + description: Klipper former från topp till botten och outputtar båda halvor.Om du endast använder en halva, se till att förstöra den andra, annars kommer den blockera maskinen! quad: name: Klippare (Quad) - description: Klipper former i fyra delar. Om du bara använder en del, se till att förstöra de andra, annars kommer de uppehålla fabrkien! + description: Klipper former i fyra delar. Om du endast använder en del, se till att förstöra de andra, annars kommer de blockera maskinen! rotater: default: @@ -483,7 +490,7 @@ buildings: stacker: default: name: &stacker Staplare - description: Staplar båda obejekt. Om de inte kan slås ihop, placeras det högra obejektet över det vänstra. + description: Staplar båda objekt. Om de inte kan slås ihop, placeras det högra objektet över det vänstra. mixer: default: @@ -516,6 +523,27 @@ buildings: deliver: Leverera toUnlock: Att låsa upp levelShortcut: LVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -530,7 +558,7 @@ storyRewards: reward_painter: title: Måleri desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a color blind mode in the settings! + Målaren har låsts upp - Extrahera färger (precis som du gör med formerna) och kombinera med en form i målaren för att måla formen!

PS: Om du är färgblind finns det ett färblint läge bland inställningarna! reward_mixer: title: Färgblandning @@ -542,7 +570,7 @@ storyRewards: reward_splitter: title: Delning/Sammanslagning - desc: Den multifunktiionella balanseraren har blivit upplåst - Den kan användas för att bygga större fabriker genom att dela eller slå ihop objekt till flera rullband!

+ desc: Den multifunktionella balanseraren har blivit upplåst - Den kan användas för att bygga större fabriker genom att dela eller slå ihop objekt till flera rullband!

reward_tunnel: title: Tunnel @@ -550,7 +578,7 @@ storyRewards: reward_rotater_ccw: title: Motsols rotation - desc: Du har låst upp en variant av roteraren - Den låter dig rotera saker motsols! För att bygga den, välj roteraren och tryck ned 'T' för att cykla genom dess varianter! + desc: Du har låst upp en variant av roteraren - Den låter dig rotera saker motsols! För att bygga den, välj roteraren och tryck ned 'T' för att bläddra genom dess varianter! reward_miner_chainable: title: Kedjeextraktor @@ -575,11 +603,11 @@ storyRewards: reward_painter_quad: title: Quad Färgläggning - desc: Du har låst upp en ny variant av Färgläggaren - Den tillåter dig att färglägga varje del av en form individuellt! + desc: Du har låst upp en ny variant av Färgläggaren - Den låter dig färglägga varje del av en form individuellt! reward_storage: title: Förvaringsbuffert - desc: Du har låst upp en ny variant av skräphantering - Den tillåter dig att förvara objekt upp till en viss kapacitet! + desc: Du har låst upp en ny variant av skräphantering - Den låter dig förvara objekt upp till en viss kapacitet! reward_freeplay: title: Friläge @@ -593,12 +621,12 @@ storyRewards: no_reward: title: Nästa nivå desc: >- - Denna nivå har ingen belöning, men nästa kommer!

PS: Se till att inte förstöra din redan existerande fabrik - Du behöver alla de där formerna igen för att låsa upp uppgraderingar! + Denna nivå har ingen belöning, men nästa har!

PS: Se till att inte förstöra din redan existerande fabrik - Du behöver alla de där formerna igen för att låsa upp uppgraderingar! no_reward_freeplay: title: Nästa nivå desc: >- - Grattis! Föresten, mer spelinnehåll är planerat för den fristående versionen! + Grattis! Förresten, mer spelinnehåll är planerat för den fristående versionen! settings: title: Inställningar @@ -643,7 +671,7 @@ settings: fullscreen: title: Fullskärm description: >- - Det är rekommenderat att spela i fullskärm för bästa upplevelse. Endast tillgänglig i den fristående versionen. + Det är rekommenderat att spela i fullskärm för bästa upplevelse. Endast tillgängligt i den fristående versionen. soundsMuted: title: Dämpa Ljud @@ -727,18 +755,17 @@ settings: title: Färgblint läge description: Aktiverar olika verktyg som låter dig spela spelet om du är färbling. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotering per byggnadstyp + description: >- + Varje byggnadstyp kommer ihåg rotationen du senast var på individuellt. + Detta kan vara mer bekvämt om du ofta bytar byggnader som du placerar. keybindings: - title: Tangentbindningar + title: Snabbtangenter hint: >- Tips: Se till att använda CTRL, SKIFT, och ALT! De låter dig använda olika placeringslägen. - resetKeybindings: Återställ Tangentbindningar + resetKeybindings: Återställ Snabbtangenter categoryLabels: general: Applikation @@ -799,6 +826,11 @@ keybindings: lockBeltDirection: Sätt på rullbandsplanerare switchDirectionLockSide: "Planerare: Byt sida" pipette: Pipett + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: Om detta spel @@ -828,7 +860,7 @@ demo: restoringGames: Återställer sparfiler importingGames: Importerar sparfiler oneGameLimit: Limiterad till endast en sparfil - customizeKeybindings: Finjustera tangentbindningar + customizeKeybindings: Finjustera snabbtangenter exportingBase: Exportera hela fabriken som en bild settingNotAvailable: Inte tillgänglig i demoversionen. diff --git a/translations/base-tr.yaml b/translations/base-tr.yaml index 8084ee4a..ea7e3eda 100644 --- a/translations/base-tr.yaml +++ b/translations/base-tr.yaml @@ -30,77 +30,97 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io is a game about building factories to automate the creation and combination of shapes. Deliver the requested, increasingly complex shapes to progress within the game and unlock upgrades to speed up your factory. + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - Since the demand raises you will have to scale up your factory to fit the needs - Don't forget about resources though, you will have to expand in the [b]infinite map[/b]! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - Since shapes can get boring soon you need to mix colors and paint your shapes with it - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - This game features 18 levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. [b]Standalone Advantages[/b] [list] - [*] Waypoints - [*] Unlimited Savegames [*] Dark Mode - [*] More settings - [*] Allow me to further develop shapez.io ❤️ - [*] More features in the future! + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] - [b]Planned features & Community suggestions[/b] + [b]Future Updates[/b] - This game is open source - Anybody can contribute! Besides of that, I listen [b]a lot[/b] to the community! I try to read all suggestions and take as much feedback into account as possible. + I am updating the game very often and trying to push an update at least every week! [list] - [*] Story mode where buildings cost shapes - [*] More levels & buildings (standalone exclusive) - [*] Different maps, and maybe map obstacles - [*] Configurable map creation (Edit number and size of patches, seed, and more) - [*] More types of shapes - [*] More performance improvements (Although the game already runs pretty good!) - [*] Color blind mode + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) [*] And much more! [/list] - Be sure to check out my trello board for the full roadmap! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: - loading: Loading - error: Error + loading: yükleniyor + error: Hata # How big numbers are rendered, e.g. "10,000" thousandsDivider: "," + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: - thousands: k + thousands: b millions: M billions: B trillions: T # Shown for infinitely big numbers - infinite: inf + infinite: sonsuz time: # Used for formatting past time dates - oneSecondAgo: one second ago - xSecondsAgo: seconds ago - oneMinuteAgo: one minute ago - xMinutesAgo: minutes ago - oneHourAgo: one hour ago - xHoursAgo: hours ago - oneDayAgo: one day ago - xDaysAgo: days ago + oneSecondAgo: bir saniye önce + xSecondsAgo: saniye önce + oneMinuteAgo: bir dakika önce + xMinutesAgo: dakika önce + oneHourAgo: bir saat önce + xHoursAgo: saat önce + oneDayAgo: bir gün önce + xDaysAgo: gün önce # Short formats for times, e.g. '5h 23m' secondsShort: s - minutesAndSecondsShort: m s - hoursAndMinutesShort: h m + minutesAndSecondsShort: d s + hoursAndMinutesShort: S m - xMinutes: minutes + xMinutes: dakika keys: tab: TAB @@ -117,57 +137,36 @@ demoBanners: Get the standalone to unlock all features! mainMenu: - play: Play + play: Oyna changelog: Changelog - importSavegame: Import - openSourceHint: This game is open source! - discordLink: Official Discord Server - helpTranslate: Help translate! + importSavegame: Yükle + openSourceHint: Bu oyun açık kaynak kodlu! + discordLink: Resmi Discord Sunucusu + helpTranslate: Çeviriye yardım et! # This is shown when using firefox and other browsers which are not supported. browserWarning: >- Sorry, but the game is known to run slow on your browser! Get the standalone version or download chrome for the full experience. - savegameLevel: Level - savegameLevelUnknown: Unknown Level + savegameLevel: Seviye + savegameLevelUnknown: Bilinmeyen seviye - contests: - contest_01_03062020: - title: "Contest #01" - desc: Win $25 for the coolest base! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- 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! - continue: Continue - newGame: New Game + continue: Devam et + newGame: Yeni Oyun madeBy: Made by subreddit: Reddit dialogs: buttons: ok: OK - delete: Delete - cancel: Cancel - later: Later - restart: Restart - reset: Reset - getStandalone: Get Standalone - deleteGame: I know what I do + delete: Sil + cancel: İptal + later: Sonra + restart: Yeniden başla + reset: Sıfırla + getStandalone: Tam versiyona eriş + deleteGame: Ne yaptığımi biliyorum viewUpdate: View Update showUpgrades: Show Upgrades showKeybindings: Show Keybindings @@ -180,7 +179,7 @@ dialogs: importSavegameSuccess: title: Savegame Imported text: >- - Your savegame has been successfully imported. + Kayıtlı oyun başarıyla yüklendi. gameLoadFailure: title: Game is broken @@ -190,7 +189,7 @@ dialogs: confirmSavegameDelete: title: Confirm deletion text: >- - Are you sure you want to delete the game? + Oyunu silmek istediğinizden emin misiniz? savegameDeletionError: title: Failed to delete @@ -255,6 +254,7 @@ dialogs: createMarker: title: New Marker desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker markerDemoLimit: desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! @@ -270,6 +270,10 @@ dialogs: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -292,6 +296,7 @@ ingame: copySelection: Copy clearSelection: Clear Selection pipette: Pipette + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -360,9 +365,9 @@ ingame: # Settings menu, when you press "ESC" settingsMenu: - playtime: Playtime + playtime: Oynama zamani - buildingsPlaced: Buildings + buildingsPlaced: Yapılar beltsPlaced: Belts buttons: @@ -399,17 +404,19 @@ ingame: This is NOT an idle game! Build more extractors and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them. colors: - red: Red - green: Green - blue: Blue - yellow: Yellow - purple: Purple + red: Kırmızı + green: Yesil + blue: Mavi + yellow: Sarı + purple: Mor cyan: Cyan - white: White - uncolored: No color + white: Beyaz + uncolored: Renksiz + black: Black shapeViewer: title: Layers - empty: Empty + empty: Bos + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -517,6 +524,27 @@ buildings: storage: name: Storage description: Stores excess items, up to a given capacity. Can be used as an overflow gate. + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -728,11 +756,11 @@ settings: title: Color Blind Mode description: Enables various tools which allow to play the game if you are color blind. rotationByBuilding: - title: Rotation by building type - description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. + This may be more comfortable if you frequently switch between placing + different building types. keybindings: title: Keybindings @@ -800,6 +828,11 @@ keybindings: lockBeltDirection: Enable belt planner switchDirectionLockSide: "Planner: Switch side" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: About this Game diff --git a/translations/base-uk.yaml b/translations/base-uk.yaml new file mode 100644 index 00000000..9d02bc0c --- /dev/null +++ b/translations/base-uk.yaml @@ -0,0 +1,877 @@ +# +# 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: `. They are encapsulated within angle brackets. The correct +# translation for this one in German for example would be: `Taste: ` (notice +# how the placeholder stayed '' 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. +# + +steamPage: + # This is the short text appearing on the steam page + shortText: shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + + # This is the text shown above the discord link + discordLink: Official Discord - Chat with me! + + # This is the long description for the steam page - It is contained here so you can help to translate it, and I will regulary update the store page. + # NOTICE: + # - Do not translate the first line (This is the gif image at the start of the store) + # - Please keep the markup (Stuff like [b], [list] etc) in the same format + longText: >- + [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] + + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. + + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! + + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. + + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. + + [img]{STEAM_APP_IMAGE}/extras/header_standalone_advantages.png[/img] + + [list] + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ + [/list] + + [img]{STEAM_APP_IMAGE}/extras/header_future_updates.png[/img] + + I am updating the game very often and trying to push an update at least every week! + + [list] + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! + [/list] + + [img]{STEAM_APP_IMAGE}/extras/header_open_source.png[/img] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [img]{STEAM_APP_IMAGE}/extras/header_links.png[/img] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + +global: + loading: Loading + error: Error + + # How big numbers are rendered, e.g. "10,000" + thousandsDivider: "," + + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + + # 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: one second ago + xSecondsAgo: seconds ago + oneMinuteAgo: one minute ago + xMinutesAgo: minutes ago + oneHourAgo: one hour ago + xHoursAgo: hours ago + oneDayAgo: one day ago + xDaysAgo: days ago + + # Short formats for times, e.g. '5h 23m' + secondsShort: s + minutesAndSecondsShort: m s + hoursAndMinutesShort: h m + + xMinutes: minutes + + keys: + tab: TAB + control: CTRL + alt: ALT + escape: ESC + shift: SHIFT + space: SPACE + +demoBanners: + # This is the "advertisement" shown in the main menu and other various places + title: Demo Version + intro: >- + Get the standalone to unlock all features! + +mainMenu: + play: Play + continue: Continue + newGame: New Game + changelog: Changelog + subreddit: Reddit + importSavegame: Import + openSourceHint: This game is open source! + discordLink: Official Discord Server + helpTranslate: Help translate! + madeBy: Made by + + # This is shown when using firefox and other browsers which are not supported. + browserWarning: >- + Sorry, but the game is known to run slow on your browser! Get the standalone version or download chrome for the full experience. + + savegameLevel: Level + savegameLevelUnknown: Unknown Level + + + +dialogs: + buttons: + ok: OK + delete: Delete + cancel: Cancel + later: Later + restart: Restart + reset: Reset + getStandalone: Get Standalone + deleteGame: I know what I am doing + viewUpdate: View Update + showUpgrades: Show Upgrades + showKeybindings: Show Keybindings + + importSavegameError: + title: Import Error + text: >- + Failed to import your savegame: + + importSavegameSuccess: + title: Savegame Imported + text: >- + Your savegame has been successfully imported. + + gameLoadFailure: + title: Game is broken + text: >- + Failed to load your savegame: + + confirmSavegameDelete: + title: Confirm deletion + text: >- + Are you sure you want to delete the game? + + savegameDeletionError: + title: Failed to delete + text: >- + Failed to delete the savegame: + + restartRequired: + title: Restart required + text: >- + You need to restart the game to apply the settings. + + editKeybinding: + title: Change Keybinding + desc: Press the key or mouse button you want to assign, or escape to cancel. + + resetKeybindingsConfirmation: + title: Reset keybindings + desc: This will reset all keybindings to their default values. Please confirm. + + keybindingsResetOk: + title: Keybindings reset + desc: The keybindings have been reset to their respective defaults! + + featureRestriction: + title: Demo Version + desc: You tried to access a feature () which is not available in the demo. Consider getting the standalone version for the full experience! + + oneSavegameLimit: + title: Limited savegames + desc: You can only have one savegame at a time in the demo version. Please remove the existing one or get the standalone version! + + updateSummary: + title: New update! + desc: >- + Here are the changes since you last played: + + upgradesIntroduction: + title: Unlock Upgrades + desc: >- + All shapes you produce can be used to unlock upgrades - Don't destroy your old factories! + The upgrades tab can be found on the top right corner of the screen. + + massDeleteConfirm: + title: Confirm delete + desc: >- + You are deleting a lot of buildings ( to be exact)! Are you sure you want to do this? + + massCutConfirm: + title: Confirm cut + desc: >- + You are cutting a lot of buildings ( to be exact)! Are you sure you want to do this? + + massCutInsufficientConfirm: + title: Confirm cut + desc: >- + You can not afford to paste this area! Are you sure you want to cut it? + + blueprintsNotUnlocked: + title: Not unlocked yet + desc: >- + Complete level 12 to unlock Blueprints! + + keybindingsIntroduction: + title: Useful keybindings + desc: >- + This game has a lot of keybindings which make it easier to build big factories. + Here are a few, but be sure to check out the keybindings!

+ CTRL + Drag: Select an area.
+ SHIFT: Hold to place multiple of one building.
+ ALT: Invert orientation of placed belts.
+ + createMarker: + title: New Marker + desc: Give it a meaningful name, you can also include a short key of a shape (Which you can generate here) + titleEdit: Edit Marker + + markerDemoLimit: + desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! + + exportScreenshotWarning: + title: Export screenshot + desc: You requested to export your base as a screenshot. Please note that this can be quite slow for a big base and even crash your game! + +ingame: + # This is shown in the top left corner and displays useful keybindings in + # every situation + keybindingsOverlay: + moveMap: Move + selectBuildings: Select area + stopPlacement: Stop placement + rotateBuilding: Rotate building + placeMultiple: Place multiple + reverseOrientation: Reverse orientation + disableAutoOrientation: Disable auto-orientation + toggleHud: Toggle HUD + placeBuilding: Place building + createMarker: Create marker + delete: Delete + pasteLastBlueprint: Paste last blueprint + lockBeltDirection: Enable belt planner + plannerSwitchSide: Flip planner side + cutSelection: Cut + copySelection: Copy + clearSelection: Clear selection + pipette: Pipette + switchLayers: Switch layers + + # Names of the colors, used for the color blind mode + colors: + red: Red + green: Green + blue: Blue + yellow: Yellow + purple: Purple + cyan: Cyan + white: White + black: Black + uncolored: No color + + # 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: Press to cycle variants. + + # Shows the hotkey in the ui, e.g. "Hotkey: Q" + hotkeyLabel: >- + Hotkey: + + infoTexts: + speed: Speed + range: Range + storage: Storage + oneItemPerSecond: 1 item / second + itemsPerSecond: items / s + itemsPerSecondDouble: (x2) + + tiles: tiles + + # The notification when completing a level + levelCompleteNotification: + # is replaced by the actual level, so this gets 'Level 03' for example. + levelTitle: Level + completed: Completed + unlockText: Unlocked ! + buttonNextLevel: Next Level + + # Notifications on the lower right + notifications: + newUpgrade: A new upgrade is available! + gameSaved: Your game has been saved. + + # The "Upgrades" window + shop: + title: Upgrades + buttonUnlock: Upgrade + + # Gets replaced to e.g. "Tier IX" + tier: Tier + + # The roman number for each tier + tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X] + + maximumLevel: MAXIMUM LEVEL (Speed x) + + # The "Statistics" window + statistics: + title: Statistics + dataSources: + stored: + title: Stored + description: Displaying amount of stored shapes in your central building. + produced: + title: Produced + description: Displaying all shapes your whole factory produces, including intermediate products. + delivered: + title: Delivered + description: Displaying shapes which are delivered to your central building. + noShapesProduced: No shapes have been produced so far. + + # Displays the shapes per minute, e.g. '523 / m' + shapesPerMinute: / m + + # Settings menu, when you press "ESC" + settingsMenu: + playtime: Playtime + + buildingsPlaced: Buildings + beltsPlaced: Belts + + buttons: + continue: Continue + settings: Settings + menu: Return to menu + + # Bottom left tutorial hints + tutorialHints: + title: Need help? + showHint: Show hint + hideHint: Close + + # When placing a blueprint + blueprintPlacer: + cost: Cost + + # Map markers + waypoints: + waypoints: Markers + hub: HUB + description: Left-click a marker to jump to it, right-click to delete it.

Press to create a marker from the current view, or right-click to create a marker at the selected location. + creationSuccessNotification: Marker has been created. + + # Shape viewer + shapeViewer: + title: Layers + empty: Empty + copyKey: Copy Key + + # Interactive tutorial + interactiveTutorial: + title: Tutorial + hints: + 1_1_extractor: Place an extractor on top of a circle shape to extract it! + 1_2_conveyor: >- + Connect the extractor with a conveyor belt to your hub!

Tip: Click and drag the belt with your mouse! + + 1_3_expand: >- + This is NOT an idle game! Build more extractors and belts to finish the goal quicker.

Tip: Hold SHIFT to place multiple extractors, and use R to rotate them. + +# All shop upgrades +shopUpgrades: + belt: + name: Belts, Distributor & Tunnels + description: Speed x → x + miner: + name: Extraction + description: Speed x → x + processors: + name: Cutting, Rotating & Stacking + description: Speed x → x + painting: + name: Mixing & Painting + description: Speed x → x + +# Buildings and their name / description +buildings: + hub: + deliver: Deliver + toUnlock: to unlock + levelShortcut: LVL + + belt: + default: + name: &belt Conveyor Belt + description: Transports items, hold and drag to place multiple. + + wire: + default: + name: &wire Wire + description: Allows you to transport energy + + miner: # Internal name for the Extractor + default: + name: &miner Extractor + description: Place over a shape or color to extract it. + + chainable: + name: Extractor (Chain) + description: Place over a shape or color to extract it. Can be chained. + + underground_belt: # Internal name for the Tunnel + default: + name: &underground_belt Tunnel + description: Allows you to tunnel resources under buildings and belts. + + tier2: + name: Tunnel Tier II + description: Allows you to tunnel resources under buildings and belts. + + splitter: # Internal name for the Balancer + default: + name: &splitter Balancer + description: Multifunctional - Evenly distributes all inputs onto all outputs. + + compact: + name: Merger (compact) + description: Merges two conveyor belts into one. + + compact-inverse: + name: Merger (compact) + description: Merges two conveyor belts into one. + + cutter: + default: + name: &cutter Cutter + description: Cuts shapes from top to bottom and outputs both halves. If you use only one part, be sure to destroy the other part or it will stall! + quad: + name: Cutter (Quad) + description: Cuts shapes into four parts. If you use only one part, be sure to destroy the other parts or it will stall! + + advanced_processor: + default: + name: &advanced_processor Advanced Processor + description: Advanced shape processing + + rotater: + default: + name: &rotater Rotate + description: Rotates shapes clockwise by 90 degrees. + ccw: + name: Rotate (CCW) + description: Rotates shapes counter-clockwise by 90 degrees. + + stacker: + default: + name: &stacker Stacker + description: Stacks both items. If they can not be merged, the right item is placed above the left item. + + mixer: + default: + name: &mixer Color Mixer + description: Mixes two colors using additive blending. + + painter: + default: + name: &painter Painter + description: &painter_desc Colors the whole shape on the left input with the color from the top input. + + mirrored: + name: *painter + description: *painter_desc + + double: + name: Painter (Double) + description: Colors the shapes on the left inputs with the color from the top input. + quad: + name: Painter (Quad) + description: Allows you to color each quadrant of the shape with a different color. + + trash: + default: + name: &trash Trash + description: Accepts inputs from all sides and destroys them. Forever. + + storage: + name: Storage + description: Stores excess items, up to a given capacity. Can be used as an overflow gate. + + energy_generator: + deliver: Deliver + + # This will be shown before the amount, so for example 'For 123 Energy' + toGenerateEnergy: For + + default: + name: &energy_generator Energy Generator + description: Generates energy by consuming shapes. Each energy generator requires a different shape. + + wire_crossings: + default: + name: &wire_crossings Wire Splitter + description: Splits a wire into two + + merger: + name: Wire Merger + description: Merges two wires into one + +storyRewards: + # Those are the rewards gained from completing the store + reward_cutter_and_trash: + title: Cutting Shapes + desc: You just unlocked the cutter - it cuts shapes half from top to bottom regardless of its orientation!

Be sure to get rid of the waste, or otherwise it will stall - For this purpose I gave you a trash, which destroys everything you put into it! + + reward_rotater: + title: Rotating + desc: The rotater has been unlocked! It rotates shapes clockwise by 90 degrees. + + reward_painter: + title: Painting + desc: >- + The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

PS: If you are colorblind, there is a colorblind mode in the settings! + + reward_mixer: + title: Color Mixing + desc: The mixer has been unlocked - Combine two colors using additive blending with this building! + + reward_stacker: + title: Combiner + desc: You can now combine shapes with the combiner! Both inputs are combined, and if they can be put next to each other, they will be fused. If not, the right input is stacked on top of the left input! + + reward_splitter: + title: Splitter/Merger + desc: The multifunctional balancer has been unlocked - It can be used to build bigger factories by splitting and merging items onto multiple belts!

+ + reward_tunnel: + title: Tunnel + desc: The tunnel has been unlocked - You can now tunnel items through belts and buildings with it! + + reward_rotater_ccw: + title: CCW Rotating + desc: You have unlocked a variant of the rotater - It allows you to rotate shapes counter-clockwise! To build it, select the rotater and press 'T' to cycle through its variants! + + reward_miner_chainable: + title: Chaining Extractor + desc: You have unlocked the chaining extractor! It can forward its resources to other extractors so you can more efficiently extract resources! + + reward_underground_belt_tier_2: + title: Tunnel Tier II + desc: You have unlocked a new variant of the tunnel - It has a bigger range, and you can also mix-n-match those tunnels now! + + reward_splitter_compact: + title: Compact Balancer + desc: >- + You have unlocked a compact variant of the balancer - It accepts two inputs and merges them into one belt! + + reward_cutter_quad: + title: Quad Cutting + desc: You have unlocked a variant of the cutter - It allows you to cut shapes in four parts instead of just two! + + reward_painter_double: + title: Double Painting + desc: You have unlocked a variant of the painter - It works as the regular painter but processes two shapes at once consuming just one color instead of two! + + reward_painter_quad: + title: Quad Painting + desc: You have unlocked a variant of the painter - It allows you to paint each part of the shape individually! + + reward_storage: + title: Storage Buffer + desc: You have unlocked a variant of the trash - It allows you to store items up to a given capacity! + + reward_freeplay: + title: Freeplay + desc: You did it! You unlocked the free-play mode! This means that shapes are now randomly generated! (No worries, more content is planned for the standalone!) + + reward_blueprints: + title: Blueprints + desc: You can now copy and paste parts of your factory! Select an area (Hold CTRL, then drag with your mouse), and press 'C' to copy it.

Pasting it is not free, you need to produce blueprint shapes to afford it! (Those you just delivered). + + # Special reward, which is shown when there is no reward actually + no_reward: + title: Next level + desc: >- + This level gave you no reward, but the next one will!

PS: Better don't destroy your existing factory - You need all those shapes later again to unlock upgrades! + + + + no_reward_freeplay: + title: Next level + desc: >- + Congratulations! By the way, more content is planned for the standalone! + +settings: + title: Settings + categories: + game: Game + app: Application + + versionBadges: + dev: Development + staging: Staging + prod: Production + buildDate: Built + + labels: + uiScale: + title: Interface scale + description: >- + Changes the size of the user interface. The interface will still scale based on your device's resolution, but this setting controls the amount of scaling. + scales: + super_small: Super small + small: Small + regular: Regular + large: Large + huge: Huge + + autosaveInterval: + title: Autosave Interval + description: >- + Controls how often the game saves automatically. You can also disable it entirely here. + + intervals: + one_minute: 1 Minute + two_minutes: 2 Minutes + five_minutes: 5 Minutes + ten_minutes: 10 Minutes + twenty_minutes: 20 Minutes + disabled: Disabled + + scrollWheelSensitivity: + title: Zoom sensitivity + description: >- + Changes how sensitive the zoom is (Either mouse wheel or trackpad). + sensitivity: + super_slow: Super slow + slow: Slow + regular: Regular + fast: Fast + super_fast: Super fast + + movementSpeed: + title: Movement speed + description: >- + Changes how fast the view moves when using the keyboard. + speeds: + super_slow: Super slow + slow: Slow + regular: Regular + fast: Fast + super_fast: Super Fast + extremely_fast: Extremely Fast + + language: + title: Language + description: >- + Change the language. All translations are user-contributed and might be incomplete! + + enableColorBlindHelper: + title: Color Blind Mode + description: >- + Enables various tools which allow you to play the game if you are color blind. + + fullscreen: + title: Fullscreen + description: >- + It is recommended to play the game in fullscreen to get the best experience. Only available in the standalone. + + soundsMuted: + title: Mute Sounds + description: >- + If enabled, mutes all sound effects. + + musicMuted: + title: Mute Music + description: >- + If enabled, mutes all music. + + theme: + title: Game theme + description: >- + Choose the game theme (light / dark). + themes: + dark: Dark + light: Light + + refreshRate: + title: Simulation Target + description: >- + If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates. This might actually decrease the FPS if your computer is too slow. + + alwaysMultiplace: + title: Multiplace + description: >- + If enabled, all buildings will stay selected after placement until you cancel it. This is equivalent to holding SHIFT permanently. + + offerHints: + title: Hints & Tutorials + description: >- + Whether to offer hints and tutorials while playing. Also hides certain UI elements up to a given level to make it easier to get into the game. + + enableTunnelSmartplace: + title: Smart Tunnels + description: >- + When enabled, placing tunnels will automatically remove unnecessary belts. This also enables you to drag tunnels and excess tunnels will get removed. + + vignette: + title: Vignette + description: >- + Enables the vignette, which darkens the screen corners and makes text easier to read. + + rotationByBuilding: + title: Rotation by building type + description: >- + Each building type remembers the rotation you last set it to individually. This may be more comfortable if you frequently switch between placing different building types. + + compactBuildingInfo: + title: Compact Building Infos + description: >- + Shortens info boxes for buildings by only showing their ratios. Otherwise a description and image is shown. + + disableCutDeleteWarnings: + title: Disable Cut/Delete Warnings + description: >- + Disables the warning dialogs brought up when cutting/deleting more than 100 entities. + +keybindings: + title: Keybindings + hint: >- + Tip: Be sure to make use of CTRL, SHIFT and ALT! They enable different placement options. + + resetKeybindings: Reset Keybindings + + categoryLabels: + general: Application + ingame: Game + navigation: Navigating + placement: Placement + massSelect: Mass Select + buildings: Building Shortcuts + placementModifiers: Placement Modifiers + + mappings: + confirm: Confirm + back: Back + mapMoveUp: Move Up + mapMoveRight: Move Right + mapMoveDown: Move Down + mapMoveLeft: Move Left + mapMoveFaster: Move Faster + centerMap: Center Map + + mapZoomIn: Zoom in + mapZoomOut: Zoom out + createMarker: Create Marker + + menuOpenShop: Upgrades + menuOpenStats: Statistics + menuClose: Close Menu + + toggleHud: Toggle HUD + toggleFPSInfo: Toggle FPS and Debug Info + switchLayers: Switch layers + exportScreenshot: Export whole Base as Image + belt: *belt + splitter: *splitter + underground_belt: *underground_belt + miner: *miner + cutter: *cutter + advanced_processor: *advanced_processor + rotater: *rotater + stacker: *stacker + mixer: *mixer + energy_generator: *energy_generator + painter: *painter + trash: *trash + wire: *wire + + pipette: Pipette + rotateWhilePlacing: Rotate + rotateInverseModifier: >- + Modifier: Rotate CCW instead + cycleBuildingVariants: Cycle Variants + confirmMassDelete: Delete area + pasteLastBlueprint: Paste last blueprint + cycleBuildings: Cycle Buildings + lockBeltDirection: Enable belt planner + switchDirectionLockSide: >- + Planner: Switch side + + massSelectStart: Hold and drag to start + massSelectSelectMultiple: Select multiple areas + massSelectCopy: Copy area + massSelectCut: Cut area + + placementDisableAutoOrientation: Disable automatic orientation + placeMultiple: Stay in placement mode + placeInverse: Invert automatic belt orientation + +about: + title: About this Game + body: >- + This game is open source and developed by Tobias Springer (this is me).

+ + If you want to contribute, check out shapez.io on github.

+ + This game wouldn't have been possible without the great discord community around my games - You should really join the discord server!

+ + The soundtrack was made by Peppsen - He's awesome.

+ + Finally, huge thanks to my best friend Niklas - Without our factorio sessions, this game would never have existed. + +changelog: + title: Changelog + +demo: + features: + restoringGames: Restoring savegames + importingGames: Importing savegames + oneGameLimit: Limited to one savegame + customizeKeybindings: Customizing Keybindings + exportingBase: Exporting whole Base as Image + + settingNotAvailable: Not available in the demo. diff --git a/translations/base-zh-CN.yaml b/translations/base-zh-CN.yaml index 1e44992c..e99d1132 100644 --- a/translations/base-zh-CN.yaml +++ b/translations/base-zh-CN.yaml @@ -57,43 +57,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io 是一款在无边际的地图上建造工厂、自动化生产与组合愈加复杂的图形的游戏。提交任务,制造更复杂的流水线,解锁升级来提升您工厂的运作速度。 + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - 你将会需要随着不断上升得需求扩大你的工厂。当然,不要忘记你可以在[b]无尽[/b]的地图上开采资源! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - 只对图形进行加工可能会使你感到无聊。我们为你准备了颜色资源——将红、绿、蓝三种颜色混合,生产更多不同的颜色并粉刷在图形上以满足需求。 + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - 这个游戏目前有18个关卡(这应该已经能让你忙碌几个小时了!),并且正在不断地更新中。很多新关卡已经在开发计划当中! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]独立版优势[/b] + [b]Standalone Advantages[/b] [list] - [*] 地图标记 - [*] 无限存档 - [*] 深色模式 - [*] 更多设置 - [*] 支持作者继续开发shapez.io❤️ - [*] 在以后还有更多特性! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] + [b]Future Updates[/b] - [b]开发计划与社区意见[/b] - - 本游戏已开源,所有人都能参与游戏内容的开发!除此以外,我[b]非常重视[/b]玩家社区的反馈!我会阅读每一条建议并尽量顾及所有建议。 + I am updating the game very often and trying to push an update at least every week! [list] - [*] 要消耗图形来造建筑的的故事模式 - [*] 更多关卡&建筑(单机版独有) - [*] 更多地图,也许会有障碍物 - [*] 可配置的地图生成(矿脉密度与大小、 随机种子以及其他地图设置) - [*] 更多图形 - [*] 更多的性能改进(当然,现在游戏已经非常流畅了!) - [*] 色盲模式 - [*] 以及更多其他的功能! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - 记得查看我的Trello计划板!那里有所有的开发计划!https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: 加载中 @@ -103,6 +119,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: "" + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # TODO: Chinese translation: suffix changes every 10000 in Chinese numbering system. # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: @@ -161,28 +180,7 @@ mainMenu: savegameLevel: 第关 savegameLevelUnknown: 未知关卡 - contests: - contest_01_03062020: - title: "竞赛 #01" - desc: 最6的工厂将能赢得25美元的奖金! - longDesc: >- - To give something back to you, I thought it would be cool to make weekly contests! -

- This weeks topic: Build the coolest base! -

- Here's the deal:
-
    -
  • Submit a screenshot of your base to contest@shapez.io
  • -
  • Bonus points if you share it on social media!
  • -
  • I will choose 5 screenshots and propose it to the discord community to vote.
  • -
  • The winner gets $25 (Paypal, Amazon Gift Card, whatever you prefer)
  • -
  • Deadline: 07.06.2020 12:00 AM CEST
  • -
-
- I'm looking forward to seeing your awesome creations! - showInfo: 详细信息 - contestOver: 本次竞赛已结束。加入官方Discord以收到关于新竞赛的提醒! # contestOver: This contest has ended - Join the discord to get noticed about new contests! continue: 继续游戏 newGame: 新游戏 @@ -288,6 +286,7 @@ dialogs: createMarker: title: 创建地图标记 desc: 给地图标记起一个的名字。你可以在名字中加入一个短代码以加入图形。(你可以在这里生成短代码。) + titleEdit: Edit Marker markerDemoLimit: desc: 在演示版中你只能创建两个地图标记。请获取独立版以创建更多标记。 @@ -301,6 +300,10 @@ dialogs: desc: >- 你将要导出你的工厂的截图。如果你的基地很大,截图过程将会很慢,且有可能导致游戏崩溃! + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? + ingame: # This is shown in the top left corner and displays useful keybindings in # every situation @@ -323,6 +326,7 @@ ingame: copySelection: 复制 clearSelection: 取消选择 pipette: 选取器 + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -440,9 +444,11 @@ ingame: cyan: 青色 white: 白色 uncolored: 无色 + black: Black shapeViewer: title: 层 # TODO: find better translation empty: 空 + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -549,6 +555,27 @@ buildings: deliver: 交付 toUnlock: 来解锁 levelShortcut: LVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store @@ -843,6 +870,11 @@ keybindings: lockBeltDirection: 启用传送带规划 switchDirectionLockSide: "规划器:换边" pipette: 选取器 + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: 关于游戏 diff --git a/translations/base-zh-TW.yaml b/translations/base-zh-TW.yaml index 973312d0..f3437e77 100644 --- a/translations/base-zh-TW.yaml +++ b/translations/base-zh-TW.yaml @@ -26,7 +26,7 @@ # Shape:圖形 # tile:格子 # Keybind:按鍵設置 -# Menu:主界面 +# Menu:主選單 # Center/Hub:基地 # Upgrade:升級 # Efficiency:效率 @@ -57,43 +57,59 @@ steamPage: longText: >- [img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img] - shapez.io 是一款在無邊際的地圖上建造工廠、自動化生產與組合愈加複雜的圖形的遊戲。提交任務,製造更複雜的流水線,解鎖升級來提升您工廠的運作速度。 + shapez.io is a game about building factories to automate the creation and processing of increasingly complex shapes across an infinitely expanding map. + Upon delivering the requested shapes you will progress within the game and unlock upgrades to speed up your factory. - 你將會需要隨著不斷上升得需求擴大你的工廠。當然,不要忘記你可以在[b]無盡[/b]的地圖上開採資源! + As the demand for shapes increases, you will have to scale up your factory to meet the demand - Don't forget about resources though, you will have to expand across the [b]infinite map[/b]! - 只對圖形進行加工可能會使你感到無聊。我們為你準備了顏色資源——將紅、綠、藍三種顏色混合,生產更多不同的顏色並粉刷在圖形上以滿足需求。 + Soon you will have to mix colors and paint your shapes with them - Combine red, green and blue color resources to produce different colors and paint shapes with it to satisfy the demand. - 這個遊戲目前有18個關卡(這應該已經能讓你忙碌幾個小時了!),並且遊戲正在不斷地更新中。很多新關卡已經在開發計劃當中! + This game features 18 progressive levels (Which should keep you busy for hours already!) but I'm constantly adding new content - There is a lot planned! + Purchasing the game gives you access to the standalone version which has additional features and you'll also receive access to newly developed features. - [b]獨立版優勢[/b] + [b]Standalone Advantages[/b] [list] - [*] 地圖標記 - [*] 無限存檔 - [*] 深色模式 - [*] 更多設置 - [*] 支持作者繼續開發shapez.io❤️ - [*] 在以後還有更多特性! + [*] Dark Mode + [*] Unlimited Waypoints + [*] Unlimited Savegames + [*] Additional settings + [*] Coming soon: Wires & Energy! Aiming for (roughly) end of July 2020. + [*] Coming soon: More Levels + [*] Allows me to further develop shapez.io ❤️ [/list] + [b]Future Updates[/b] - [b]開發計劃與社區意見[/b] - - 本遊戲已開源,所有人都能參與遊戲內容的開發!除此以外,我[b]非常重視[/b]玩家社區的反饋!我會閱讀每一條建議並儘量顧及所有建議。 + I am updating the game very often and trying to push an update at least every week! [list] - [*] 要消耗圖形來造建築的的故事模式 - [*] 更多關卡&建築(單機版獨有) - [*] 更多地圖,也許會有障礙物 - [*] 可配置的地圖生成(礦脈密度與大小、 隨機種子以及其他地圖設置) - [*] 更多圖形 - [*] 更多的性能改進(當然,現在遊戲已經非常流暢了!) - [*] 色盲模式 - [*] 以及更多其他的功能! + [*] Different maps and challenges (e.g. maps with obstacles) + [*] Puzzles (Deliver the requested shape with a restricted area / set of buildings) + [*] A story mode where buildings have a cost + [*] Configurable map generator (Configure resource/shape size/density, seed and more) + [*] Additional types of shapes + [*] Performance improvements (The game already runs pretty well!) + [*] And much more! [/list] - 記得查看我的Trello計劃板!那裡有所有的開發計劃! https://trello.com/b/ISQncpJP/shapezio + [b]This game is open source![/b] + + Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible. + Be sure to check out my trello board for the full roadmap! + + [b]Links[/b] + + [list] + [*] [url=https://discord.com/invite/HN7EVzV]Official Discord[/url] + [*] [url=https://trello.com/b/ISQncpJP/shapezio]Roadmap[/url] + [*] [url=https://www.reddit.com/r/shapezio]Subreddit[/url] + [*] [url=https://github.com/tobspr/shapez.io]Source code (GitHub)[/url] + [*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]Help translate[/url] + [/list] + + discordLink: Official Discord - Chat with me! global: loading: 加載中 @@ -102,6 +118,9 @@ global: # How big numbers are rendered, e.g. "10,000" thousandsDivider: " " + # What symbol to use to seperate the integer part from the fractional part of a number, e.g. "0.4" + decimalSeparator: "." + # The suffix for large numbers, e.g. 1.3k, 400.2M, etc. suffix: thousands: 千 @@ -148,8 +167,8 @@ mainMenu: play: 開始遊戲 changelog: 更新日誌 importSavegame: 導入 - openSourceHint: 本游戏已开源頭! - discordLink: 官方Discord服務器 + openSourceHint: 本遊戲已開源! + discordLink: 官方Discord伺服器 helpTranslate: 幫助我們翻譯! # This is shown when using firefox and other browsers which are not supported. @@ -159,28 +178,7 @@ mainMenu: savegameLevel: Level savegameLevelUnknown: 未知關卡 - contests: - contest_01_03062020: - title: "比賽 #01" - desc: 最屌的工廠將能贏得25美元的獎金! - longDesc: >- - 為了回饋您,我認為每週進行比賽也很酷! -

- 本週主題:建立最酷的基地! -

- 這是交易:
-
    -
  • 將您的基地的屏幕截圖提交到 contest@shapez.io -
  • 如果您在社交媒體上分享會有額外獎勵積分! -
  • 我將選擇5張屏幕截圖,並將其提交給 discord 社區進行投票。 -
  • 獲勝者將獲得 $ 25 (貝寶paypal,亞馬遜禮品卡,隨您喜歡) -
  • 截止日期:CEST 07.06.2020 12:00 AM - -
    - 我期待看到您的出色創作! - showInfo: 詳細信息 - contestOver: 本次競賽已結束。加入官方Discord以收到關於新競賽的提醒! continue: 繼續 newGame: 新遊戲 madeBy: 作者: @@ -189,7 +187,7 @@ mainMenu: dialogs: buttons: ok: 確認 - delete: 删除 + delete: 刪除 cancel: 取消 later: 之後 restart: 重啟 @@ -201,19 +199,19 @@ dialogs: showKeybindings: 顯示按鍵設置 importSavegameError: - title: 導入錯誤 + title: 匯入錯誤 text: >- - 未能導入你這存檔: + 存檔匯入失敗: importSavegameSuccess: - title: 導入成功 + title: 匯入成功 text: >- - 存檔被成功導入 + 存檔匯入成功 gameLoadFailure: - title: 存檔被損壞 + title: 存檔損毀 text: >- - 未能導入你這存檔: + 存檔載入失敗: confirmSavegameDelete: title: 確認刪除 @@ -223,12 +221,12 @@ dialogs: savegameDeletionError: title: 刪除錯誤 text: >- - 未能删除你這存档 + 存檔刪除失敗 restartRequired: title: 需要重啟 text: >- - 你需要重啟遊戲以應用變更的設置。 + 你需要重啟遊戲以套用變更的設置。 editKeybinding: title: 更改按鍵設置 @@ -258,8 +256,8 @@ dialogs: upgradesIntroduction: title: 解鎖建築升級 desc: >- -
    你生產過的所有圖形都會被用來升級建築。升級菜單在屏幕右上角。 - 不要銷毀你之前建造的工廠! + 你生產過的所有圖形可以被用來升級建築。不要銷毀你之前建造的工廠! + 升級選單在屏幕右上角。 massDeleteConfirm: title: 確認刪除 @@ -283,18 +281,23 @@ dialogs: createMarker: title: 創建標記 desc: 給地圖標記起一個的名字。你可以在名字中加入一個短代碼以加入圖形。 (你可以在這裡生成短代碼。) + titleEdit: Edit Marker markerDemoLimit: desc: 在演示版中你只能創建兩個地圖標記。請獲取獨立版以創建更多標記。 massCutConfirm: - title: 確認剪割 + title: 確認剪下 desc: >- - 你將要剪割很多建築,準確來說有幢!你確定要這麼做嗎? + 你將要剪下很多建築,準確來說有幢!你確定要這麼做嗎? exportScreenshotWarning: title: 工廠截圖 desc: >- - 你將要導出你的工廠的截圖。如果你的基地很大,截圖過程將會很慢,甚至有可能導致遊戲崩潰! + 你將要匯出你的工廠的截圖。如果你的基地很大,截圖過程將會很慢,甚至有可能導致遊戲當掉! + + massCutInsufficientConfirm: + title: Confirm cut + desc: You can not afford to paste this area! Are you sure you want to cut it? ingame: # This is shown in the top left corner and displays useful keybindings in @@ -314,10 +317,11 @@ ingame: pasteLastBlueprint: 貼上一個藍圖 lockBeltDirection: 啟用傳送帶規劃 plannerSwitchSide: 規劃器換邊 - cutSelection: 剪下選項 - copySelection: 複製選項 - clearSelection: 清空選項 + cutSelection: 剪下選取 + copySelection: 複製選取 + clearSelection: 清空選取 pipette: 吸附 + switchLayers: Switch layers # Everything related to placing buildings (I.e. as soon as you selected a building # from the toolbar) @@ -355,8 +359,8 @@ ingame: # The "Upgrades" window shop: - title: Upgrades - buttonUnlock: Upgrade + title: 建築升級 + buttonUnlock: 升級 # Gets replaced to e.g. "Tier IX" tier: 級 @@ -365,11 +369,11 @@ ingame: # Chinese translation: Chinese characters for each tier tierLabels: [壹, 貳, 叁, 肆, 伍, 陸, 柒, 捌, 玖, 拾] - maximumLevel: 最高级(倍效率) + maximumLevel: 最高級(倍效率) # The "Statistics" window statistics: - title: 統計信息 + title: 統計資訊 dataSources: stored: title: 儲存 @@ -395,7 +399,7 @@ ingame: buttons: continue: 繼續 settings: 設置 - menu: 回到主界面 + menu: 回到主選單 # Bottom left tutorial hints tutorialHints: @@ -420,10 +424,10 @@ ingame: hints: 1_1_extractor: 在圓形礦脈上放一個開採機來獲取圓形! 1_2_conveyor: >- - 用傳送帶將你的開採機連接到基地上!

    提示:用你的鼠標按下並拖動傳送帶! + 用傳送帶將你的開採機連接到基地上!

    提示:用你的游標按下並拖動傳送帶! 1_3_expand: >- - 這不是一個挂機遊戲!建造更多的開採機和傳送帶來更快地完成目標。

    + 這不是一個放置型遊戲!建造更多的開採機和傳送帶來更快地完成目標。

    提示:按住SHIFT鍵來放置多個開採機,用R鍵旋轉它們。 colors: @@ -432,12 +436,14 @@ ingame: blue: 藍 yellow: 黃 purple: 紫 - cyan: 淺藍 + cyan: 青 white: 白 uncolored: 無顏色 + black: Black shapeViewer: title: 層 empty: 空 + copyKey: Copy Key # All shop upgrades shopUpgrades: @@ -495,10 +501,10 @@ buildings: cutter: default: name: &cutter 切割機 - description: 將圖形從上到下切開並輸出。 如果你只需要其中一半,記得把另一半銷毀掉,否則切割機會停止工作! + description: 將圖形從上到下切開並輸出。 如果你只需要其中一半,記得把另一半銷毀掉,否則切割機會停止運作! quad: name: 切割機(四分) - description: 將輸入的圖形切成四塊。 如果你只需要其中一塊,記得把其他的銷毀掉,否則切割機會停止工作! + description: 將輸入的圖形切成四塊。 如果你只需要其中一塊,記得把其他的銷毀掉,否則切割機會停止運作! rotater: default: @@ -511,12 +517,12 @@ buildings: stacker: default: name: &stacker 混合機 - description: 將輸入的圖形拼貼在一起。如果不能被直接拼貼,右邊的圖形會被混合在左邊的圖形上面. + description: 將輸入的圖形拼貼在一起。如果不能被直接拼貼,右邊的圖形會被疊在左邊的圖形上面. mixer: default: name: &mixer 混色機 - description: 將兩個顏色混合在一起。 (加法混合) + description: 將兩個顏色加在一起。 painter: default: @@ -524,7 +530,7 @@ buildings: description: &painter_desc 將整個圖形塗上輸入的顏色。 double: name: 上色機(雙倍) - description: 同時為兩個輸入的圖形上色,每次上色只消耗一份顏色。 + description: 同時為兩個輸入的圖形上色,每次上色只消耗一份顏色塗料。 quad: name: 上色機(四向) description: 為圖形的四個角塗上不同的顏色。 @@ -544,12 +550,33 @@ buildings: deliver: 交付 toUnlock: 來解鎖 levelShortcut: LVL + wire: + default: + name: Energy Wire + description: Allows you to transport energy. + advanced_processor: + default: + name: Color Inverter + description: Accepts a color or shape and inverts it. + energy_generator: + deliver: Deliver + toGenerateEnergy: For + default: + name: Energy Generator + description: Generates energy by consuming shapes. + wire_crossings: + default: + name: Wire Splitter + description: Splits a energy wire into two. + merger: + name: Wire Merger + description: Merges two energy wires into one. storyRewards: # Those are the rewards gained from completing the store reward_cutter_and_trash: title: 切割圖形 - desc: 切割機已解鎖。不論切割機的方向,它都會把圖形從上到下切成兩半。

    記得把不需要的部分處理掉,否則這個這個建築會停止工作。為此我給你準備了垃圾桶,它會把所有放進去的物品銷毀掉。 + desc: 切割機已解鎖。不論切割機的方向,它都會把圖形垂直地切成兩半。

    記得把不需要的部分處理掉,否則這個這個建築會停止運作。為此我給你準備了垃圾桶,它會把所有放進去的物品銷毀掉。 reward_rotater: title: 順時針旋轉 @@ -558,15 +585,15 @@ storyRewards: reward_painter: title: 上色 desc: >- - The painter has been unlocked - Extract some color veins (just as you do with shapes) and combine it with a shape in the painter to color them!

    PS: If you are colorblind, there is a color blind mode in the settings! + 上色機已解鎖。開採一些顏色,用上色機把顏色和圖形混合,就可以為圖形著色。

    備註:如果你是色盲,設置中有色盲模式可以選。 reward_mixer: title: 混色 - desc: 混色器已解鎖-在此建築物中使用附加混合結合兩種顏色! + desc: 混色器已解鎖-在此建築物中使用附加混合結合兩種顏色! reward_stacker: title: 混合 - desc: 混合機已解鎖。混合機會嘗試把兩個輸入的圖形拼貼在一起。如果沒有重疊的部分,右邊的輸入會被混合到左邊的輸入上方! + desc: 混合機已解鎖。如果沒有重疊的部分,混合機會嘗試把兩個輸入的圖形拼貼在一起。如果有重疊的部分,右邊的輸入會被到左邊的輸入上方! reward_splitter: title: 分離/合併 @@ -574,19 +601,19 @@ storyRewards: reward_tunnel: title: 隧道 - desc: 隧道已解鎖。你現在可以從其他傳送帶或建築底下運送物品了(最長距離為四)! + desc: 隧道已解鎖。你現在可以從其他傳送帶或建築底下運送物品了! reward_rotater_ccw: title: 逆時針旋轉 - desc: 您已解鎖了旋轉器的變體-它可以逆時針旋轉! 要構建它,請選擇旋轉器,然後按“ T”鍵循環其變種! + desc: 您已解鎖了旋轉器的變體-它可以逆時針旋轉! 要構建它,請選擇旋轉器,然後按“T”鍵切換其變種! reward_miner_chainable: title: 鏈式開採機 - desc: 鏈式開採機變體已解鎖。它是開採機的一個變體。它可以將開采出來的資源傳遞給其他的開採機,使得資源提取更加高效! + desc: 鏈式開採機變體已解鎖。它是開採機的一個變體。它可以將開採出來的資源傳遞給其他的開採機,使得資源提取更加高效! reward_underground_belt_tier_2: title: 貳級隧道 - desc: 貳級隧道變體已解鎖。這個隧道有更長的傳輸距離。你還可以混用不同的隧道變體(點與點最長距離為7)! + desc: 貳級隧道變體已解鎖。這個隧道有更長的傳輸距離。你還可以混用不同的隧道變體! reward_splitter_compact: title: 小型合流機 @@ -615,7 +642,7 @@ storyRewards: reward_blueprints: title: 藍圖 - desc: 現在,您可以複製並貼上工廠的各個部分! 選擇一個區域(按住CTRL,然後用鼠標拖動),然後按'C'將其複制。

    貼上為非空閒,您需要生成藍圖 形狀來負擔得起! (您剛交付的那些)。 + desc: 現在,您可以複製並貼上工廠的各個部分! 選擇一個區域(按住CTRL,然後用游標拖動),然後按'C'將其複制。

    複製不是免費的,您需要用藍圖 形狀來支付! (您剛交付的那些)。 # Special reward, which is shown when there is no reward actually no_reward: @@ -669,9 +696,9 @@ settings: 改變語言。所有的翻譯皆由玩家提供,且有可能正在施工中! fullscreen: - title: 全屏 + title: 全螢幕 description: >- - 全屏以獲得更好的遊戲體驗。僅在獨立版中可用。 + 全螢幕以獲得更好的遊戲體驗。僅在獨立版中可用。 soundsMuted: title: 關閉音效 @@ -695,7 +722,7 @@ settings: refreshRate: title: 模擬頻率、刷新頻率 description: >- - 如果你的顯示器是144hz的,請在這裡更改刷新頻率,這樣遊戲可以正確地根據你的屏幕進行模擬。但是如果你的電腦性能不佳,提高刷新頻率可能降低幀數。 + 如果你的顯示器是144hz的,請在這裡更改刷新頻率,這樣遊戲可以正確地根據你的螢幕進行模擬。但是如果你的電腦性能不佳,提高刷新頻率可能降低幀數。 # description: >- # If you have a 144hz monitor, change the refresh rate here so the game will properly simulate at higher refresh rates. This might actually decrease the FPS if your computer is too slow. @@ -732,7 +759,7 @@ settings: vignette: title: 暈映 description: >- - 啟用暈映,將屏幕角落裡的顏色變深,更容易閱讀文本。 + 啟用暈映,將屏幕角落裡的顏色變深,更容易閱讀文字。 autosaveInterval: title: 自動刷新時間 @@ -744,27 +771,27 @@ settings: five_minutes: 5分鐘 ten_minutes: 10分鐘 twenty_minutes: 20分鐘 - disabled: 禁用 + disabled: 停用 compactBuildingInfo: title: 省略建築信息 description: >- - 通過顯示建築物的比率來縮短建築物的信息框。 否則 + 通過顯示建築物的比率來縮短建築物的資訊框。 否則 顯示所有說明+圖像。 disableCutDeleteWarnings: - title: 禁用剪下/刪除的警告 + title: 停用剪下/刪除的警告 description: >- - 剪下/刪除超過100幢建築物時禁用警告。 + 剪下/刪除超過100幢建築物時不顯示警告。 enableColorBlindHelper: title: 色盲模式 description: 如果您是色盲者,啟用了這設定,就可以玩遊戲了。 rotationByBuilding: - title: Rotation by building type + title: 依建築類型旋轉 description: >- - Each building type remembers the rotation you last set it to individually. - This may be more comfortable if you frequently switch between placing - different building types. + 每個建築類型,將會分別記住您最後一次使用的旋轉方向。 + 如果您常常切換不同類型的建築,這樣可能會更方便。 + keybindings: title: 按鍵設置 hint: >- @@ -794,8 +821,8 @@ keybindings: mapZoomOut: 縮小 createMarker: 創建地圖標記 - menuOpenShop: 升級菜單 - menuOpenStats: 統計菜單 + menuOpenShop: 升級選單 + menuOpenStats: 統計選單 toggleHud: 開關HUD toggleFPSInfo: 開關幀數與調試信息 @@ -823,14 +850,19 @@ keybindings: placementDisableAutoOrientation: 取消自動定向 placeMultiple: 繼續放置 placeInverse: 反向放置傳送帶 - pasteLastBlueprint: 粘貼上一張藍圖 + pasteLastBlueprint: 貼上前一張藍圖 massSelectCut: 剪切 - exportScreenshot: 導出截圖 + exportScreenshot: 匯出截圖 mapMoveFaster: 快速移動 lockBeltDirection: 啟用傳送帶規劃 switchDirectionLockSide: "規劃器:換邊" pipette: Pipette + menuClose: Close Menu + switchLayers: Switch layers + advanced_processor: Color Inverter + energy_generator: Energy Generator + wire: Energy Wire about: title: 關於遊戲 @@ -857,9 +889,9 @@ changelog: demo: features: restoringGames: 恢復存檔 #中? - importingGames: 倒入存檔 #中? + importingGames: 匯入存檔 #中? oneGameLimit: 最多一個存檔 customizeKeybindings: 按鍵設置 # customizeKeybindings: Customizing Keybindings - exportingBase: 導出工廠截圖 + exportingBase: 匯出工廠截圖 settingNotAvailable: 在演示版中不可用。 diff --git a/version b/version index b0c8928e..867e5243 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.1.18 \ No newline at end of file +1.2.0 \ No newline at end of file