diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dea711fef0..85459446aa 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,11 +7,9 @@ assignees: '' --- -**Note**: Do not report any new bugs directly relating to the v6 campaign. They will not be fixed or considered at this time. - **Platform**: *Android/iOS/Mac/Windows/Linux* -**Build**: *The build number under the title in the main menu. Required.* +**Build**: *The build number under the title in the main menu. Required. "LATEST" IS NOT A VERSION, I NEED THE EXACT BUILD NUMBER OF YOUR GAME.* **Issue**: *Explain your issue in detail.* @@ -19,7 +17,7 @@ assignees: '' **Link(s) to mod(s) used**: *The mod repositories or zip files that are related to the issue, if applicable.* -**Save file**: *The save file you were playing on when the bug happened. REQUIRED for any issue that happens in-game.* +**Save file**: *The (zipped) save file you were playing on when the bug happened. THIS IS REQUIRED FOR ANY ISSUE HAPPENING IN-GAME, REGARDLESS OF WHETHER YOU THINK IT HAPPENS EVERYWHERE. DO NOT DELETE OR OMIT THIS LINE UNLESS YOU ARE SURE THAT THE ISSUE DOES NOT HAPPEN IN-GAME.* **Crash report**: *The contents of relevant crash report files. REQUIRED if you are reporting a crash.* diff --git a/.travis.yml b/.travis.yml index 6b1dfd72ac..11dbe8cd1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ script: - git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds - cd ../MindustryBuilds - echo ${TRAVIS_TAG} -- if [ -n "$TRAVIS_TAG" ]; then echo versionName=5-fdroid-${TRAVIS_TAG:1}$'\n'versionCode=${TRAVIS_TAG:1} > version_fdroid.txt; git add .; git commit -m "Updating to build ${TRAVIS_TAG}"; fi +- if [ -n "$TRAVIS_TAG" ]; then echo versionName=6-fdroid-${TRAVIS_TAG:1}$'\n'versionCode=${TRAVIS_TAG:1} > version_fdroid.txt; git add .; git commit -m "Updating to build ${TRAVIS_TAG}"; fi - git tag ${TRAVIS_BUILD_NUMBER} - git config --global user.name "Build Uploader" - if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds ${TRAVIS_BUILD_NUMBER}; git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds; fi diff --git a/README.md b/README.md index 5c9c797297..13f620832f 100644 --- a/README.md +++ b/README.md @@ -9,34 +9,34 @@ _[Trello Board](https://trello.com/b/aE2tcUwF/mindustry-40-plans)_ _[Wiki](https://mindustrygame.github.io/wiki)_ _[Javadoc](https://mindustrygame.github.io/docs/)_ -### Contributing +## Contributing See [CONTRIBUTING](CONTRIBUTING.md). -### Building +## Building Bleeding-edge builds are generated automatically for every commit. You can see them [here](https://github.com/Anuken/MindustryBuilds/releases). If you'd rather compile on your own, follow these instructions. First, make sure you have [JDK 14](https://adoptopenjdk.net/) installed. Open a terminal in the root directory, `cd` to the Mindustry folder and run the following commands: -#### Windows +### Windows _Running:_ `gradlew desktop:run` _Building:_ `gradlew desktop:dist` _Sprite Packing:_ `gradlew tools:pack` -#### Linux/Mac OS +### Linux/Mac OS _Running:_ `./gradlew desktop:run` _Building:_ `./gradlew desktop:dist` _Sprite Packing:_ `./gradlew tools:pack` -#### Server +### Server Server builds are bundled with each released build (in Releases). If you'd rather compile on your own, replace 'desktop' with 'server', e.g. `gradlew server:dist`. -#### Android +### Android 1. Install the Android SDK [here.](https://developer.android.com/studio#downloads) Make sure you're downloading the "Command line tools only", as Android Studio is not required. 2. Set the `ANDROID_HOME` environment variable to point to your unzipped Android SDK directory. @@ -44,7 +44,9 @@ Server builds are bundled with each released build (in Releases). If you'd rathe To debug the application on a connected phone, run `gradlew android:installDebug android:run`. -##### Troubleshooting +### Troubleshooting + +#### Permission Denied If the terminal returns `Permission denied` or `Command not found` on Mac/Linux, run `chmod +x ./gradlew` before running `./gradlew`. *This is a one-time procedure.* @@ -53,11 +55,11 @@ If the terminal returns `Permission denied` or `Command not found` on Mac/Linux, Gradle may take up to several minutes to download files. Be patient.
After building, the output .JAR file should be in `/desktop/build/libs/Mindustry.jar` for desktop builds, and in `/server/build/libs/server-release.jar` for server builds. -### Feature Requests +## Feature Requests Post feature requests and feedback [here](https://github.com/Anuken/Mindustry-Suggestions/issues/new/choose). -### Downloads +## Downloads [Get it on Itch.io s.name().contains("Sync")) || ann.serialize()); diff --git a/annotations/src/main/java/mindustry/annotations/misc/LogicStatementProcessor.java b/annotations/src/main/java/mindustry/annotations/misc/LogicStatementProcessor.java index 64adc37c89..6e597bd002 100644 --- a/annotations/src/main/java/mindustry/annotations/misc/LogicStatementProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/misc/LogicStatementProcessor.java @@ -43,9 +43,9 @@ public class LogicStatementProcessor extends BaseProcessor{ String name = c.annotation(RegisterStatement.class).value(); if(beganWrite){ - writer.nextControlFlow("else if(obj instanceof $T)", c.mirror()); + writer.nextControlFlow("else if(obj.getClass() == $T.class)", c.mirror()); }else{ - writer.beginControlFlow("if(obj instanceof $T)", c.mirror()); + writer.beginControlFlow("if(obj.getClass() == $T.class)", c.mirror()); beganWrite = true; } @@ -53,6 +53,7 @@ public class LogicStatementProcessor extends BaseProcessor{ writer.addStatement("out.append($S)", name); Seq fields = c.fields(); + fields.addAll(c.superclass().fields()); String readSt = "if(tokens[0].equals($S))"; if(beganRead){ diff --git a/annotations/src/main/resources/classids.properties b/annotations/src/main/resources/classids.properties index 86ca440e1c..43a3517ff0 100644 --- a/annotations/src/main/resources/classids.properties +++ b/annotations/src/main/resources/classids.properties @@ -14,6 +14,8 @@ mindustry.entities.comp.EffectStateComp=9 mindustry.entities.comp.FireComp=10 mindustry.entities.comp.LaunchCoreComp=11 mindustry.entities.comp.PlayerComp=12 +mindustry.entities.comp.PosTeam=27 +mindustry.entities.comp.PosTeamDef=28 mindustry.entities.comp.PuddleComp=13 mindustry.type.Weather.WeatherStateComp=14 mindustry.world.blocks.campaign.LaunchPad.LaunchPayloadComp=15 diff --git a/annotations/src/main/resources/revisions/BuilderCommanderPayloadUnit/0.json b/annotations/src/main/resources/revisions/BuilderCommanderPayloadUnit/0.json deleted file mode 100644 index 826bd02faf..0000000000 --- a/annotations/src/main/resources/revisions/BuilderCommanderPayloadUnit/0.json +++ /dev/null @@ -1 +0,0 @@ -{fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderMechUnit/0.json b/annotations/src/main/resources/revisions/BuilderMechUnit/0.json deleted file mode 100644 index 0588266557..0000000000 --- a/annotations/src/main/resources/revisions/BuilderMechUnit/0.json +++ /dev/null @@ -1 +0,0 @@ -{fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:deactivated,type:boolean,size:1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:plans,type:arc.struct.Queue,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderMinerUnit/0.json b/annotations/src/main/resources/revisions/BuilderMinerUnit/0.json deleted file mode 100644 index a4e818fd35..0000000000 --- a/annotations/src/main/resources/revisions/BuilderMinerUnit/0.json +++ /dev/null @@ -1 +0,0 @@ -{fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:deactivated,type:boolean,size:1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:plans,type:arc.struct.Queue,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/Building/0.json b/annotations/src/main/resources/revisions/BuildingComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/Building/0.json rename to annotations/src/main/resources/revisions/BuildingComp/0.json diff --git a/annotations/src/main/resources/revisions/Bullet/0.json b/annotations/src/main/resources/revisions/BulletComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/Bullet/0.json rename to annotations/src/main/resources/revisions/BulletComp/0.json diff --git a/annotations/src/main/resources/revisions/Decal/0.json b/annotations/src/main/resources/revisions/DecalComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/Decal/0.json rename to annotations/src/main/resources/revisions/DecalComp/0.json diff --git a/annotations/src/main/resources/revisions/EffectState/0.json b/annotations/src/main/resources/revisions/EffectStateComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/EffectState/0.json rename to annotations/src/main/resources/revisions/EffectStateComp/0.json diff --git a/annotations/src/main/resources/revisions/EffectState/1.json b/annotations/src/main/resources/revisions/EffectStateComp/1.json similarity index 100% rename from annotations/src/main/resources/revisions/EffectState/1.json rename to annotations/src/main/resources/revisions/EffectStateComp/1.json diff --git a/annotations/src/main/resources/revisions/EffectState/2.json b/annotations/src/main/resources/revisions/EffectStateComp/2.json similarity index 100% rename from annotations/src/main/resources/revisions/EffectState/2.json rename to annotations/src/main/resources/revisions/EffectStateComp/2.json diff --git a/annotations/src/main/resources/revisions/EffectState/3.json b/annotations/src/main/resources/revisions/EffectStateComp/3.json similarity index 100% rename from annotations/src/main/resources/revisions/EffectState/3.json rename to annotations/src/main/resources/revisions/EffectStateComp/3.json diff --git a/annotations/src/main/resources/revisions/EffectState/4.json b/annotations/src/main/resources/revisions/EffectStateComp/4.json similarity index 100% rename from annotations/src/main/resources/revisions/EffectState/4.json rename to annotations/src/main/resources/revisions/EffectStateComp/4.json diff --git a/annotations/src/main/resources/revisions/EffectState/5.json b/annotations/src/main/resources/revisions/EffectStateComp/5.json similarity index 100% rename from annotations/src/main/resources/revisions/EffectState/5.json rename to annotations/src/main/resources/revisions/EffectStateComp/5.json diff --git a/annotations/src/main/resources/revisions/Fire/0.json b/annotations/src/main/resources/revisions/FireComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/Fire/0.json rename to annotations/src/main/resources/revisions/FireComp/0.json diff --git a/annotations/src/main/resources/revisions/Fire/1.json b/annotations/src/main/resources/revisions/FireComp/1.json similarity index 100% rename from annotations/src/main/resources/revisions/Fire/1.json rename to annotations/src/main/resources/revisions/FireComp/1.json diff --git a/annotations/src/main/resources/revisions/ForceDraw/0.json b/annotations/src/main/resources/revisions/ForceDrawComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/ForceDraw/0.json rename to annotations/src/main/resources/revisions/ForceDrawComp/0.json diff --git a/annotations/src/main/resources/revisions/LaunchCore/0.json b/annotations/src/main/resources/revisions/LaunchCoreComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/LaunchCore/0.json rename to annotations/src/main/resources/revisions/LaunchCoreComp/0.json diff --git a/annotations/src/main/resources/revisions/LaunchPayload/0.json b/annotations/src/main/resources/revisions/LaunchPayloadComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/LaunchPayload/0.json rename to annotations/src/main/resources/revisions/LaunchPayloadComp/0.json diff --git a/annotations/src/main/resources/revisions/MechUnit/0.json b/annotations/src/main/resources/revisions/MechUnit/0.json deleted file mode 100644 index 1779e118de..0000000000 --- a/annotations/src/main/resources/revisions/MechUnit/0.json +++ /dev/null @@ -1 +0,0 @@ -{fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:deactivated,type:boolean,size:1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/MechUnit/1.json b/annotations/src/main/resources/revisions/MechUnit/1.json deleted file mode 100644 index 66897ee06f..0000000000 --- a/annotations/src/main/resources/revisions/MechUnit/1.json +++ /dev/null @@ -1 +0,0 @@ -{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/Player/0.json b/annotations/src/main/resources/revisions/PlayerComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/Player/0.json rename to annotations/src/main/resources/revisions/PlayerComp/0.json diff --git a/annotations/src/main/resources/revisions/PosTeamDef/0.json b/annotations/src/main/resources/revisions/PosTeamDef/0.json new file mode 100644 index 0000000000..1c1e6c36ec --- /dev/null +++ b/annotations/src/main/resources/revisions/PosTeamDef/0.json @@ -0,0 +1 @@ +{fields:[{name:team,type:mindustry.game.Team},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/Puddle/0.json b/annotations/src/main/resources/revisions/PuddleComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/Puddle/0.json rename to annotations/src/main/resources/revisions/PuddleComp/0.json diff --git a/annotations/src/main/resources/revisions/UnitEntity/0.json b/annotations/src/main/resources/revisions/UnitEntity/0.json deleted file mode 100644 index 5431957381..0000000000 --- a/annotations/src/main/resources/revisions/UnitEntity/0.json +++ /dev/null @@ -1 +0,0 @@ -{fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:deactivated,type:boolean,size:1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/UnitEntity/1.json b/annotations/src/main/resources/revisions/UnitEntity/1.json deleted file mode 100644 index dd8fdb2784..0000000000 --- a/annotations/src/main/resources/revisions/UnitEntity/1.json +++ /dev/null @@ -1 +0,0 @@ -{version:1,fields:[{name:ammo,type:float,size:4},{name:armor,type:float,size:4},{name:controller,type:mindustry.entities.units.UnitController,size:-1},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:isShooting,type:boolean,size:1},{name:mounts,type:"mindustry.entities.units.WeaponMount[]",size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Seq,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/WeatherState/0.json b/annotations/src/main/resources/revisions/WeatherStateComp/0.json similarity index 100% rename from annotations/src/main/resources/revisions/WeatherState/0.json rename to annotations/src/main/resources/revisions/WeatherStateComp/0.json diff --git a/annotations/src/main/resources/revisions/WeatherState/1.json b/annotations/src/main/resources/revisions/WeatherStateComp/1.json similarity index 100% rename from annotations/src/main/resources/revisions/WeatherState/1.json rename to annotations/src/main/resources/revisions/WeatherStateComp/1.json diff --git a/annotations/src/main/resources/revisions/WeatherState/2.json b/annotations/src/main/resources/revisions/WeatherStateComp/2.json similarity index 100% rename from annotations/src/main/resources/revisions/WeatherState/2.json rename to annotations/src/main/resources/revisions/WeatherStateComp/2.json diff --git a/annotations/src/main/resources/revisions/BlockUnitUnit/0.json b/annotations/src/main/resources/revisions/block/0.json similarity index 100% rename from annotations/src/main/resources/revisions/BlockUnitUnit/0.json rename to annotations/src/main/resources/revisions/block/0.json diff --git a/annotations/src/main/resources/revisions/BlockUnitUnit/1.json b/annotations/src/main/resources/revisions/block/1.json similarity index 100% rename from annotations/src/main/resources/revisions/BlockUnitUnit/1.json rename to annotations/src/main/resources/revisions/block/1.json diff --git a/annotations/src/main/resources/revisions/block/2.json b/annotations/src/main/resources/revisions/block/2.json new file mode 100644 index 0000000000..b9ab081fe8 --- /dev/null +++ b/annotations/src/main/resources/revisions/block/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/CommanderLegsUnit/0.json b/annotations/src/main/resources/revisions/corvus/0.json similarity index 100% rename from annotations/src/main/resources/revisions/CommanderLegsUnit/0.json rename to annotations/src/main/resources/revisions/corvus/0.json diff --git a/annotations/src/main/resources/revisions/CommanderLegsUnit/1.json b/annotations/src/main/resources/revisions/corvus/1.json similarity index 100% rename from annotations/src/main/resources/revisions/CommanderLegsUnit/1.json rename to annotations/src/main/resources/revisions/corvus/1.json diff --git a/annotations/src/main/resources/revisions/corvus/2.json b/annotations/src/main/resources/revisions/corvus/2.json new file mode 100644 index 0000000000..b9ab081fe8 --- /dev/null +++ b/annotations/src/main/resources/revisions/corvus/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/CommanderUnitWaterMove/0.json b/annotations/src/main/resources/revisions/flare/0.json similarity index 100% rename from annotations/src/main/resources/revisions/CommanderUnitWaterMove/0.json rename to annotations/src/main/resources/revisions/flare/0.json diff --git a/annotations/src/main/resources/revisions/CommanderUnitWaterMove/1.json b/annotations/src/main/resources/revisions/flare/1.json similarity index 100% rename from annotations/src/main/resources/revisions/CommanderUnitWaterMove/1.json rename to annotations/src/main/resources/revisions/flare/1.json diff --git a/annotations/src/main/resources/revisions/flare/2.json b/annotations/src/main/resources/revisions/flare/2.json new file mode 100644 index 0000000000..b9ab081fe8 --- /dev/null +++ b/annotations/src/main/resources/revisions/flare/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/CommanderMechUnit/0.json b/annotations/src/main/resources/revisions/mace/0.json similarity index 100% rename from annotations/src/main/resources/revisions/CommanderMechUnit/0.json rename to annotations/src/main/resources/revisions/mace/0.json diff --git a/annotations/src/main/resources/revisions/CommanderMechUnit/1.json b/annotations/src/main/resources/revisions/mace/1.json similarity index 100% rename from annotations/src/main/resources/revisions/CommanderMechUnit/1.json rename to annotations/src/main/resources/revisions/mace/1.json diff --git a/annotations/src/main/resources/revisions/mace/2.json b/annotations/src/main/resources/revisions/mace/2.json new file mode 100644 index 0000000000..7b348dd022 --- /dev/null +++ b/annotations/src/main/resources/revisions/mace/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/0.json b/annotations/src/main/resources/revisions/mega/0.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/0.json rename to annotations/src/main/resources/revisions/mega/0.json diff --git a/annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/1.json b/annotations/src/main/resources/revisions/mega/1.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderMinerPayloadUnit/1.json rename to annotations/src/main/resources/revisions/mega/1.json diff --git a/annotations/src/main/resources/revisions/mega/2.json b/annotations/src/main/resources/revisions/mega/2.json new file mode 100644 index 0000000000..87371c85dd --- /dev/null +++ b/annotations/src/main/resources/revisions/mega/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/MinerUnit/0.json b/annotations/src/main/resources/revisions/mono/0.json similarity index 100% rename from annotations/src/main/resources/revisions/MinerUnit/0.json rename to annotations/src/main/resources/revisions/mono/0.json diff --git a/annotations/src/main/resources/revisions/MinerUnit/1.json b/annotations/src/main/resources/revisions/mono/1.json similarity index 100% rename from annotations/src/main/resources/revisions/MinerUnit/1.json rename to annotations/src/main/resources/revisions/mono/1.json diff --git a/annotations/src/main/resources/revisions/mono/2.json b/annotations/src/main/resources/revisions/mono/2.json new file mode 100644 index 0000000000..6a6cc37b39 --- /dev/null +++ b/annotations/src/main/resources/revisions/mono/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/0.json b/annotations/src/main/resources/revisions/nova/0.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/0.json rename to annotations/src/main/resources/revisions/nova/0.json diff --git a/annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/1.json b/annotations/src/main/resources/revisions/nova/1.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderCommanderMechMinerUnit/1.json rename to annotations/src/main/resources/revisions/nova/1.json diff --git a/annotations/src/main/resources/revisions/nova/2.json b/annotations/src/main/resources/revisions/nova/2.json new file mode 100644 index 0000000000..541f5f8c57 --- /dev/null +++ b/annotations/src/main/resources/revisions/nova/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/AmmoDistributeBuilderCommanderPayloadUnit/0.json b/annotations/src/main/resources/revisions/oct/0.json similarity index 100% rename from annotations/src/main/resources/revisions/AmmoDistributeBuilderCommanderPayloadUnit/0.json rename to annotations/src/main/resources/revisions/oct/0.json diff --git a/annotations/src/main/resources/revisions/oct/1.json b/annotations/src/main/resources/revisions/oct/1.json new file mode 100644 index 0000000000..1e9e8f02c7 --- /dev/null +++ b/annotations/src/main/resources/revisions/oct/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderMinerTrailUnit/0.json b/annotations/src/main/resources/revisions/poly/0.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderMinerTrailUnit/0.json rename to annotations/src/main/resources/revisions/poly/0.json diff --git a/annotations/src/main/resources/revisions/BuilderMinerUnit/1.json b/annotations/src/main/resources/revisions/poly/1.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderMinerUnit/1.json rename to annotations/src/main/resources/revisions/poly/1.json diff --git a/annotations/src/main/resources/revisions/poly/2.json b/annotations/src/main/resources/revisions/poly/2.json new file mode 100644 index 0000000000..f210a1f05c --- /dev/null +++ b/annotations/src/main/resources/revisions/poly/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderPayloadUnit/0.json b/annotations/src/main/resources/revisions/quad/0.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderPayloadUnit/0.json rename to annotations/src/main/resources/revisions/quad/0.json diff --git a/annotations/src/main/resources/revisions/BuilderPayloadUnit/1.json b/annotations/src/main/resources/revisions/quad/1.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderPayloadUnit/1.json rename to annotations/src/main/resources/revisions/quad/1.json diff --git a/annotations/src/main/resources/revisions/quad/2.json b/annotations/src/main/resources/revisions/quad/2.json new file mode 100644 index 0000000000..c0af7d53a9 --- /dev/null +++ b/annotations/src/main/resources/revisions/quad/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/LegsUnit/0.json b/annotations/src/main/resources/revisions/risso/0.json similarity index 100% rename from annotations/src/main/resources/revisions/LegsUnit/0.json rename to annotations/src/main/resources/revisions/risso/0.json diff --git a/annotations/src/main/resources/revisions/LegsUnit/1.json b/annotations/src/main/resources/revisions/risso/1.json similarity index 100% rename from annotations/src/main/resources/revisions/LegsUnit/1.json rename to annotations/src/main/resources/revisions/risso/1.json diff --git a/annotations/src/main/resources/revisions/risso/2.json b/annotations/src/main/resources/revisions/risso/2.json new file mode 100644 index 0000000000..b9ab081fe8 --- /dev/null +++ b/annotations/src/main/resources/revisions/risso/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/BuilderLegsUnit/0.json b/annotations/src/main/resources/revisions/spiroct/0.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderLegsUnit/0.json rename to annotations/src/main/resources/revisions/spiroct/0.json diff --git a/annotations/src/main/resources/revisions/BuilderLegsUnit/1.json b/annotations/src/main/resources/revisions/spiroct/1.json similarity index 100% rename from annotations/src/main/resources/revisions/BuilderLegsUnit/1.json rename to annotations/src/main/resources/revisions/spiroct/1.json diff --git a/annotations/src/main/resources/revisions/spiroct/2.json b/annotations/src/main/resources/revisions/spiroct/2.json new file mode 100644 index 0000000000..fe5760e693 --- /dev/null +++ b/annotations/src/main/resources/revisions/spiroct/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/build.gradle b/build.gradle index e2a00358b6..c94a79598a 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ allprojects{ ext{ versionNumber = '6' - if(!project.hasProperty("versionModifier")) versionModifier = 'alpha' + if(!project.hasProperty("versionModifier")) versionModifier = 'beta' if(!project.hasProperty("versionType")) versionType = 'official' appName = 'Mindustry' steamworksVersion = '891ed912791e01fe9ee6237a6497e5212b85c256' @@ -262,6 +262,8 @@ project(":ios"){ project(":core"){ apply plugin: "java-library" + compileJava.options.fork = true + task preGen{ outputs.upToDateWhen{ false } generateLocales() @@ -303,7 +305,7 @@ project(":core"){ compileOnly project(":annotations") annotationProcessor project(":annotations") - annotationProcessor 'com.github.Anuken:jabel:40eec868af' + annotationProcessor 'com.github.Anuken:jabel:34e4c172e65b3928cd9eabe1993654ea79c409cd' } } diff --git a/core/assets-raw/sprites/blocks/environment/cliff.png b/core/assets-raw/sprites/blocks/environment/cliff.png index 9d76c62084..0ea51ef09b 100644 Binary files a/core/assets-raw/sprites/blocks/environment/cliff.png and b/core/assets-raw/sprites/blocks/environment/cliff.png differ diff --git a/core/assets-raw/sprites/blocks/environment/cliff0.png b/core/assets-raw/sprites/blocks/environment/cliff0.png new file mode 100644 index 0000000000..17b24f68e1 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/cliff0.png differ diff --git a/core/assets-raw/sprites/blocks/environment/cliff1.png b/core/assets-raw/sprites/blocks/environment/cliff1.png new file mode 100644 index 0000000000..03ff8dbf3d Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/cliff1.png differ diff --git a/core/assets-raw/sprites/blocks/environment/cliff2.png b/core/assets-raw/sprites/blocks/environment/cliff2.png new file mode 100644 index 0000000000..dbf002cee5 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/cliff2.png differ diff --git a/core/assets-raw/sprites/blocks/environment/cliff3.png b/core/assets-raw/sprites/blocks/environment/cliff3.png new file mode 100644 index 0000000000..e78a6f27ce Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/cliff3.png differ diff --git a/core/assets-raw/sprites/blocks/environment/cliff4.png b/core/assets-raw/sprites/blocks/environment/cliff4.png new file mode 100644 index 0000000000..7800c59677 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/cliff4.png differ diff --git a/core/assets-raw/sprites/blocks/environment/cliff5.png b/core/assets-raw/sprites/blocks/environment/cliff5.png new file mode 100644 index 0000000000..2e71f802f2 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/cliff5.png differ diff --git a/core/assets-raw/sprites/blocks/environment/cliff6.png b/core/assets-raw/sprites/blocks/environment/cliff6.png new file mode 100644 index 0000000000..fceb598e3e Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/cliff6.png differ diff --git a/core/assets-raw/sprites/blocks/environment/cliff7.png b/core/assets-raw/sprites/blocks/environment/cliff7.png new file mode 100644 index 0000000000..5978387bbe Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/cliff7.png differ diff --git a/core/assets-raw/sprites/blocks/environment/dune-wall1.png b/core/assets-raw/sprites/blocks/environment/dune-wall1.png index 923945dd74..64d13b3f24 100644 Binary files a/core/assets-raw/sprites/blocks/environment/dune-wall1.png and b/core/assets-raw/sprites/blocks/environment/dune-wall1.png differ diff --git a/core/assets-raw/sprites/blocks/environment/dune-wall2.png b/core/assets-raw/sprites/blocks/environment/dune-wall2.png index 85783da449..5e3efcaae0 100644 Binary files a/core/assets-raw/sprites/blocks/environment/dune-wall2.png and b/core/assets-raw/sprites/blocks/environment/dune-wall2.png differ diff --git a/core/assets-raw/sprites/blocks/environment/space.png b/core/assets-raw/sprites/blocks/environment/space.png new file mode 100644 index 0000000000..bc38442fd1 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/space.png differ diff --git a/core/assets/baseparts/1603214918168.msch b/core/assets/baseparts/1603214918168.msch new file mode 100644 index 0000000000..6d69a2c362 --- /dev/null +++ b/core/assets/baseparts/1603214918168.msch @@ -0,0 +1,2 @@ +mschx5 +! Ey-J(qG&'.}SmtWKuXGq Yz\P?E:Y ΤԢh)(%UDK(.%#V0FN# \ No newline at end of file diff --git a/core/assets/baseparts/1603214967392.msch b/core/assets/baseparts/1603214967392.msch new file mode 100644 index 0000000000..0e30b20a82 --- /dev/null +++ b/core/assets/baseparts/1603214967392.msch @@ -0,0 +1 @@ +mschx%A ᧀZc\.z$dФ/t?3o`Ɲ.L<$NV!b>=e%80r"^!GKug9耦{S_@+$jW\oJSM ܅0?CThqW \ No newline at end of file diff --git a/core/assets/baseparts/1603214996033.msch b/core/assets/baseparts/1603214996033.msch new file mode 100644 index 0000000000..83690987ae --- /dev/null +++ b/core/assets/baseparts/1603214996033.msch @@ -0,0 +1,3 @@ +mschx% + Ӫmic׽C/{bU~A>:n^Xvw?ŧO }c|tt#-)䃑dqPҒr$b@*b2rtҳRZґ@Wr# \ No newline at end of file diff --git a/core/assets/baseparts/1603215171294.msch b/core/assets/baseparts/1603215171294.msch new file mode 100644 index 0000000000..eaef917ff3 --- /dev/null +++ b/core/assets/baseparts/1603215171294.msch @@ -0,0 +1,2 @@ +mschx%ᎃ Ai߃pB`M +!0;060/oK8J\k a|T k~Sq)O-h_|M%35V⾸Ӌ\[}ٱ#ⶼ@0-'hh0@W @JCi4bjp2gㄽ_]䡎Eӱ-K+. \ No newline at end of file diff --git a/core/assets/baseparts/1603215272794.msch b/core/assets/baseparts/1603215272794.msch new file mode 100644 index 0000000000..b2351a3857 --- /dev/null +++ b/core/assets/baseparts/1603215272794.msch @@ -0,0 +1 @@ +mschxMKn D 1P&#$ 9yvtCY_%Jno>1-~K؎i?#BI%q;R8W;r˖#v)!F\7ٔoIy{4ïvg=!;^`4E ` ah:I:!꬐u0hRFC7: TW0t=z*] %wX#H7G4}mWW03Įb6 e> \ No newline at end of file diff --git a/core/assets/baseparts/1603215345320.msch b/core/assets/baseparts/1603215345320.msch new file mode 100644 index 0000000000..8c97534bdf --- /dev/null +++ b/core/assets/baseparts/1603215345320.msch @@ -0,0 +1,4 @@ +mschxEn@\E!dͲ:iҐqvfاȇP^]|g7Bw +Vp]ln5'?|`npr};МC0O[vM߆4vpߑ'*HY~2dJNV(BLr +bHw-cKM52e*W R!KL{X# SAJR5dCV6r]m`t~H覵RvX +2HNk{8'L^+y# +pU%%%JAJ$?M \ No newline at end of file diff --git a/core/assets/baseparts/1603215415778.msch b/core/assets/baseparts/1603215415778.msch new file mode 100644 index 0000000000..6f7f75ab97 --- /dev/null +++ b/core/assets/baseparts/1603215415778.msch @@ -0,0 +1,2 @@ +mschx-k +1 MуP PҮEdM?o2c1e_BϚ/guI08bI~e.pRwGO`madh{Nނ:'"IZ}äz}o)" \ No newline at end of file diff --git a/core/assets/baseparts/1603215454977.msch b/core/assets/baseparts/1603215454977.msch new file mode 100644 index 0000000000..c0a53057ed Binary files /dev/null and b/core/assets/baseparts/1603215454977.msch differ diff --git a/core/assets/baseparts/1603215491407.msch b/core/assets/baseparts/1603215491407.msch new file mode 100644 index 0000000000..ba578a4a55 --- /dev/null +++ b/core/assets/baseparts/1603215491407.msch @@ -0,0 +1,2 @@ +mschx5ኃ01mj9(h~H½eufCn +jgA7}~K>@ }cNOv2a=oc\D[=qt0&?S (Р(p=R$тJT&geJIMʴ* ~#d|EE4I#tFxpzpzʤ3% h'/4 ol```›SfffG?J (, \ No newline at end of file diff --git a/core/assets/baseparts/1603215563717.msch b/core/assets/baseparts/1603215563717.msch new file mode 100644 index 0000000000..460c1d9f8b Binary files /dev/null and b/core/assets/baseparts/1603215563717.msch differ diff --git a/core/assets/baseparts/1603215697527.msch b/core/assets/baseparts/1603215697527.msch new file mode 100644 index 0000000000..427e52f671 Binary files /dev/null and b/core/assets/baseparts/1603215697527.msch differ diff --git a/core/assets/baseparts/1603215771822.msch b/core/assets/baseparts/1603215771822.msch new file mode 100644 index 0000000000..68ee586ea5 Binary files /dev/null and b/core/assets/baseparts/1603215771822.msch differ diff --git a/core/assets/baseparts/1603215801163.msch b/core/assets/baseparts/1603215801163.msch new file mode 100644 index 0000000000..09b9033d84 --- /dev/null +++ b/core/assets/baseparts/1603215801163.msch @@ -0,0 +1 @@ +mschx-[ DJJ aQMӵ~g&31dSo=-q[[LޭFqav.0[ SA/ciF(dPD~+ \ No newline at end of file diff --git a/core/assets/baseparts/1603216038407.msch b/core/assets/baseparts/1603216038407.msch new file mode 100644 index 0000000000..85865ba123 Binary files /dev/null and b/core/assets/baseparts/1603216038407.msch differ diff --git a/core/assets/baseparts/1603216102310.msch b/core/assets/baseparts/1603216102310.msch new file mode 100644 index 0000000000..a05dbc61ed --- /dev/null +++ b/core/assets/baseparts/1603216102310.msch @@ -0,0 +1 @@ +mschx%[j0 EoؓK]e258 ;SJI]">O}\_~Hy !K) %Q5KzFNR2L/9uۋX|iX9u+8pz&։mOh!>t^m1%(M6Ae) \ No newline at end of file diff --git a/core/assets/baseparts/1603216240041.msch b/core/assets/baseparts/1603216240041.msch new file mode 100644 index 0000000000..c0960c09d5 --- /dev/null +++ b/core/assets/baseparts/1603216240041.msch @@ -0,0 +1,3 @@ +mschxMIR0EJk.cp +*cZrF_\n?2^x(Rv Hg^}N'ς$6r4Tl"=ZނbA4W'&wt3-l`PC?6s}+iyf$15a-~Y/gD>X \ No newline at end of file diff --git a/core/assets/baseparts/1603222833941.msch b/core/assets/baseparts/1603222833941.msch new file mode 100644 index 0000000000..565eecf779 Binary files /dev/null and b/core/assets/baseparts/1603222833941.msch differ diff --git a/core/assets/baseparts/1603222912251.msch b/core/assets/baseparts/1603222912251.msch new file mode 100644 index 0000000000..6b33abac34 Binary files /dev/null and b/core/assets/baseparts/1603222912251.msch differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 647901a572..f492a6f473 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -20,7 +20,7 @@ gameover = Game Over gameover.pvp = The[accent] {0}[] team is victorious! highscore = [accent]New highscore! copied = Copied. -indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[]. +indev.popup = [accent]v6[] is currently in [accent]beta[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- SFX and music are unfinished/missing\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[]. indev.notready = This part of the game isn't ready yet load.sound = Sounds @@ -100,8 +100,7 @@ committingchanges = Comitting Changes done = Done feature.unsupported = Your device does not support this feature. -mods.alphainfo = Keep in mind that mods are in alpha, and[scarlet] may be very buggy[].\nReport any issues you find to the Mindustry GitHub or Discord. -mods.alpha = [accent](Alpha) +mods.alphainfo = Keep in mind that mods are in alpha, and[scarlet] may be very buggy[].\nReport any issues you find to the Mindustry GitHub. mods = Mods mods.none = [lightgray]No mods found! mods.guide = Modding Guide @@ -285,12 +284,15 @@ selectschematic = [accent][[{0}][] to select+copy pausebuilding = [accent][[{0}][] to pause building resumebuilding = [scarlet][[{0}][] to resume building wave = [accent]Wave {0} +wave.cap = [accent]Wave {0}/{1} wave.waiting = [lightgray]Wave in {0} wave.waveInProgress = [lightgray]Wave in progress waiting = [lightgray]Waiting... waiting.players = Waiting for players... wave.enemies = [lightgray]{0} Enemies Remaining wave.enemy = [lightgray]{0} Enemy Remaining +wave.guardianwarn = Guardian approaching in [accent]{0}[] waves. +wave.guardianwarn.one = Guardian approaching in [accent]{0}[] wave. loadimage = Load Image saveimage = Save Image unknown = Unknown @@ -329,6 +331,7 @@ editor.generation = Generation: editor.ingame = Edit In-Game editor.publish.workshop = Publish On Workshop editor.newmap = New Map +editor.center = Center workshop = Workshop waves.title = Waves waves.remove = Remove @@ -418,6 +421,7 @@ filters.empty = [lightgray]No filters! Add one with the button below. filter.distort = Distort filter.noise = Noise filter.enemyspawn = Enemy Spawn Select +filter.spawnpath = Path To Spawn filter.corespawn = Core Select filter.median = Median filter.oremedian = Ore Median @@ -442,6 +446,7 @@ filter.option.amount = Amount filter.option.block = Block filter.option.floor = Floor filter.option.flooronto = Target Floor +filter.option.target = Target filter.option.wall = Wall filter.option.ore = Ore filter.option.floor2 = Secondary Floor @@ -475,7 +480,7 @@ requirement.research = Research {0} requirement.capture = Capture {0} bestwave = [lightgray]Best Wave: {0} launch.text = Launch -campaign.multiplayer = While playing multiplayer in campaign, you can only research using items from [accent]your[] sectors, [scarlet]not[] the host's sector that you are on right now.\n\nTo get items to [accent]your[] sectors in multiplayer, use a [accent]launch pad[]. +research.multiplayer = Only the host can research items. uncover = Uncover configure = Configure Loadout #TODO @@ -509,6 +514,7 @@ weather.rain.name = Rain weather.snow.name = Snow weather.sandstorm.name = Sandstorm weather.sporestorm.name = Sporestorm +weather.fog.name = Fog sectors.unexplored = [lightgray]Unexplored sectors.resources = Resources: @@ -518,6 +524,12 @@ sectors.resume = Resume sectors.launch = Launch sectors.select = Select sectors.nonelaunch = [lightgray]none (sun) +sectors.rename = Rename Sector +sector.missingresources = [scarlet]Insufficient Core Resources + +planet.serpulo.name = Serpulo +#TODO better name +planet.sun.name = Sun #NOTE TO TRANSLATORS: don't bother editing these, they'll be removed and/or rewritten anyway sector.groundZero.name = Ground Zero @@ -562,6 +574,10 @@ settings.clear.confirm = Are you sure you want to clear this data?\nWhat is done settings.clearall.confirm = [scarlet]WARNING![]\nThis will clear all data, including saves, maps, unlocks and keybinds.\nOnce you press 'ok' the game will wipe all data and automatically exit. settings.clearsaves.confirm = Are you sure you want to clear all your saves? settings.clearsaves = Clear Saves +settings.clearresearch = Clear Research +settings.clearresearch.confirm = Are you sure you want to clear all of your campaign research? +settings.clearcampaignsaves = Clear Campaign Saves +settings.clearcampaignsaves.confirm = Are you sure you want to clear all of your campaign saves? paused = [accent]< Paused > clear = Clear banned = [scarlet]Banned @@ -572,50 +588,74 @@ info.title = Info error.title = [scarlet]An error has occured error.crashtitle = An error has occured unit.nobuild = [scarlet]Unit can't build -blocks.input = Input -blocks.output = Output -blocks.booster = Booster -blocks.tiles = Required Tiles -blocks.affinities = Affinities +lastaccessed = [lightgray]Last Accessed: {0} block.unknown = [lightgray]??? -blocks.powercapacity = Power Capacity -blocks.powershot = Power/Shot -blocks.damage = Damage -blocks.targetsair = Targets Air -blocks.targetsground = Targets Ground -blocks.itemsmoved = Move Speed -blocks.launchtime = Time Between Launches -blocks.shootrange = Range -blocks.size = Size -blocks.displaysize = Display Size -blocks.liquidcapacity = Liquid Capacity -blocks.powerrange = Power Range -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Power Use -blocks.powerdamage = Power/Damage -blocks.itemcapacity = Item Capacity -blocks.memorycapacity = Memory Capacity -blocks.basepowergeneration = Base Power Generation -blocks.productiontime = Production Time -blocks.repairtime = Block Full Repair Time -blocks.speedincrease = Speed Increase -blocks.range = Range -blocks.drilltier = Drillables -blocks.drillspeed = Base Drill Speed -blocks.boosteffect = Boost Effect -blocks.maxunits = Max Active Units -blocks.health = Health -blocks.buildtime = Build Time -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Build Cost -blocks.inaccuracy = Inaccuracy -blocks.shots = Shots -blocks.reload = Shots/Second -blocks.ammo = Ammo -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time + +stat.input = Input +stat.output = Output +stat.booster = Booster +stat.tiles = Required Tiles +stat.affinities = Affinities +stat.powercapacity = Power Capacity +stat.powershot = Power/Shot +stat.damage = Damage +stat.targetsair = Targets Air +stat.targetsground = Targets Ground +stat.itemsmoved = Move Speed +stat.launchtime = Time Between Launches +stat.shootrange = Range +stat.size = Size +stat.displaysize = Display Size +stat.liquidcapacity = Liquid Capacity +stat.powerrange = Power Range +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Power Use +stat.powerdamage = Power/Damage +stat.itemcapacity = Item Capacity +stat.memorycapacity = Memory Capacity +stat.basepowergeneration = Base Power Generation +stat.productiontime = Production Time +stat.repairtime = Block Full Repair Time +stat.speedincrease = Speed Increase +stat.range = Range +stat.drilltier = Drillables +stat.drillspeed = Base Drill Speed +stat.boosteffect = Boost Effect +stat.maxunits = Max Active Units +stat.health = Health +stat.buildtime = Build Time +stat.maxconsecutive = Max Consecutive +stat.buildcost = Build Cost +stat.inaccuracy = Inaccuracy +stat.shots = Shots +stat.reload = Shots/Second +stat.ammo = Ammo +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time +stat.explosiveness = Explosiveness +stat.basedeflectchance = Base Deflect Chance +stat.lightningchance = Lightning Chance +stat.lightningdamage = Lightning Damage +stat.flammability = Flammability +stat.radioactivity = Radioactivity +stat.heatcapacity = HeatCapacity +stat.viscosity = Viscosity +stat.temperature = Temperature +stat.speed = Speed +stat.buildspeed = Build Speed +stat.minespeed = Mine Speed +stat.minetier = Mine Tier +stat.payloadcapacity = Payload Capacity +stat.commandlimit = Command Limit +stat.abilities = Abilities + +ability.forcefield = Force Field +ability.repairfield = Repair Field +ability.statusfield = Status Field +ability.unitspawn = {0} Factory +ability.shieldregenfield = Shield Regen Field bar.drilltierreq = Better Drill Required bar.noresources = Missing Resources @@ -627,6 +667,7 @@ bar.powerbalance = Power: {0}/s bar.powerstored = Stored: {0}/{1} bar.poweramount = Power: {0} bar.poweroutput = Power Output: {0} +bar.powerlines = Connections: {0}/{1} bar.items = Items: {0} bar.capacity = Capacity: {0} bar.unitcap = {0} {1}/{2} @@ -638,6 +679,8 @@ bar.progress = Build Progress bar.input = Input bar.output = Output +units.processorcontrol = [lightgray]Processor Controlled + bullet.damage = [stat]{0}[lightgray] damage bullet.splashdamage = [stat]{0}[lightgray] area dmg ~[stat] {1}[lightgray] tiles bullet.incendiary = [stat]incendiary @@ -645,12 +688,15 @@ bullet.homing = [stat]homing bullet.shock = [stat]shock bullet.frag = [stat]frag bullet.knockback = [stat]{0}[lightgray] knockback +bullet.pierce = [stat]{0}[lightgray]x pierce +bullet.infinitepierce = [stat]pierce bullet.freezing = [stat]freezing bullet.tarred = [stat]tarred bullet.multiplier = [stat]{0}[lightgray]x ammo multiplier bullet.reload = [stat]{0}[lightgray]x fire rate unit.blocks = blocks +unit.blockssquared = blocks² unit.powersecond = power units/second unit.liquidsecond = liquid units/second unit.itemssecond = items/second @@ -682,7 +728,6 @@ setting.linear.name = Linear Filtering setting.hints.name = Hints setting.flow.name = Display Resource Flow Rate setting.buildautopause.name = Auto-Pause Building -setting.mapcenter.name = Auto Center Map To Player setting.animatedwater.name = Animated Fluids setting.animatedshields.name = Animated Shields setting.antialias.name = Antialias[lightgray] (requires restart)[] @@ -716,7 +761,6 @@ setting.fullscreen.name = Fullscreen setting.borderlesswindow.name = Borderless Window[lightgray] (restart may be required) setting.fps.name = Show FPS & Ping setting.smoothcamera.name = Smooth Camera -setting.blockselectkeys.name = Show Block Select Keys setting.vsync.name = VSync setting.pixelate.name = Pixelate setting.minimap.name = Show Minimap @@ -863,6 +907,7 @@ content.item.name = Items content.liquid.name = Liquids content.unit.name = Units content.block.name = Blocks + item.copper.name = Copper item.lead.name = Lead item.coal.name = Coal @@ -884,23 +929,6 @@ liquid.slag.name = Slag liquid.oil.name = Oil liquid.cryofluid.name = Cryofluid -item.explosiveness = [lightgray]Explosiveness: {0}% -item.flammability = [lightgray]Flammability: {0}% -item.radioactivity = [lightgray]Radioactivity: {0}% - -unit.health = [lightgray]Health: {0} -unit.speed = [lightgray]Speed: {0} -unit.weapon = [lightgray]Weapon: {0} -unit.itemcapacity = [lightgray]Item Capacity: {0} -unit.minespeed = [lightgray]Mining Speed: {0}% -unit.minepower = [lightgray]Mining Power: {0} -unit.ability = [lightgray]Ability: {0} -unit.buildspeed = [lightgray]Building Speed: {0}% - -liquid.heatcapacity = [lightgray]Heat Capacity: {0} -liquid.viscosity = [lightgray]Viscosity: {0} -liquid.temperature = [lightgray]Temperature: {0} - unit.dagger.name = Dagger unit.mace.name = Mace unit.fortress.name = Fortress @@ -941,6 +969,7 @@ block.cliff.name = Cliff block.sand-boulder.name = Sand Boulder block.grass.name = Grass block.slag.name = Slag +block.space.name = Space block.salt.name = Salt block.salt-wall.name = Salt Wall block.pebbles.name = Pebbles @@ -986,6 +1015,7 @@ block.darksand-water.name = Dark Sand Water block.char.name = Char block.dacite.name = Dacite block.dacite-wall.name = Dacite Wall +block.dacite-boulder.name = Dacite Boulder block.ice-snow.name = Ice Snow block.stone-wall.name = Stone Wall block.ice-wall.name = Ice Wall @@ -1259,7 +1289,7 @@ block.rotary-pump.description = An advanced pump. Pumps more liquid, but require block.thermal-pump.description = The ultimate pump. block.conduit.description = Basic liquid transport block. Moves liquids forward. Used in conjunction with pumps and other conduits. block.pulse-conduit.description = An advanced liquid transport block. Transports liquids faster and stores more than standard conduits. -block.plated-conduit.description = Moves liquids at the same rate as pulse conduits, but possesses more armor. Does not accept fluids from the sides by anything other than conduits.\nLeaks less. +block.plated-conduit.description = Moves liquids at the same rate as pulse conduits, but possesses more armor. Does not accept fluids from the sides by anything other than conduits.\nDoes not leak. block.liquid-router.description = Accepts liquids from one direction and outputs them to up to 3 other directions equally. Can also store a certain amount of liquid. Useful for splitting the liquids from one source to multiple targets. block.liquid-tank.description = Stores a large amount of liquids. Use for creating buffers in situations with non-constant demand of materials or as a safeguard for cooling vital blocks. block.liquid-junction.description = Acts as a bridge for two crossing conduits. Useful in situations with two different conduits carrying different liquids to different locations. @@ -1310,5 +1340,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets. block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. - +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_be.properties b/core/assets/bundles/bundle_be.properties index f62aba4377..590d8094f2 100644 --- a/core/assets/bundles/bundle_be.properties +++ b/core/assets/bundles/bundle_be.properties @@ -570,49 +570,49 @@ info.title = Інфармацыя error.title = [crimson]Адбылася памылка error.crashtitle = Адбылася памылка unit.nobuild = [scarlet]Unit can't build -blocks.input = Уваход -blocks.output = Выхад -blocks.booster = Паскаральнік -blocks.tiles = Неабходныя пліткі -blocks.affinities = Павелічэнне эфектыўнасці +stat.input = Уваход +stat.output = Выхад +stat.booster = Паскаральнік +stat.tiles = Неабходныя пліткі +stat.affinities = Павелічэнне эфектыўнасці block.unknown = [lightgray]??? -blocks.powercapacity = Умяшчальнасць энергіі -blocks.powershot = Энергія/Выстрэл -blocks.damage = Страты -blocks.targetsair = Паветраныя мэты -blocks.targetsground = Наземныя мэты -blocks.itemsmoved = Хуткасць перамяшчэння -blocks.launchtime = Інтэрвал запускаў -blocks.shootrange = Радыус дзеяння -blocks.size = Памер -blocks.displaysize = Display Size -blocks.liquidcapacity = Умяшчальнасць вадкасці -blocks.powerrange = Далёкасць перадачы энергіі -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Колькасць злучэнняў -blocks.poweruse = Спажывае энергіі -blocks.powerdamage = Энергія/страты -blocks.itemcapacity = Умяшчальнасць прадметаў -blocks.basepowergeneration = Базавая генерацыя энергіі -blocks.productiontime = Час вытворчасці -blocks.repairtime = Час поўнай рэгенерацыі -blocks.speedincrease = Павелічэнне хуткасці -blocks.range = Радыус дзеяння -blocks.drilltier = Бурит -blocks.drillspeed = Базавая хуткасць свідравання -blocks.boosteffect = паскараўся эфект -blocks.maxunits = Максімальная колькасць актыўных адзінак -blocks.health = Здароўе -blocks.buildtime = Час будаўніцтва -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Кошт будаўніцтва -blocks.inaccuracy = Роскід -blocks.shots = Стрэлы -blocks.reload = Стрэлы/секунду -blocks.ammo = Боепрыпасы -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Умяшчальнасць энергіі +stat.powershot = Энергія/Выстрэл +stat.damage = Страты +stat.targetsair = Паветраныя мэты +stat.targetsground = Наземныя мэты +stat.itemsmoved = Хуткасць перамяшчэння +stat.launchtime = Інтэрвал запускаў +stat.shootrange = Радыус дзеяння +stat.size = Памер +stat.displaysize = Display Size +stat.liquidcapacity = Умяшчальнасць вадкасці +stat.powerrange = Далёкасць перадачы энергіі +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Колькасць злучэнняў +stat.poweruse = Спажывае энергіі +stat.powerdamage = Энергія/страты +stat.itemcapacity = Умяшчальнасць прадметаў +stat.basepowergeneration = Базавая генерацыя энергіі +stat.productiontime = Час вытворчасці +stat.repairtime = Час поўнай рэгенерацыі +stat.speedincrease = Павелічэнне хуткасці +stat.range = Радыус дзеяння +stat.drilltier = Бурит +stat.drillspeed = Базавая хуткасць свідравання +stat.boosteffect = паскараўся эфект +stat.maxunits = Максімальная колькасць актыўных адзінак +stat.health = Здароўе +stat.buildtime = Час будаўніцтва +stat.maxconsecutive = Max Consecutive +stat.buildcost = Кошт будаўніцтва +stat.inaccuracy = Роскід +stat.shots = Стрэлы +stat.reload = Стрэлы/секунду +stat.ammo = Боепрыпасы +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Патрабуецца свідар лепей bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Вялікая турэль, якая можа ве block.spectre.description = Масіўная двуствольное гармата. Страляе буйнымі бранябойнымі кулямі па паветраных і наземных мэтах. block.meltdown.description = Масіўная лазерная гармата. Зараджае і страляе пастаянным лазерным прамянём ў бліжэйшых ворагаў. Патрабуецца астуджальная вадкасць для працы. block.repair-point.description = Бесперапынна лечыць бліжэйшую пашкоджаную баявую адзінку або мех у сваім радыусе. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index e0c66ff624..f9f98951dc 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -55,6 +55,7 @@ schematic.saved = Šablona byla uložena. schematic.delete.confirm = Šablona bude kompletně vyhlazena. schematic.rename = Přejmenovat šablonu schematic.info = {0}x{1}, {2} bloků +schematic.disabled = [scarlet]Šablony jsou zakázány[]\nNa této [accent]mapě[] nebo [accent]serveru[] nemůžeš používat šablony. stat.wave = Vln poraženo: [accent]{0} stat.enemiesDestroyed = Nepřátel zničeno: [accent]{0}[] @@ -346,6 +347,7 @@ waves.invalid = Neplatné vlny ve schránce. waves.copied = Vlny byly zkopírovány. waves.none = Žádní nepřátelé nebyli definováni.\nVlny s prázdným rozložením budou automaticky upraveny na výchozí rozložení. +#these are intentionally in lower case wavemode.counts = počty wavemode.totals = součty wavemode.health = zdraví @@ -471,22 +473,17 @@ requirement.wave = Dosáhni vlny {0} na mapě {1} requirement.core = Znič nepřátelské jádro na mapě {0} requirement.research = Vynalezeno {0} requirement.capture = Polapeno {0} -resume = Zpět do mapy:\n[lightgray]{0}[] bestwave = [lightgray]Nejvyšší vlna: {0} -launch = < VYSLAT > launch.text = Vyslat -launch.title = Vyslání bylo úspěšné -launch.next = [lightgray]další možnost bude až ve vlně {0}[] -launch.unable2 = [scarlet]Není možno se vyslat.[] -launch.confirm = Toto vyšle veškeré suroviny ve Tvém jádře zpět.\nJiž se na tuto základnu nebudeš moci vrátit. -launch.skip.confirm = Jestli teď zůstaneš, budeš moci odejít až po několika dalších vlnách. +campaign.multiplayer = Když hraješ kampaň ve hře více hráčů, můžeš vynalézat pouze pomocí věcí ze [accent]svých[] sektorů, [scarlet]ne[] ze sektoru hostitele, kde jsi právě teď.\n\nAbys získal věci do [accent]svých[] sektorů ve hře více hráčů, použij [accent]vysílací plošinu[]. uncover = Odkrýt mapu configure = Přizpůsobit vybavení +#TODO loadout = Načtení resources = Zdroje bannedblocks = Zakázané bloky addall = Přidat vše -launch.destination = Destination: {0} +launch.destination = Cíl: {0} configure.invalid = Hodnota musí být číslo mezi 0 a {0}. zone.unlocked = [lightgray]Mapa {0} byla odemknuta.[] zone.requirement.complete = Bylo dosaženo vlny {0},\nčímž byla splněna podmínka pro mapu {1}. @@ -519,9 +516,10 @@ sectors.production = Výroba: sectors.stored = Uskladněno: sectors.resume = Pokračovat sectors.launch = Vyslat -sectors.select = Select -sectors.nonelaunch = [lightgray]none (sun) +sectors.select = Vybrat +sectors.nonelaunch = [lightgray]žádné (slunce)[] +#NOTE TO TRANSLATORS: don't bother editing these, they'll be removed and/or rewritten anyway sector.groundZero.name = Základní tábor sector.craters.name = Krátery sector.frozenForest.name = Zamrzlý les @@ -534,6 +532,10 @@ sector.tarFields.name = Dehtová pole sector.saltFlats.name = Solné nížiny sector.fungalPass.name = Plísňový průsmyk +#unused +#sector.impact0078.name = Impact 0078 +#sector.crags.name = Crags + sector.groundZero.description = Optimální místo, kde znovu začít. Nízký výskyt nepřátel. Několik málo surovin.\nPosbírej co nejvíce olova a mědi.\nBěž dál. sector.frozenForest.description = Dokonce až sem, blízko hor, se dokázaly spóry rozrůst. Mráz je však nemůže zadržet navěky.\n\nPusť se do práce za pomocí energie. Stav spalovací generátory. Nauč se, jak používat opravovací věže. sector.saltFlats.description = Na okraji pouště leží Solné nížiny. V této lokaci se nachází jen několik málo surovin.\n\nNepřítel zde vybudoval zásobovací komplex. Znič jádro v jeho základně. Nenechej kámen na kameni. @@ -570,49 +572,50 @@ info.title = Informace error.title = [scarlet]Objevila se chyba[] error.crashtitle = Objevila se chyba unit.nobuild = [scarlet]Jednotka nemůže stavět -blocks.input = Vstup -blocks.output = Výstup -blocks.booster = Posilovač -blocks.tiles = Vyžadované dlaždice -blocks.affinities = Synergie +stat.input = Vstup +stat.output = Výstup +stat.booster = Posilovač +stat.tiles = Vyžadované dlaždice +stat.affinities = Synergie block.unknown = [lightgray]???[] -blocks.powercapacity = Kapacita energie -blocks.powershot = Energie na 1 výstřel -blocks.damage = Poškození -blocks.targetsair = Zaměřuje vzdušné jednotky -blocks.targetsground = Zaměřuje pozemní jednotky -blocks.itemsmoved = Rychlost pohybu -blocks.launchtime = Čas mezi vysláním -blocks.shootrange = Dostřel -blocks.size = Velikost -blocks.displaysize = Velikost zobrazovače -blocks.liquidcapacity = Kapacita kapalin -blocks.powerrange = Rozsah energie -blocks.linkrange = Dosah napojení -blocks.instructions = Instrukce -blocks.powerconnections = Nejvyšší počet spojení -blocks.poweruse = Spotřeba energie -blocks.powerdamage = Energie na jednotku poškození -blocks.itemcapacity = Kapacita předmětů -blocks.basepowergeneration = Základní generování energie -blocks.productiontime = Čas produkce -blocks.repairtime = Čas do úplné opravy -blocks.speedincrease = Zvýšení rychlosti -blocks.range = Dosah -blocks.drilltier = Lze těžit -blocks.drillspeed = Základní rychlost vrtu -blocks.boosteffect = Účinek posílení -blocks.maxunits = Nejvýše aktivních jednotek -blocks.health = Životy -blocks.buildtime = Čas stavby -blocks.maxconsecutive = Nejvýše po sobě -blocks.buildcost = Cena stavby -blocks.inaccuracy = Nepřesnost -blocks.shots = Střely -blocks.reload = Střel za 1s -blocks.ammo = Střelivo -blocks.shieldhealth = Zdraví štítu -blocks.cooldowntime = Čas na zchladnutí +stat.powercapacity = Kapacita energie +stat.powershot = Energie na 1 výstřel +stat.damage = Poškození +stat.targetsair = Zaměřuje vzdušné jednotky +stat.targetsground = Zaměřuje pozemní jednotky +stat.itemsmoved = Rychlost pohybu +stat.launchtime = Čas mezi vysláním +stat.shootrange = Dostřel +stat.size = Velikost +stat.displaysize = Velikost zobrazovače +stat.liquidcapacity = Kapacita kapalin +stat.powerrange = Rozsah energie +stat.linkrange = Dosah napojení +stat.instructions = Instrukce +stat.powerconnections = Nejvyšší počet spojení +stat.poweruse = Spotřeba energie +stat.powerdamage = Energie na jednotku poškození +stat.itemcapacity = Kapacita předmětů +stat.memorycapacity = Kapacita paměti +stat.basepowergeneration = Základní generování energie +stat.productiontime = Čas produkce +stat.repairtime = Čas do úplné opravy +stat.speedincrease = Zvýšení rychlosti +stat.range = Dosah +stat.drilltier = Lze těžit +stat.drillspeed = Základní rychlost vrtu +stat.boosteffect = Účinek posílení +stat.maxunits = Nejvýše aktivních jednotek +stat.health = Životy +stat.buildtime = Čas stavby +stat.maxconsecutive = Nejvýše po sobě +stat.buildcost = Cena stavby +stat.inaccuracy = Nepřesnost +stat.shots = Střely +stat.reload = Střel za 1s +stat.ammo = Střelivo +stat.shieldhealth = Zdraví štítu +stat.cooldowntime = Čas na zchladnutí bar.drilltierreq = Je vyžadován lepší vrt bar.noresources = Chybějí zdroje @@ -635,6 +638,8 @@ bar.progress = Stavba v průběhu bar.input = Vstup bar.output = Výstup +units.processorcontrol = [lightgray]Procesor je ovládán[] + bullet.damage = [stat]{0}[lightgray] poškození[] bullet.splashdamage = [stat]{0}[lightgray] plošného poškození ~[stat] {1}[lightgray] dlaždic bullet.incendiary = [stat]zápalné @@ -822,6 +827,7 @@ mode.custom = Vlastní pravidla rules.infiniteresources = Neomezeně surovin rules.reactorexplosions = Výbuch reaktoru +rules.schematic = Šablony povoleny rules.wavetimer = Časovač vln rules.waves = Vlny rules.attack = Režim útoku @@ -846,7 +852,8 @@ rules.title.enemy = Nepřátelé rules.title.unit = Jednotky rules.title.experimental = Experimentální rules.title.environment = Environmentální -rules.lighting = Světlo +rules.lighting = Osvětlení +rules.enemyLights = Světla nepřátel rules.fire = Výstřel rules.explosions = Výbušné poškození bloku/jednotky rules.ambientlight = Světlo prostředí @@ -915,8 +922,8 @@ unit.eclipse.name = Zatmění unit.mono.name = Mono unit.poly.name = Poly unit.mega.name = Mega -unit.quad.name = Quad -unit.oct.name = Oct +unit.quad.name = Tetra +unit.oct.name = Hexo unit.risso.name = Risso unit.minke.name = Minke unit.bryde.name = Bryde @@ -928,7 +935,7 @@ unit.gamma.name = Gama unit.scepter.name = Žezlo unit.reign.name = Panovník unit.vela.name = Vela -unit.corvus.name = Corvus +unit.corvus.name = Havran block.resupply-point.name = Zásobovací místo block.parallax.name = Paralaxa @@ -1076,6 +1083,7 @@ block.unloader.name = Odbavovač block.vault.name = Trezor block.wave.name = Vlna block.swarmer.name = Rojiště +block.tsunami.name = Tsunami block.salvo.name = Salva block.ripple.name = Vlnění block.phase-conveyor.name = Fázový přepravník @@ -1112,8 +1120,9 @@ block.overdrive-projector.name = Urychlující projektor block.force-projector.name = Silový projektor block.arc.name = Oblouk block.rtg-generator.name = RTG -block.spectre.name = Spectre -block.meltdown.name = Meltdown +block.spectre.name = Přízrak +block.meltdown.name = Rozpékač +block.foreshadow.name = Znamení osudu block.container.name = Kontejnér block.launch-pad.name = Vysílací plošina block.launch-pad-large.name = Velká vysílací plošina @@ -1139,6 +1148,7 @@ block.hyper-processor.name = Hyperprocesor block.logic-display.name = Zobrazovač logiky block.large-logic-display.name = Velký zobrazovač logiky block.memory-cell.name = Paměťová buňka +block.memory-bank.name = Paměťová banka team.blue.name = modrý team.crux.name = červený @@ -1302,4 +1312,4 @@ block.cyclone.description = Velká protiletecká a protipozemní střílna. Pál block.spectre.description = Velká střílna s kanónem s dvěma hlavněmi. Střílí velké náboje, které pronikají brněním jak pozemních, tak vzdušných nepřátelských cílů. block.meltdown.description = Masivní laserový kanón. Nabije se a pak pálí nepřetržitý laserový paprsek na nepřátele v okolí. Vyžaduje ke své funkci chlazení. block.repair-point.description = Nepřetržitě léčí nejbližší poškozenou jednotku v poli své působnosti. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_da.properties b/core/assets/bundles/bundle_da.properties index 0e9d2ce889..b65afebcd3 100644 --- a/core/assets/bundles/bundle_da.properties +++ b/core/assets/bundles/bundle_da.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [crimson]An error has occured error.crashtitle = An error has occured unit.nobuild = [scarlet]Unit can't build -blocks.input = Input -blocks.output = Output -blocks.booster = Booster -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Input +stat.output = Output +stat.booster = Booster +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Power Capacity -blocks.powershot = Power/Shot -blocks.damage = Damage -blocks.targetsair = Targets Air -blocks.targetsground = Targets Ground -blocks.itemsmoved = Move Speed -blocks.launchtime = Time Between Launches -blocks.shootrange = Range -blocks.size = Size -blocks.displaysize = Display Size -blocks.liquidcapacity = Liquid Capacity -blocks.powerrange = Power Range -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Power Use -blocks.powerdamage = Power/Damage -blocks.itemcapacity = Item Capacity -blocks.basepowergeneration = Base Power Generation -blocks.productiontime = Production Time -blocks.repairtime = Block Full Repair Time -blocks.speedincrease = Speed Increase -blocks.range = Range -blocks.drilltier = Drillables -blocks.drillspeed = Base Drill Speed -blocks.boosteffect = Boost Effect -blocks.maxunits = Max Active Units -blocks.health = Health -blocks.buildtime = Build Time -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Build Cost -blocks.inaccuracy = Inaccuracy -blocks.shots = Shots -blocks.reload = Shots/Second -blocks.ammo = Ammo -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Power Capacity +stat.powershot = Power/Shot +stat.damage = Damage +stat.targetsair = Targets Air +stat.targetsground = Targets Ground +stat.itemsmoved = Move Speed +stat.launchtime = Time Between Launches +stat.shootrange = Range +stat.size = Size +stat.displaysize = Display Size +stat.liquidcapacity = Liquid Capacity +stat.powerrange = Power Range +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Power Use +stat.powerdamage = Power/Damage +stat.itemcapacity = Item Capacity +stat.basepowergeneration = Base Power Generation +stat.productiontime = Production Time +stat.repairtime = Block Full Repair Time +stat.speedincrease = Speed Increase +stat.range = Range +stat.drilltier = Drillables +stat.drillspeed = Base Drill Speed +stat.boosteffect = Boost Effect +stat.maxunits = Max Active Units +stat.health = Health +stat.buildtime = Build Time +stat.maxconsecutive = Max Consecutive +stat.buildcost = Build Cost +stat.inaccuracy = Inaccuracy +stat.shots = Shots +stat.reload = Shots/Second +stat.ammo = Ammo +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Better Drill Required bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets. block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index 67311e3451..5d02ed2f85 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [crimson]Ein Fehler ist aufgetreten error.crashtitle = Ein Fehler ist aufgetreten! unit.nobuild = [scarlet]Einheit kann nicht bauen! -blocks.input = Eingang -blocks.output = Ausgang -blocks.booster = Verstärkung -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Eingang +stat.output = Ausgang +stat.booster = Verstärkung +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Kapazität -blocks.powershot = Stromverbrauch/Schuss -blocks.damage = Schaden -blocks.targetsair = Visiert Lufteinheiten an -blocks.targetsground = Visiert Bodeneinheiten an -blocks.itemsmoved = Bewegungsgeschwindigkeit -blocks.launchtime = Zeit zwischen Starts -blocks.shootrange = Reichweite -blocks.size = Größe -blocks.displaysize = Display Size -blocks.liquidcapacity = Flüssigkeitskapazität -blocks.powerrange = Stromreichweite -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Maximale Stromverbindungen -blocks.poweruse = Stromverbrauch -blocks.powerdamage = Stromverbrauch/Schadenspunkt -blocks.itemcapacity = Materialkapazität -blocks.basepowergeneration = Basis-Stromerzeugung -blocks.productiontime = Produktionszeit -blocks.repairtime = Zeit zur vollständigen Reparatur -blocks.speedincrease = Geschwindigkeitserhöhung -blocks.range = Reichweite -blocks.drilltier = Abbaubare Erze -blocks.drillspeed = Bohrgeschwindigkeit -blocks.boosteffect = Verstärkungseffekt -blocks.maxunits = Max. aktive Einheiten -blocks.health = Lebenspunkte -blocks.buildtime = Baudauer -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Baukosten -blocks.inaccuracy = Ungenauigkeit -blocks.shots = Schüsse -blocks.reload = Schüsse/Sekunde -blocks.ammo = Munition -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Kapazität +stat.powershot = Stromverbrauch/Schuss +stat.damage = Schaden +stat.targetsair = Visiert Lufteinheiten an +stat.targetsground = Visiert Bodeneinheiten an +stat.itemsmoved = Bewegungsgeschwindigkeit +stat.launchtime = Zeit zwischen Starts +stat.shootrange = Reichweite +stat.size = Größe +stat.displaysize = Display Size +stat.liquidcapacity = Flüssigkeitskapazität +stat.powerrange = Stromreichweite +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Maximale Stromverbindungen +stat.poweruse = Stromverbrauch +stat.powerdamage = Stromverbrauch/Schadenspunkt +stat.itemcapacity = Materialkapazität +stat.basepowergeneration = Basis-Stromerzeugung +stat.productiontime = Produktionszeit +stat.repairtime = Zeit zur vollständigen Reparatur +stat.speedincrease = Geschwindigkeitserhöhung +stat.range = Reichweite +stat.drilltier = Abbaubare Erze +stat.drillspeed = Bohrgeschwindigkeit +stat.boosteffect = Verstärkungseffekt +stat.maxunits = Max. aktive Einheiten +stat.health = Lebenspunkte +stat.buildtime = Baudauer +stat.maxconsecutive = Max Consecutive +stat.buildcost = Baukosten +stat.inaccuracy = Ungenauigkeit +stat.shots = Schüsse +stat.reload = Schüsse/Sekunde +stat.ammo = Munition +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Besserer Bohrer Benötigt bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Ein großer Schnellfeuer-Geschützturm. block.spectre.description = Ein großer Geschützturm, der zwei starke Schüsse gleichzeitig abfeuert. block.meltdown.description = Ein großer Geschützturm, der starke Strahlen mit großer Reichweite abfeuert. block.repair-point.description = Heilt durchgehend die nächste befreundete, beschädigte Einheit in der Umgebung. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index 8c538a6974..6c24039d7e 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -2,14 +2,14 @@ credits.text = Creado por [royal]Anuken[] - [sky]anukendev@gmail.com[] credits = Créditos contributors = Traductores y Contribuidores discord = ¡Únete al Discord de Mindustry! -link.discord.description = La sala oficial del Discord de Mindustry +link.discord.description = El servidor official de Discord de Mindustry link.reddit.description = El subreddit de Mindustry link.github.description = Código fuente del juego link.changelog.description = Lista de actualizaciones -link.dev-builds.description = Versiones de desarrollo inestables +link.dev-builds.description = Versiones en desarrollo inestables link.trello.description = Tablero de Trello oficial para las características planificadas link.itch.io.description = itch.io es la página donde podes descargar las versiones para PC y web -link.google-play.description = Ficha en la Google Play Store +link.google-play.description = Página de Mindustry en Google Play Store link.f-droid.description = Página de F-Droid del juego link.wiki.description = Wiki oficial de Mindustry link.suggestions.description = Sugerir nuevas funciones @@ -18,7 +18,7 @@ screenshot = Captura de pantalla guardada en {0} screenshot.invalid = Mapa demasiado grande, no hay suficiente memoria para la captura de pantalla. gameover = Tu núcleo ha sido destruido. gameover.pvp = ¡El equipo[accent] {0}[] ha ganado! -highscore = [accent]¡Nueva mejor puntuación! +highscore = [accent]¡Nuevo récord de puntuación! copied = Copiado. indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[]. indev.notready = This part of the game isn't ready yet @@ -38,12 +38,12 @@ be.ignore = Ignorar be.noupdates = No se encontraron actualizaciones. be.check = Revisando actualizaciones -schematic = Esquemático -schematic.add = Guardar esquemático... -schematics = Esquemáticos -schematic.replace = Un esquemático con ese nombre ya existe. ¿Deseas remplazarlo? -schematic.exists = Un esquemático con ese nombre ya existe. -schematic.import = Importar esquemático... +schematic = Esquema +schematic.add = Guardar esquema... +schematics = Esquemas +schematic.replace = Un esquema con ese nombre ya existe. ¿Deseas remplazarlo? +schematic.exists = Un esquema con ese nombre ya existe. +schematic.import = Importar esquema... schematic.exportfile = Exportar archivo schematic.importfile = Importar archivo schematic.browseworkshop = Buscar en el Steam Workshop @@ -570,49 +570,49 @@ info.title = [accent]Información error.title = [crimson]Un error ha ocurrido. error.crashtitle = Un error ha ocurrido. unit.nobuild = [scarlet]Unit can't build -blocks.input = Entrada -blocks.output = Salida -blocks.booster = Potenciador -blocks.tiles = Tiles requeridos -blocks.affinities = Afinidades +stat.input = Entrada +stat.output = Salida +stat.booster = Potenciador +stat.tiles = Tiles requeridos +stat.affinities = Afinidades block.unknown = [lightgray]??? -blocks.powercapacity = Capacidad de Energía -blocks.powershot = Energía/Disparo -blocks.damage = Daño -blocks.targetsair = Apunta al Aire -blocks.targetsground = Apunta a Tierra -blocks.itemsmoved = Velocidad de movimiento -blocks.launchtime = Tiempo entre lanzamientos -blocks.shootrange = Rango de Disparo -blocks.size = Tamaño -blocks.displaysize = Display Size -blocks.liquidcapacity = Capacidad de Líquidos -blocks.powerrange = Rango de Energía -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Conexiones maximas -blocks.poweruse = Consumo de Energía -blocks.powerdamage = Energía/Daño -blocks.itemcapacity = Capacidad de Objetos -blocks.basepowergeneration = Generación de energía base -blocks.productiontime = Tiempo de producción -blocks.repairtime = Tiempo para Reparar Bloque Completamente -blocks.speedincrease = Aumento de Velocidad -blocks.range = Rango -blocks.drilltier = Taladrables -blocks.drillspeed = Velocidad Base del Taladro -blocks.boosteffect = Efecto del Potenciador -blocks.maxunits = Máximo de Unidades Activas -blocks.health = Vida -blocks.buildtime = Tiempo de construcción -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Coste de construcción -blocks.inaccuracy = Imprecisión -blocks.shots = Disparos -blocks.reload = Recarga -blocks.ammo = Munición -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Capacidad de Energía +stat.powershot = Energía/Disparo +stat.damage = Daño +stat.targetsair = Apunta al Aire +stat.targetsground = Apunta a Tierra +stat.itemsmoved = Velocidad de movimiento +stat.launchtime = Tiempo entre lanzamientos +stat.shootrange = Rango de Disparo +stat.size = Tamaño +stat.displaysize = Display Size +stat.liquidcapacity = Capacidad de Líquidos +stat.powerrange = Rango de Energía +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Conexiones maximas +stat.poweruse = Consumo de Energía +stat.powerdamage = Energía/Daño +stat.itemcapacity = Capacidad de Objetos +stat.basepowergeneration = Generación de energía base +stat.productiontime = Tiempo de producción +stat.repairtime = Tiempo para Reparar Bloque Completamente +stat.speedincrease = Aumento de Velocidad +stat.range = Rango +stat.drilltier = Taladrables +stat.drillspeed = Velocidad Base del Taladro +stat.boosteffect = Efecto del Potenciador +stat.maxunits = Máximo de Unidades Activas +stat.health = Vida +stat.buildtime = Tiempo de construcción +stat.maxconsecutive = Max Consecutive +stat.buildcost = Coste de construcción +stat.inaccuracy = Imprecisión +stat.shots = Disparos +stat.reload = Recarga +stat.ammo = Munición +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Se requiere un mejor taladro. bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Una torre grande anti-aérea y anti-terrestre. Dispa block.spectre.description = Un cañon masivo de dos barriles. Dispara balas perforantes a objetivos de aire y tierra. block.meltdown.description = Un cañon láser masivo. Carga y dispara un rayo láser constante a enemigos cercanos. Requiere enfriamiento para operar. block.repair-point.description = Repara la unidad dañada más cercana a su alrededor. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_et.properties b/core/assets/bundles/bundle_et.properties index d5ac8cfb74..62b0002df6 100644 --- a/core/assets/bundles/bundle_et.properties +++ b/core/assets/bundles/bundle_et.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [crimson]Viga error.crashtitle = Viga unit.nobuild = [scarlet]Unit can't build -blocks.input = Sisend -blocks.output = Väljund -blocks.booster = Kiirendaja -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Sisend +stat.output = Väljund +stat.booster = Kiirendaja +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Energiamahtuvus -blocks.powershot = Energia ühikut/lasu kohta -blocks.damage = Hävituspunkte -blocks.targetsair = Sihib õhku -blocks.targetsground = Sihib maapinnale -blocks.itemsmoved = Transportimise kiirus -blocks.launchtime = Aeg lendutõusude vahel -blocks.shootrange = Ulatus -blocks.size = Suurus -blocks.displaysize = Display Size -blocks.liquidcapacity = Vedelike mahutavus -blocks.powerrange = Energia ulatus -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Energiatarve -blocks.powerdamage = Energiatarve hävituspunkti kohta -blocks.itemcapacity = Ressursside mahutavus -blocks.basepowergeneration = Energiatootlus -blocks.productiontime = Tootmisaeg -blocks.repairtime = Täieliku parandamise aeg -blocks.speedincrease = Kiiruse suurenemine -blocks.range = Ulatus -blocks.drilltier = Kaevandatav -blocks.drillspeed = Puurimise kiirus -blocks.boosteffect = Kiirendaja mõju -blocks.maxunits = Maks. aktiivseid väeüksuseid -blocks.health = Elud -blocks.buildtime = Ehitamise aeg -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Ehitamise maksumus -blocks.inaccuracy = Ebatäpsus -blocks.shots = Laske -blocks.reload = Lasku/s -blocks.ammo = Laskemoon -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Energiamahtuvus +stat.powershot = Energia ühikut/lasu kohta +stat.damage = Hävituspunkte +stat.targetsair = Sihib õhku +stat.targetsground = Sihib maapinnale +stat.itemsmoved = Transportimise kiirus +stat.launchtime = Aeg lendutõusude vahel +stat.shootrange = Ulatus +stat.size = Suurus +stat.displaysize = Display Size +stat.liquidcapacity = Vedelike mahutavus +stat.powerrange = Energia ulatus +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Energiatarve +stat.powerdamage = Energiatarve hävituspunkti kohta +stat.itemcapacity = Ressursside mahutavus +stat.basepowergeneration = Energiatootlus +stat.productiontime = Tootmisaeg +stat.repairtime = Täieliku parandamise aeg +stat.speedincrease = Kiiruse suurenemine +stat.range = Ulatus +stat.drilltier = Kaevandatav +stat.drillspeed = Puurimise kiirus +stat.boosteffect = Kiirendaja mõju +stat.maxunits = Maks. aktiivseid väeüksuseid +stat.health = Elud +stat.buildtime = Ehitamise aeg +stat.maxconsecutive = Max Consecutive +stat.buildcost = Ehitamise maksumus +stat.inaccuracy = Ebatäpsus +stat.shots = Laske +stat.reload = Lasku/s +stat.ammo = Laskemoon +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Nõuab paremat puuri bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Suur lendavate ja maapealsete väeüksuste vastane k block.spectre.description = Massiivne kaheraudne kahur, mis tulistab soomuskatteid läbistavaid mürske nii lendavate kui ka maapealsete väeüksuste pihta. block.meltdown.description = Massiivne laserkahur, mis tekitab püsiva energiakiire. Vajab töötamiseks jahutusvedelikku. block.repair-point.description = Parandab kõige lähemal asuvat liitlaste väeüksust. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_eu.properties b/core/assets/bundles/bundle_eu.properties index 5ef1a41b71..7afde97031 100644 --- a/core/assets/bundles/bundle_eu.properties +++ b/core/assets/bundles/bundle_eu.properties @@ -570,49 +570,49 @@ info.title = Informazioa error.title = [crimson]Errore bat gertatu da error.crashtitle = Errore bat gertatu da unit.nobuild = [scarlet]Unit can't build -blocks.input = Sarrera -blocks.output = Irteera -blocks.booster = Indargarria -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Sarrera +stat.output = Irteera +stat.booster = Indargarria +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Energia-edukiera -blocks.powershot = Energia/tiroko -blocks.damage = Kaltea -blocks.targetsair = Airera tirokatzen du -blocks.targetsground = Lurrera tirokatzen du -blocks.itemsmoved = Garraio-abiadura -blocks.launchtime = Egozketen arteko denbora -blocks.shootrange = Irismena -blocks.size = Neurria -blocks.displaysize = Display Size -blocks.liquidcapacity = Likido-edukiera -blocks.powerrange = Energia irismena -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Gehieneko konexioak -blocks.poweruse = Energia-erabilera -blocks.powerdamage = Energia/Kaltea -blocks.itemcapacity = Elementu-edukiera -blocks.basepowergeneration = Oinarrizko energia sorrera -blocks.productiontime = Eraikitze denbora -blocks.repairtime = Blokearen konpontze denbora osoa -blocks.speedincrease = Abiadura areagotzea -blocks.range = Irismena -blocks.drilltier = Ustiagarriak -blocks.drillspeed = Oinarrizko ustiatze-abiadura -blocks.boosteffect = Indartze-efektua -blocks.maxunits = Gehieneko unitate aktiboak -blocks.health = Osasuna -blocks.buildtime = Eraikitze-denbora -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Eraikitze-kostua -blocks.inaccuracy = Zehazgabetasuna -blocks.shots = Tiroak -blocks.reload = Tiroak/segundoko -blocks.ammo = Munizioa -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Energia-edukiera +stat.powershot = Energia/tiroko +stat.damage = Kaltea +stat.targetsair = Airera tirokatzen du +stat.targetsground = Lurrera tirokatzen du +stat.itemsmoved = Garraio-abiadura +stat.launchtime = Egozketen arteko denbora +stat.shootrange = Irismena +stat.size = Neurria +stat.displaysize = Display Size +stat.liquidcapacity = Likido-edukiera +stat.powerrange = Energia irismena +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Gehieneko konexioak +stat.poweruse = Energia-erabilera +stat.powerdamage = Energia/Kaltea +stat.itemcapacity = Elementu-edukiera +stat.basepowergeneration = Oinarrizko energia sorrera +stat.productiontime = Eraikitze denbora +stat.repairtime = Blokearen konpontze denbora osoa +stat.speedincrease = Abiadura areagotzea +stat.range = Irismena +stat.drilltier = Ustiagarriak +stat.drillspeed = Oinarrizko ustiatze-abiadura +stat.boosteffect = Indartze-efektua +stat.maxunits = Gehieneko unitate aktiboak +stat.health = Osasuna +stat.buildtime = Eraikitze-denbora +stat.maxconsecutive = Max Consecutive +stat.buildcost = Eraikitze-kostua +stat.inaccuracy = Zehazgabetasuna +stat.shots = Tiroak +stat.reload = Tiroak/segundoko +stat.ammo = Munizioa +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Zulagailu hobea behar da bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Aire zein lurreko defentsarako dorre handia. Torpedo block.spectre.description = Kanoi bikoitz erraldoia. Blindajea zulatu dezaketen bala handiak tirokatzen ditu aireko zein lurreko xedeei. block.meltdown.description = Laser kanoi erraldoia. Etengabeko laser izpi bat kargatu eta jauritzen die inguruko etsaiei. Hozgarria behar du jarduteko. block.repair-point.description = Etengabe konpontzen du inguruko kaltetutako unitate hurbilena. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_fi.properties b/core/assets/bundles/bundle_fi.properties index ae351b8764..30a231333c 100644 --- a/core/assets/bundles/bundle_fi.properties +++ b/core/assets/bundles/bundle_fi.properties @@ -570,49 +570,49 @@ info.title = Informaatio error.title = [crimson]An error has occured error.crashtitle = An error has occured unit.nobuild = [scarlet]Unit can't build -blocks.input = Sisääntulo -blocks.output = Ulostulo -blocks.booster = Tehostaja -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Sisääntulo +stat.output = Ulostulo +stat.booster = Tehostaja +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Energiakapasiteetti -blocks.powershot = Energiaa/Ammus -blocks.damage = Vahinko -blocks.targetsair = Hyökkää ilmaan -blocks.targetsground = Hyökkää maahan -blocks.itemsmoved = Liikkumisnopeus -blocks.launchtime = Aika laukaisujen välillä -blocks.shootrange = Kantama -blocks.size = Koko -blocks.displaysize = Display Size -blocks.liquidcapacity = Nestekapasiteetti -blocks.powerrange = Energiakantama -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Maksimimäärä yhdistyksiä -blocks.poweruse = Energian käyttö -blocks.powerdamage = Energia/Vahinko -blocks.itemcapacity = Tavarakapasiteetti -blocks.basepowergeneration = Perus energiantuotto -blocks.productiontime = Tuotantoaika -blocks.repairtime = Kokonaisen palikan korjausaika -blocks.speedincrease = Nopeuden kasvu -blocks.range = Etäisyys -blocks.drilltier = Porattavat -blocks.drillspeed = Kanta Poran Nopeus -blocks.boosteffect = Tehostamisem vaikutus -blocks.maxunits = Maksimimäärä yksikköjä -blocks.health = Elämäpisteet -blocks.buildtime = Rakentamisaika -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Rakentamishinta -blocks.inaccuracy = Epätarkkuus -blocks.shots = Ammusta -blocks.reload = Ammusta/sekunnissa -blocks.ammo = Ammus -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Energiakapasiteetti +stat.powershot = Energiaa/Ammus +stat.damage = Vahinko +stat.targetsair = Hyökkää ilmaan +stat.targetsground = Hyökkää maahan +stat.itemsmoved = Liikkumisnopeus +stat.launchtime = Aika laukaisujen välillä +stat.shootrange = Kantama +stat.size = Koko +stat.displaysize = Display Size +stat.liquidcapacity = Nestekapasiteetti +stat.powerrange = Energiakantama +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Maksimimäärä yhdistyksiä +stat.poweruse = Energian käyttö +stat.powerdamage = Energia/Vahinko +stat.itemcapacity = Tavarakapasiteetti +stat.basepowergeneration = Perus energiantuotto +stat.productiontime = Tuotantoaika +stat.repairtime = Kokonaisen palikan korjausaika +stat.speedincrease = Nopeuden kasvu +stat.range = Etäisyys +stat.drilltier = Porattavat +stat.drillspeed = Kanta Poran Nopeus +stat.boosteffect = Tehostamisem vaikutus +stat.maxunits = Maksimimäärä yksikköjä +stat.health = Elämäpisteet +stat.buildtime = Rakentamisaika +stat.maxconsecutive = Max Consecutive +stat.buildcost = Rakentamishinta +stat.inaccuracy = Epätarkkuus +stat.shots = Ammusta +stat.reload = Ammusta/sekunnissa +stat.ammo = Ammus +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Parempi pora vaadittu bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets. block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_fil.properties b/core/assets/bundles/bundle_fil.properties index 86c3c0737a..0fa6608526 100644 --- a/core/assets/bundles/bundle_fil.properties +++ b/core/assets/bundles/bundle_fil.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [scarlet]An error has occured error.crashtitle = An error has occured unit.nobuild = [scarlet]Unit can't build -blocks.input = Input -blocks.output = Output -blocks.booster = Booster -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Input +stat.output = Output +stat.booster = Booster +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Power Capacity -blocks.powershot = Power/Shot -blocks.damage = Damage -blocks.targetsair = Targets Air -blocks.targetsground = Targets Ground -blocks.itemsmoved = Move Speed -blocks.launchtime = Time Between Launches -blocks.shootrange = Range -blocks.size = Size -blocks.displaysize = Display Size -blocks.liquidcapacity = Liquid Capacity -blocks.powerrange = Power Range -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Power Use -blocks.powerdamage = Power/Damage -blocks.itemcapacity = Item Capacity -blocks.basepowergeneration = Base Power Generation -blocks.productiontime = Production Time -blocks.repairtime = Block Full Repair Time -blocks.speedincrease = Speed Increase -blocks.range = Range -blocks.drilltier = Drillables -blocks.drillspeed = Base Drill Speed -blocks.boosteffect = Boost Effect -blocks.maxunits = Max Active Units -blocks.health = Health -blocks.buildtime = Build Time -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Build Cost -blocks.inaccuracy = Inaccuracy -blocks.shots = Shots -blocks.reload = Shots/Second -blocks.ammo = Ammo -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Power Capacity +stat.powershot = Power/Shot +stat.damage = Damage +stat.targetsair = Targets Air +stat.targetsground = Targets Ground +stat.itemsmoved = Move Speed +stat.launchtime = Time Between Launches +stat.shootrange = Range +stat.size = Size +stat.displaysize = Display Size +stat.liquidcapacity = Liquid Capacity +stat.powerrange = Power Range +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Power Use +stat.powerdamage = Power/Damage +stat.itemcapacity = Item Capacity +stat.basepowergeneration = Base Power Generation +stat.productiontime = Production Time +stat.repairtime = Block Full Repair Time +stat.speedincrease = Speed Increase +stat.range = Range +stat.drilltier = Drillables +stat.drillspeed = Base Drill Speed +stat.boosteffect = Boost Effect +stat.maxunits = Max Active Units +stat.health = Health +stat.buildtime = Build Time +stat.maxconsecutive = Max Consecutive +stat.buildcost = Build Cost +stat.inaccuracy = Inaccuracy +stat.shots = Shots +stat.reload = Shots/Second +stat.ammo = Ammo +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Better Drill Required bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets. block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_fr.properties b/core/assets/bundles/bundle_fr.properties index e7749d7347..925465c595 100644 --- a/core/assets/bundles/bundle_fr.properties +++ b/core/assets/bundles/bundle_fr.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [crimson]Une erreur s'est produite error.crashtitle = Une erreur s'est produite unit.nobuild = [scarlet]Cette unité ne peut construire -blocks.input = Entrée -blocks.output = Sortie -blocks.booster = Booster -blocks.tiles = Pré-requis -blocks.affinities = Affinités +stat.input = Entrée +stat.output = Sortie +stat.booster = Booster +stat.tiles = Pré-requis +stat.affinities = Affinités block.unknown = [lightgray]??? -blocks.powercapacity = Capacité d'énergie -blocks.powershot = Énergie/Tir -blocks.damage = Dégâts -blocks.targetsair = Cibles Aériennes -blocks.targetsground = Cibles Terrestres -blocks.itemsmoved = Vitesse de Déplacement -blocks.launchtime = Temps entre chaque lancement -blocks.shootrange = Portée de tir -blocks.size = Taille -blocks.displaysize = Display Size -blocks.liquidcapacity = Capacité liquide -blocks.powerrange = Portée électrique -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Nombre maximal de connections -blocks.poweruse = Énergie utilisée -blocks.powerdamage = Dégâts d'énergie -blocks.itemcapacity = Stockage -blocks.basepowergeneration = Production d'énergie -blocks.productiontime = Durée de production -blocks.repairtime = Durée de réparation complète du Bloc -blocks.speedincrease = Accélération -blocks.range = Portée -blocks.drilltier = Forable -blocks.drillspeed = Vitesse de forage de base -blocks.boosteffect = Effet du Boost -blocks.maxunits = Unités actives max -blocks.health = Santé -blocks.buildtime = Durée de construction -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Coût de construction -blocks.inaccuracy = Imprécision -blocks.shots = Tirs -blocks.reload = Tirs/Seconde -blocks.ammo = Munitions -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Capacité d'énergie +stat.powershot = Énergie/Tir +stat.damage = Dégâts +stat.targetsair = Cibles Aériennes +stat.targetsground = Cibles Terrestres +stat.itemsmoved = Vitesse de Déplacement +stat.launchtime = Temps entre chaque lancement +stat.shootrange = Portée de tir +stat.size = Taille +stat.displaysize = Display Size +stat.liquidcapacity = Capacité liquide +stat.powerrange = Portée électrique +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Nombre maximal de connections +stat.poweruse = Énergie utilisée +stat.powerdamage = Dégâts d'énergie +stat.itemcapacity = Stockage +stat.basepowergeneration = Production d'énergie +stat.productiontime = Durée de production +stat.repairtime = Durée de réparation complète du Bloc +stat.speedincrease = Accélération +stat.range = Portée +stat.drilltier = Forable +stat.drillspeed = Vitesse de forage de base +stat.boosteffect = Effet du Boost +stat.maxunits = Unités actives max +stat.health = Santé +stat.buildtime = Durée de construction +stat.maxconsecutive = Max Consecutive +stat.buildcost = Coût de construction +stat.inaccuracy = Imprécision +stat.shots = Tirs +stat.reload = Tirs/Seconde +stat.ammo = Munitions +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Meilleure Foreuse Requise bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Une grande tourelle qui tire rapidement des débris block.spectre.description = Une tourelle massive à double cannon et qui tire de puissantes balles perce-blindages simultanément. block.meltdown.description = Une tourelle massive chargeant et tirant de puissants rayons lasers. Nécessite un liquide de refroidissement. block.repair-point.description = Soigne en permanence l'unité endommagée la plus proche à proximité. -block.segment.description = Endommage et détruit les tirs ennemis. Cependant, les lasers ne peuvent pas être ciblés. +block.segment.description = Endommage et détruit les tirs ennemis. Cependant, les lasers ne peuvent pas être ciblés. \ No newline at end of file diff --git a/core/assets/bundles/bundle_fr_BE.properties b/core/assets/bundles/bundle_fr_BE.properties index 02fe5e58b1..869da14c46 100644 --- a/core/assets/bundles/bundle_fr_BE.properties +++ b/core/assets/bundles/bundle_fr_BE.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [crimson]Une erreur s'est produite error.crashtitle = Une erreur s'est produite unit.nobuild = [scarlet]Unit can't build -blocks.input = Ressource(s) requise(s) -blocks.output = Ressource(s) produite(s) -blocks.booster = Booster -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Ressource(s) requise(s) +stat.output = Ressource(s) produite(s) +stat.booster = Booster +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]Inconnu -blocks.powercapacity = Capacité d'énergie -blocks.powershot = Énergie/Tir -blocks.damage = Damage -blocks.targetsair = Cible les unités aériennes -blocks.targetsground = Cible les unités terrestres -blocks.itemsmoved = Vitesse de déplacement -blocks.launchtime = Temps entre chaque lancement -blocks.shootrange = Portée -blocks.size = Taille -blocks.displaysize = Display Size -blocks.liquidcapacity = Capacité en liquide -blocks.powerrange = Distance de transmission -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Énergie utilisée -blocks.powerdamage = Énergie/Dégâts -blocks.itemcapacity = Stockage -blocks.basepowergeneration = Production d'énergie de base -blocks.productiontime = Temps de production -blocks.repairtime = Temps pour la réparation totale du bloc -blocks.speedincrease = Augmentation de la vitesse -blocks.range = Portée -blocks.drilltier = Forable -blocks.drillspeed = Vitesse de forage de base -blocks.boosteffect = Effet boostant -blocks.maxunits = Maximum d'unitée active -blocks.health = Santé -blocks.buildtime = Temps de construction -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Coût de construction -blocks.inaccuracy = Précision -blocks.shots = Tirs -blocks.reload = Tirs/Seconde -blocks.ammo = Munition -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Capacité d'énergie +stat.powershot = Énergie/Tir +stat.damage = Damage +stat.targetsair = Cible les unités aériennes +stat.targetsground = Cible les unités terrestres +stat.itemsmoved = Vitesse de déplacement +stat.launchtime = Temps entre chaque lancement +stat.shootrange = Portée +stat.size = Taille +stat.displaysize = Display Size +stat.liquidcapacity = Capacité en liquide +stat.powerrange = Distance de transmission +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Énergie utilisée +stat.powerdamage = Énergie/Dégâts +stat.itemcapacity = Stockage +stat.basepowergeneration = Production d'énergie de base +stat.productiontime = Temps de production +stat.repairtime = Temps pour la réparation totale du bloc +stat.speedincrease = Augmentation de la vitesse +stat.range = Portée +stat.drilltier = Forable +stat.drillspeed = Vitesse de forage de base +stat.boosteffect = Effet boostant +stat.maxunits = Maximum d'unitée active +stat.health = Santé +stat.buildtime = Temps de construction +stat.maxconsecutive = Max Consecutive +stat.buildcost = Coût de construction +stat.inaccuracy = Précision +stat.shots = Tirs +stat.reload = Tirs/Seconde +stat.ammo = Munition +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Better Drill Required bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Une grande tourelle à tir rapide. block.spectre.description = Une grande tourelle qui tire deux balles puissantes à la fois. block.meltdown.description = Une grande tourelle qui tire de puissants faisceaux à longue portée. block.repair-point.description = Soigne en permanence l'unité endommagée la plus proche à proximité. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_hu.properties b/core/assets/bundles/bundle_hu.properties index b28d471cdd..c24c9a24ee 100644 --- a/core/assets/bundles/bundle_hu.properties +++ b/core/assets/bundles/bundle_hu.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [crimson]An error has occured error.crashtitle = An error has occured unit.nobuild = [scarlet]Unit can't build -blocks.input = Input -blocks.output = Output -blocks.booster = Booster -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Input +stat.output = Output +stat.booster = Booster +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Power Capacity -blocks.powershot = Power/Shot -blocks.damage = Damage -blocks.targetsair = Targets Air -blocks.targetsground = Targets Ground -blocks.itemsmoved = Move Speed -blocks.launchtime = Time Between Launches -blocks.shootrange = Range -blocks.size = Size -blocks.displaysize = Display Size -blocks.liquidcapacity = Liquid Capacity -blocks.powerrange = Power Range -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Power Use -blocks.powerdamage = Power/Damage -blocks.itemcapacity = Item Capacity -blocks.basepowergeneration = Base Power Generation -blocks.productiontime = Production Time -blocks.repairtime = Block Full Repair Time -blocks.speedincrease = Speed Increase -blocks.range = Range -blocks.drilltier = Drillables -blocks.drillspeed = Base Drill Speed -blocks.boosteffect = Boost Effect -blocks.maxunits = Max Active Units -blocks.health = Health -blocks.buildtime = Build Time -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Build Cost -blocks.inaccuracy = Inaccuracy -blocks.shots = Shots -blocks.reload = Shots/Second -blocks.ammo = Ammo -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Power Capacity +stat.powershot = Power/Shot +stat.damage = Damage +stat.targetsair = Targets Air +stat.targetsground = Targets Ground +stat.itemsmoved = Move Speed +stat.launchtime = Time Between Launches +stat.shootrange = Range +stat.size = Size +stat.displaysize = Display Size +stat.liquidcapacity = Liquid Capacity +stat.powerrange = Power Range +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Power Use +stat.powerdamage = Power/Damage +stat.itemcapacity = Item Capacity +stat.basepowergeneration = Base Power Generation +stat.productiontime = Production Time +stat.repairtime = Block Full Repair Time +stat.speedincrease = Speed Increase +stat.range = Range +stat.drilltier = Drillables +stat.drillspeed = Base Drill Speed +stat.boosteffect = Boost Effect +stat.maxunits = Max Active Units +stat.health = Health +stat.buildtime = Build Time +stat.maxconsecutive = Max Consecutive +stat.buildcost = Build Cost +stat.inaccuracy = Inaccuracy +stat.shots = Shots +stat.reload = Shots/Second +stat.ammo = Ammo +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Better Drill Required bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets. block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_in_ID.properties b/core/assets/bundles/bundle_in_ID.properties index 32aabb9eb5..e9f6f933eb 100644 --- a/core/assets/bundles/bundle_in_ID.properties +++ b/core/assets/bundles/bundle_in_ID.properties @@ -20,22 +20,22 @@ gameover = Permainan Habis gameover.pvp = Tim[accent] {0}[] menang! highscore = [accent]Rekor Baru! copied = Tersalin. -indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[]. -indev.notready = This part of the game isn't ready yet +indevpopup = [accent]v6[] saat ini dalam versi [accent]alpha[].\n[lightgray]Artinya:[]\n[scarlet]- Kampanye belum sepenuhnya selesai[]\n- Beberapa konten tidak tersedia\n - Beberapa [scarlet]Unit AI[] tidak sepenuhnya bekerja\n- Beberapa unit belum sepenuhnya selesai\n- Semua yang kamu lihat dapat berubah atau dihapus sewaktu-waktu.\n\nLaporkan bug atau crash di [accent]Github[]. +indev.notready = Bagian tersebut saat ini belum siap load.sound = Suara load.map = Peta load.image = Gambar load.content = Konten load.system = Sistem -load.mod = Mods +load.mod = Mod load.scripts = Skrip be.update = Versi Bleeding Edge terbaru tersedia: be.update.confirm = Unduh dan ulang kembali sekarang? be.updating = Memperbarui... -be.ignore = Biarkan -be.noupdates = Tidak ada hal baru yang ditemukan. +be.ignore = Abaikan +be.noupdates = Tidak ada pembaruan yang ditemukan. be.check = Cek versi baru schematic = Skema @@ -52,9 +52,10 @@ schematic.copy.import = Impor dari papan klip schematic.shareworkshop = Bagikan di Workshop schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Balik Skema schematic.saved = Skema telah disimpan. -schematic.delete.confirm = Skema ini akan benar - benar dihapus +schematic.delete.confirm = Skema ini akan benar-benar dihapus. schematic.rename = Ganti nama Skema schematic.info = {0}x{1}, {2} blok +schematic.disabled = [scarlet]Skema dilarang[]\nAnda tidak diperbolehkan untuk menggunakan skema di [accent]peta[] atau [accent]server ini. stat.wave = Gelombang Terkalahkan:[accent] {0} stat.enemiesDestroyed = Musuh Terhancurkan:[accent] {0} @@ -65,7 +66,7 @@ stat.delivered = Sumber Daya yang Diluncurkan: stat.playtime = Waktu Bermain:[accent] {0} stat.rank = Nilai Akhir: [accent]{0} -globalitems = [accent]Global Items +globalitems = [accent]Item Global map.delete = Apakah Anda yakin ingin menghapus peta "[accent]{0}[]"? level.highscore = Nilai Tertinggi: [accent]{0} level.select = Pilih Level @@ -85,7 +86,7 @@ close = Tutup website = Situs Jaringan quit = Keluar save.quit = Simpan & Keluar -maps = Maps +maps = Peta maps.browse = Cari Peta continue = Lanjutkan maps.none = [lightgray]Peta tidak ditemukan! @@ -106,16 +107,16 @@ mods.none = [lightgray]Tidak ada mod yang ditemukan! mods.guide = Panduan Modding mods.report = Lapor Kesalahan mods.openfolder = Buka Folder Mod -mods.reload = mengulangi -mods.reloadexit = game akan keluar, untuk mengulang mod. +mods.reload = Muat Ulang +mods.reloadexit = Game akan keluar, untuk mengulang mod. mod.display = [gray]Mod:[orange] {0} mod.enabled = [lightgray]Aktif mod.disabled = [scarlet]Nonaktif mod.disable = Aktif -mod.content = konten: +mod.content = Konten: mod.delete.error = Tidak bisa menghapus mod. File mungkin sedang digunakan. mod.requiresversion = [scarlet]Versi game minimal yang dibutuhkan: [accent]{0} -mod.outdated = [scarlet]Not compatible with V6 (no minGameVersion: 105) +mod.outdated = [scarlet]Tidak cocok dengan V6 (minGameVersion: 105) mod.missingdependencies = [scarlet]Ketergantungan hilang: {0} mod.erroredcontent = [scarlet]Konten Mengalami Kesalahan mod.errors = Kesalahan terjadi disaat memuat konten. @@ -125,22 +126,22 @@ mod.enable = Aktif mod.requiresrestart = Game akan keluar untuk mengaktifkan mod. mod.reloadrequired = [scarlet]Dibutuhkan untuk memuat ulang mod.import = Impor Mod -mod.import.file = Import File +mod.import.file = Impor File mod.import.github = Impor Mod GitHub -mod.jarwarn = [scarlet]mod dari JAR sebenarnya tidak aman.[]\nPastikan anda mengimpor mod dari sumber terpercaya! +mod.jarwarn = [scarlet]Mod dari JAR sebenarnya tidak aman.[]\nPastikan anda mengimpor mod dari sumber terpercaya! mod.item.remove = Item ini merupakan bagian dari mod[accent] '{0}'[] mod. Untuk dihilangkan, hapus mod ini. mod.remove.confirm = Mod ini akan dihapus. mod.author = [lightgray]Pencipta:[] {0} mod.missing = Simpanan ini mengandung mod yang telah diperbarui atau sudah lama tidak dipasang. Kemungkinan akan terjadi perubahan. Apakah Anda yakin untuk memuatnya?\n[lightgray]Mods:\n{0} mod.preview.missing = Sebelum memposting mod di workshop, kamu harus memberi foto pratinjau.\nBeri sebuah foto berformat[accent] preview.png[] ke dalam folder mod dan ulang kembali. -mod.folder.missing = Hanya mod dengan format folder yang dapat diposting di workshop.\nUntuk mengubah mod menjadi folder, ekstrak file mod tersebut dan pastikan berbentuk sebuah folder, kemudian ulang game Anda atau mod Anda.. -mod.scripts.disable = perangkat anda tidak mendukung mod berformat skrip/JS. Anda harus menonaktifkan mod untuk lanjut bermain!. +mod.folder.missing = Hanya mod dengan format folder yang dapat diposting di workshop.\nUntuk mengubah mod menjadi folder, ekstrak file mod tersebut dan pastikan berbentuk sebuah folder, kemudian ulang game Anda atau mod Anda. +mod.scripts.disable = Perangkat anda tidak mendukung mod berformat skrip/JS. Anda harus menonaktifkan mod untuk lanjut bermain! about.button = Tentang name = Nama: noname = Pilih[accent] nama pemain[] dahulu. -planetmap = Planet Map -launchcore = Launch Core +planetmap = Peta Planet +launchcore = Luncurkan Inti filename = Nama File: unlocked = Konten baru terbuka! completed = [accent]Terselesaikan @@ -148,17 +149,17 @@ techtree = Cabang Teknologi research.list = [lightgray]Penelitian: research = Penelitian researched = [lightgray]{0} telah diteliti. -research.progress = {0}% complete +research.progress = {0}% diteliti players = {0} pemain aktif players.single = {0} pemain aktif -players.search = cari -players.notfound = [gray]tidak ada pemain ditemukan +players.search = Cari +players.notfound = [gray]Tidak ada pemain ditemukan server.closing = [accent]Menutup server... server.kicked.kick = Anda telah dikeluarkan dari server! server.kicked.whitelist = Anda tidak ada di dalam whitelist. server.kicked.serverClose = Server ditutup. server.kicked.vote = Anda dipilih untuk dikeluarkan. Sampai jumpa! -server.kicked.clientOutdated = Client kadaluarsa! Perbarui mindustry Anda! +server.kicked.clientOutdated = Client kadaluarsa! Perbarui game Anda! server.kicked.serverOutdated = Server kadaluarsa! Tanya pemilik untuk memperbarui! server.kicked.banned = Anda telah dilarang untuk memasuki server ini. server.kicked.typeMismatch = Server ini tidak cocok dengan versi build Anda. @@ -197,7 +198,7 @@ trace.mobile = Client Mobile: [accent]{0} trace.modclient = Client Modifikasi: [accent]{0} invalidid = Client ID tidak valid! Laporkan masalah. server.bans = Pemain Dilarang Masuk -server.bans.none = Tidak ada pemain yang diberiizin masuk! +server.bans.none = Tidak ada pemain yang tidak diberi izin masuk! server.admins = Admin server.admins.none = Tidak ada admin! server.add = Tambahkan Server @@ -262,7 +263,7 @@ view.workshop = Lihat di Workshop workshop.listing = Sunting Daftar Workshop ok = OK open = Buka -customize = edit +customize = Sunting Peraturan cancel = Batal openlink = Buka Tautan copylink = Salin Tautan @@ -335,7 +336,7 @@ waves.never = waves.every = setiap waves.waves = gelombang waves.perspawn = per muncul -waves.shields = shields/wave +waves.shields = perisai/gelombang waves.to = sampai waves.guardian = Guardian waves.preview = Pratinjau @@ -346,9 +347,10 @@ waves.invalid = Gelombang tidak valid di papan klip. waves.copied = Gelombang tersalin. waves.none = Tidak ada musuh yang didefinisikan.\nIngat bahwa susunan gelombang yang kosong akan diubah menjadi susunan gelombang standar secara otomatis. -wavemode.counts = counts -wavemode.totals = totals -wavemode.health = health +#memang sengaja diberi huruf kecil +wavemode.counts = jumlah +wavemode.totals = total +wavemode.health = darah editor.default = [lightgray] details = Detail... @@ -357,9 +359,9 @@ editor.name = Nama: editor.spawn = Munculkan Unit editor.removeunit = Hapus Unit editor.teams = Tim -editor.errorload = Terjadi kesalahan saat memuat file:\n[accent]{0} -editor.errorsave = Terjadi kesalahan saat menyimpan file:\n[accent]{0} -editor.errorimage = Itu gambar biasa, bukan peta. Jangan merubah ekstensi dan megharapkan akan berhasil.\n\nJika anda ingin mengimpor peta "Legacy", gunakan tombol 'impor peta legacy ' di penyunting. +editor.errorload = Terjadi kesalahan saat memuat file. +editor.errorsave = Terjadi kesalahan saat menyimpan file. +editor.errorimage = Itu gambar biasa, bukan peta. Jangan merubah ekstensi dan megharapkan akan berhasil.\n\nJika anda ingin mengimpor peta "Legacy", gunakan tombol 'Impor Peta Legacy ' di penyunting. editor.errorlegacy = Peta ini terlalu tua, dan memakai format peta "legacy" yang tidak didukung lagi. editor.errornot = Ini bukan merupakan file peta. editor.errorheader = File peta ini bisa jadi tidak sah atau rusak. @@ -415,8 +417,8 @@ toolmode.drawteams.description = Menggambar tim bukannya blok. filters.empty = [lightgray]Tidak ada filter! Tambahkan dengan tombol dibawah. filter.distort = Kerusakkan filter.noise = Kebisingan -filter.enemyspawn = Enemy Spawn Select -filter.corespawn = Core Select +filter.enemyspawn = Pilih Munculnya Musuh +filter.corespawn = Pilih Inti filter.median = Median filter.oremedian = Median Bijih filter.blend = Campur @@ -436,7 +438,7 @@ filter.option.circle-scale = Ukuran Lingkaran filter.option.octaves = Oktaf filter.option.falloff = Kemerosotan filter.option.angle = Sudut -filter.option.amount = Amount +filter.option.amount = Jumlah filter.option.block = Blok filter.option.floor = Lantai filter.option.flooronto = Target Lantai @@ -451,7 +453,7 @@ width = Lebar: height = Tinggi: menu = Menu play = Bermain -campaign = kampanye +campaign = Kampanye load = Memuat save = Simpan fps = FPS: {0} @@ -469,24 +471,19 @@ locked = Terkunci complete = [lightgray]Mencapai: requirement.wave = Capai gelombang {0} dalam {1} requirement.core = Hancurkan inti musuh dalam {0} -requirement.research = Research {0} -requirement.capture = Capture {0} -resume = Lanjutkan Zona:\n[lightgray]{0} +requirement.research = Kembangkan {0} +requirement.capture = Kuasai {0} bestwave = [lightgray]Gelombang Terbaik: {0} -launch = < MELUNCUR > -launch.text = Launch -launch.title = Berhasil Meluncur -launch.next = [lightgray]kesempatan berikutnya di gelombang {0} -launch.unable2 = [scarlet]Tidak dapat MELUNCUR.[] -launch.confirm = Ini akan meluncurkan semua sumber daya di inti.\nAnda tidak bisa kembali lagi ke tempat ini. -launch.skip.confirm = Jika Anda lewati sekarang, Anda tidak akan dapat meluncur hingga gelombang berikutnya. +launch.text = Luncurkan +campaign.multiplayer = Saat bermain bersama di kampanye, Kamu hanya bisa kembangkan menggunakan item dari sektor [accent]kamu[], [scarlet]Bukan[] sektor milik host yang kamu berada sekarang.\n\nUntuk mendapatkan item tersebut ke sektor [accent]kamu[] saat bermain bersama, gunakan [accent]alas peluncur[]. uncover = Buka configure = Konfigurasi Muatan -loadout = Loadout -resources = Resources +#TODO +loadout = Muatan +resources = Sumber Daya bannedblocks = Balok yang dilarang -addall = Tambah Semu -launch.destination = Destination: {0} +addall = Tambah Semua +launch.destination = Destinasi: {0} configure.invalid = Jumlah harus berupa angka diantara 0 dan {0}. zone.unlocked = [lightgray]{0} terbuka. zone.requirement.complete = Gelombang {0} terselesaikan:\nPersyaratan zona {1} tercapai. @@ -508,20 +505,21 @@ error.io = Terjadi kesalahan jaringan I/O. error.any = Terjadi kesalahan Jaringan tidak diketahui. error.bloom = Gagal untuk menginisialisasi bloom.\nPerangkat Anda mungkin tidak mendukung fitur ini. -weather.rain.name = Rain -weather.snow.name = Snow -weather.sandstorm.name = Sandstorm -weather.sporestorm.name = Sporestorm +weather.rain.name = Hujan +weather.snow.name = Salju +weather.sandstorm.name = Badai Pasir +weather.sporestorm.name = Badai Spora -sectors.unexplored = [lightgray]Unexplored -sectors.resources = Resources: -sectors.production = Production: -sectors.stored = Stored: -sectors.resume = Resume -sectors.launch = Launch -sectors.select = Select -sectors.nonelaunch = [lightgray]none (sun) +sectors.unexplored = [lightgray]Belum Ditelusuri +sectors.resources = Sumber Daya: +sectors.production = Produksi: +sectors.stored = Terisi: +sectors.resume = Lanjutkan +sectors.launch = Luncurkan +sectors.select = Pilih +sectors.nonelaunch = [lightgray]tidak ada +#NOTE TO TRANSLATORS: don't bother editing these, they'll be removed and/or rewritten anyway sector.groundZero.name = Ground Zero sector.craters.name = The Craters sector.frozenForest.name = Frozen Forest @@ -534,8 +532,12 @@ sector.tarFields.name = Tar Fields sector.saltFlats.name = Salt Flats sector.fungalPass.name = Fungal Pass -sector.groundZero.description = lokasi yang optimal untuk bermain satu kali lagi. Sangat sedikit musuh. Beberapa sumber daya.\nKumpulkan timah dan tembaga sebanyak yang anda bisa.\nPindah. -sector.frozenForest.description = disini, dekat dengan gunung, spora spora sudah menyebar. Temperatur yang sangat rendah tidak dapat mempertahankan selamanya.\n\nBerusaha untuk kekuatan. Bangun generator pembakaran. Pelajari cara menggunakan mender. +#unused +#sector.impact0078.name = Impact 0078 +#sector.crags.name = Crags + +sector.groundZero.description = Lokasi yang optimal untuk bermain satu kali lagi. Sangat sedikit musuh. Beberapa sumber daya.\nKumpulkan timah dan tembaga sebanyak yang anda bisa.\nPindah. +sector.frozenForest.description = Disini, dekat dengan gunung, spora spora sudah menyebar. Temperatur yang sangat rendah tidak dapat mempertahankan selamanya.\n\nBerusaha untuk kekuatan. Bangun generator pembakaran. Pelajari cara menggunakan mender. sector.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing. sector.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills. sector.ruinousShores.description = Past the wastes, is the shoreline. Once, this location housed a coastal defense array. Not much of it remains. Only the most basic defense structures have remained unscathed, everything else reduced to scrap.\nContinue the expansion outwards. Rediscover the technology. @@ -547,7 +549,7 @@ sector.nuclearComplex.description = A former facility for the production and pro sector.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores. settings.language = Bahasa -settings.data = Game Data +settings.data = Data Game settings.reset = Atur ulang ke Default (standar) settings.rebind = Ganti tombol settings.resetKey = Atur ulang @@ -558,65 +560,66 @@ settings.graphics = Grafik settings.cleardata = Menghapus Data Permainan... settings.clear.confirm = Anda yakin ingin menghapus data ini?\nWaktu tidak bisa diulang kembali! settings.clearall.confirm = [scarlet]PERINGATAN![]\nIni akan menghapus semua data permainan, termasuk simpanan, peta, bukaan dan keybind.\nSetelah Anda menekan 'ok' permainan akan menghapus semua data dan keluar otomatis. -settings.clearsaves.confirm = Are you sure you want to clear all your saves? -settings.clearsaves = Clear Saves +settings.clearsaves.confirm = Anda yakin ingin menghapus semua simpanan? +settings.clearsaves = Bersihkan Simpanan paused = [accent]< Jeda > clear = Bersih banned = [scarlet]Dilarang -unplaceable.sectorcaptured = [scarlet]Requires captured sector +unplaceable.sectorcaptured = [scarlet]Membutuhkan sektor yang dikuasai yes = Ya no = Tidak info.title = Info error.title = [crimson]Sebuah kesalahan telah terjadi error.crashtitle = Sebuah kesalahan telah terjadi -unit.nobuild = [scarlet]Unit can't build -blocks.input = Masukan -blocks.output = Pengeluaran -blocks.booster = Pendorong -blocks.tiles = Kotak yang dibutuhkan -blocks.affinities = Afinitas +unit.nobuild = [scarlet]Unit tidak dapat membangun +stat.input = Masukan +stat.output = Pengeluaran +stat.booster = Pendorong +stat.tiles = Kotak yang dibutuhkan +stat.affinities = Afinitas block.unknown = [lightgray]??? -blocks.powercapacity = Kapasitas Tenaga -blocks.powershot = Tenaga/Tembakan -blocks.damage = Kerusakan -blocks.targetsair = Menargetkan Udara -blocks.targetsground = Menargetkan Darat -blocks.itemsmoved = Kecepatan Gerak -blocks.launchtime = Waktu Diantara Peluncuran -blocks.shootrange = Jarak -blocks.size = Ukuran -blocks.displaysize = Display Size -blocks.liquidcapacity = Kapasitas Zat Cair -blocks.powerrange = Jarak Tenaga -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Koneksi Maksimal -blocks.poweruse = Penggunaan Tenaga -blocks.powerdamage = Tenaga/Pukulan -blocks.itemcapacity = Kapasitas Item -blocks.basepowergeneration = Basis Generasi Tenaga -blocks.productiontime = Waktu Produksi -blocks.repairtime = Waktu Memperbaiki Blok Penuh -blocks.speedincrease = Tambahan Kecepatan -blocks.range = Jarak -blocks.drilltier = Sumber Daya yang Bisa di Bor -blocks.drillspeed = Basis Kecepatan Bor -blocks.boosteffect = Efek Pendorong -blocks.maxunits = Maks Unit Aktif -blocks.health = Darah -blocks.buildtime = Waktu Pembuatan -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Biaya Bangunan -blocks.inaccuracy = Jarak Melenceng -blocks.shots = Tembakan -blocks.reload = Tembakan/Detik -blocks.ammo = Amunisi -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Kapasitas Tenaga +stat.powershot = Tenaga/Tembakan +stat.damage = Kerusakan +stat.targetsair = Menargetkan Udara +stat.targetsground = Menargetkan Darat +stat.itemsmoved = Kecepatan Gerak +stat.launchtime = Waktu Diantara Peluncuran +stat.shootrange = Jarak +stat.size = Ukuran +stat.displaysize = Ukuran Tampilan +stat.liquidcapacity = Kapasitas Zat Cair +stat.powerrange = Jarak Tenaga +stat.linkrange = Jarak Tautan +stat.instructions = Instruksi +stat.powerconnections = Koneksi Maksimal +stat.poweruse = Penggunaan Tenaga +stat.powerdamage = Tenaga/Pukulan +stat.itemcapacity = Kapasitas Item +stat.memorycapacity = Kapasitas Memori +stat.basepowergeneration = Basis Generasi Tenaga +stat.productiontime = Waktu Produksi +stat.repairtime = Waktu Memperbaiki Blok Penuh +stat.speedincrease = Tambahan Kecepatan +stat.range = Jarak +stat.drilltier = Sumber Daya yang Bisa di Bor +stat.drillspeed = Basis Kecepatan Bor +stat.boosteffect = Efek Pendorong +stat.maxunits = Maks Unit Aktif +stat.health = Darah +stat.buildtime = Waktu Pembuatan +stat.maxconsecutive = Max Consecutive +stat.buildcost = Biaya Bangunan +stat.inaccuracy = Jarak Melenceng +stat.shots = Tembakan +stat.reload = Tembakan/Detik +stat.ammo = Amunisi +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Membutuhkan Bor yang Lebih Baik -bar.noresources = Missing Resources -bar.corereq = Core Base Required +bar.noresources = Sumber Daya Tidak Ditemukan +bar.corereq = Memerlukan Inti Dasar bar.drillspeed = Kecepatan Bor: {0}/s bar.pumpspeed = Kecepatan Pompa: {0}/s bar.efficiency = Daya Guna: {0}% @@ -655,16 +658,16 @@ unit.liquidunits = unit zat cair unit.powerunits = unit tenaga unit.degrees = derajat unit.seconds = detik -unit.minutes = mins +unit.minutes = menit unit.persecond = /detik -unit.perminute = /min +unit.perminute = /menit unit.timesspeed = x kecepatan unit.percent = % unit.shieldhealth = shield health unit.items = item -unit.thousands = ribu -unit.millions = juta -unit.billions = b +unit.thousands = rb +unit.millions = jt +unit.billions = m category.general = Umum category.power = Tenaga category.liquids = Zat Cair @@ -677,13 +680,13 @@ setting.shadows.name = Bayangan setting.blockreplace.name = Usulan Blok Otomatis setting.linear.name = Filter Bergaris setting.hints.name = Petunjuk -setting.flow.name = Display Resource Flow Rate[scarlet] (experimental) +setting.flow.name = Tampilan Laju Aliran Sumber Daya setting.buildautopause.name = Jeda Otomatis saat Membangun -setting.mapcenter.name = Auto Center Map To Player +setting.mapcenter.name = Pusatkan Peta Otomatis Ke Pemain setting.animatedwater.name = Animasi Perairan setting.animatedshields.name = Animasi Pelindung setting.antialias.name = Antialiasi[lightgray] (membutuhkan restart)[] -setting.playerindicators.name = Player Indicators +setting.playerindicators.name = Indikasi Pemain setting.indicators.name = Indikasi Musuh/Teman Lain setting.autotarget.name = Target Secara Otomatis setting.keyboard.name = Kontrol Mouse+Papan Ketik @@ -702,7 +705,7 @@ setting.difficulty.name = Tingkat Kesulitan: setting.screenshake.name = Layar Getar setting.effects.name = Munculkan Efek setting.destroyedblocks.name = Tunjukkan Blok yang Telah Hancur -setting.blockstatus.name = Display Block Status +setting.blockstatus.name = Tunjukan Status Blok setting.conveyorpathfinding.name = Navigasi Pengantar Otomatis setting.sensitivity.name = Sensitivitas Kontroler setting.saveinterval.name = Jarak Menyimpan @@ -712,15 +715,15 @@ setting.milliseconds = {0} milisekon setting.fullscreen.name = Layar Penuh setting.borderlesswindow.name = Jendela tak Berbatas[lightgray] (mungkin memerlukan mengulang kembali) setting.fps.name = Tunjukkan FPS -setting.smoothcamera.name = Smooth Camera +setting.smoothcamera.name = Kamera Halus setting.blockselectkeys.name = Tunjukkan Kunci Pilih Blok setting.vsync.name = VSync setting.pixelate.name = Mode Pixel[lightgray] (menonaktifkan animasi) setting.minimap.name = Tunjukkan Peta Kecil -setting.coreitems.name = Display Core Items (WIP) +setting.coreitems.name = Tunjukkan Item Inti (WIP) setting.position.name = Tunjukkan Posisi Pemain setting.musicvol.name = Volume Musik -setting.atmosphere.name = Show Planet Atmosphere +setting.atmosphere.name = Tunjukkan Atmosfer Planet setting.ambientvol.name = Volume Sekeliling setting.mutemusic.name = Diamkan Musik setting.sfxvol.name = Volume Efek Suara @@ -738,30 +741,30 @@ public.beta = Ingat bahwa game versi beta tidak dapat membuat lobi publik. uiscale.reset = Skala UI telah diubah.\nTekan "OK" untuk mengonfirmasi.\n[scarlet]Kembali dan keluar di[accent] {0}[] pengaturan... uiscale.cancel = Batal & Keluar setting.bloom.name = Bloom -keybind.title = Ganti Kunci -keybinds.mobile = [scarlet]Mayoritas kunci tidak mendukung mobile. Hanya gerakan dasar yang didukung. +keybind.title = Ganti Tombol +keybinds.mobile = [scarlet]Mayoritas tombol tidak didukung oleh perangkat ponsel Hanya gerakan dasar yang didukung. category.general.name = Umum category.view.name = Melihat category.multiplayer.name = Bermain Bersama -category.blocks.name = Block Select +category.blocks.name = Pilih Blok command.attack = Serang command.rally = Kumpul/Patroli command.retreat = Mundur -command.idle = Idle -placement.blockselectkeys = \n[lightgray]Kunci: [{0}, -keybind.respawn.name = Respawn -keybind.control.name = Control Unit +command.idle = Diam di Tempat +placement.blockselectkeys = \n[lightgray]Tombol: [{0}, +keybind.respawn.name = Muncul Kembali +keybind.control.name = Kontrol Unit keybind.clear_building.name = Hapus Bangunan -keybind.press = Tekan kunci... -keybind.press.axis = Tekan sumbu atau kunci... +keybind.press = Tekan tombol... +keybind.press.axis = Tekan sumbu atau tombol... keybind.screenshot.name = Tangkapan Layar Peta keybind.toggle_power_lines.name = Aktifkan Tenaga Laser -keybind.toggle_block_status.name = Toggle Block Statuses -keybind.move_x.name = Pindah x -keybind.move_y.name = Pindah y -keybind.mouse_move.name = Ikut Mouse -keybind.pan.name = Pan View -keybind.boost.name = Boost +keybind.toggle_block_status.name = Status Blok +keybind.move_x.name = Pindah X +keybind.move_y.name = Pindah Y +keybind.mouse_move.name = Ikuti Mouse +keybind.pan.name = Tampilan Geser +keybind.boost.name = Dorongan keybind.schematic_select.name = Pilih Daerah keybind.schematic_menu.name = Menu Skema keybind.schematic_flip_x.name = Balik Skema X @@ -788,9 +791,9 @@ keybind.diagonal_placement.name = Penaruhan Diagonal keybind.pick.name = Memilih Blok keybind.break_block.name = Menghancurkan Blok keybind.deselect.name = Batal Memilih -keybind.pickupCargo.name = Pickup Cargo -keybind.dropCargo.name = Drop Cargo -keybind.command.name = Command +keybind.pickupCargo.name = Muat Kargo +keybind.dropCargo.name = Turunkan Kargo +keybind.command.name = Perintah keybind.shoot.name = Menembak keybind.zoom.name = Perbesar keybind.menu.name = Menu @@ -801,7 +804,7 @@ keybind.chat.name = Pesan keybind.player_list.name = Daftar pemain keybind.console.name = Papan Konsol keybind.rotate.name = Putar -keybind.rotateplaced.name = Putar yang ada (Tekan) +keybind.rotateplaced.name = Putar yang ada (Tekan dan Tahan) keybind.toggle_menus.name = Muncul Tidaknya Menu keybind.chat_history_prev.name = Sejarah Pesan Sebelumnya keybind.chat_history_next.name = Sejarah Pesan Setelahnya @@ -822,13 +825,14 @@ mode.custom = Pengaturan Modifikasi rules.infiniteresources = Sumber Daya Tak Terbatas rules.reactorexplosions = Ledakan Reaktor +rules.schematic = Skema Diperbolehkan rules.wavetimer = Pengaturan Waktu Gelombang rules.waves = Gelombang rules.attack = Mode Penyerangan -rules.buildai = AI Building +rules.buildai = Bangunan A.I. rules.enemyCheat = Sumber Daya A.I Musuh (Tim Merah) Tak Terbatas rules.blockhealthmultiplier = Multiplikasi Darah Blok -rules.blockdamagemultiplier = Block Damage Multiplier +rules.blockdamagemultiplier = Multiplikasi Kekuatan Blok rules.unitbuildspeedmultiplier = Multiplikasi Kecepatan Munculnya Unit rules.unithealthmultiplier = Multiplikasi Darah Unit rules.unitdamagemultiplier = Multiplikasi Kekuatan Unit @@ -836,23 +840,24 @@ rules.enemycorebuildradius = Dilarang Membangun Radius Inti Musuh :[lightgray] ( rules.wavespacing = Jarak Gelombang:[lightgray] (detik) rules.buildcostmultiplier = Multiplikasi Harga Bangunan rules.buildspeedmultiplier = Multiplikasi Waktu Pembuatan Bangunan -rules.deconstructrefundmultiplier = Penggembalian Dana Mendekonstraksi Blok +rules.deconstructrefundmultiplier = Penggembalian Dana Mendekonstruksi Blok rules.waitForWaveToEnd = Gelombang menunggu musuh rules.dropzoneradius = Radius Titik Muncul:[lightgray] (Blok) -rules.unitammo = Units Require Ammo +rules.unitammo = Unit Membutuhkan AMunisi rules.title.waves = Gelombang rules.title.resourcesbuilding = Sumber Daya & Bangunan rules.title.enemy = Musuh rules.title.unit = Unit rules.title.experimental = Eksperimental -rules.title.environment = Environment +rules.title.environment = Lingkungan rules.lighting = Penerangan -rules.fire = Fire -rules.explosions = Block/Unit Explosion Damage +rules.enemyLights = Sinar dari Musuh +rules.fire = Api +rules.explosions = Kekuatan Ledakan Blok/Unit rules.ambientlight = Sinar Disekeliling -rules.weather = Weather -rules.weather.frequency = Frequency: -rules.weather.duration = Duration: +rules.weather = Cuaca +rules.weather.frequency = Frekuensi: +rules.weather.duration = Durasi: content.item.name = Item content.liquid.name = Zat Cair @@ -877,7 +882,7 @@ item.scrap.name = Kepingan liquid.water.name = Air liquid.slag.name = Terak liquid.oil.name = Minyak -liquid.cryofluid.name = Cairan Dingin +liquid.cryofluid.name = Cairan Pendingin item.explosiveness = [lightgray]Tingkat Keledakan: {0}% item.flammability = [lightgray]Tingkat Kebakaran: {0}% @@ -885,12 +890,12 @@ item.radioactivity = [lightgray]Tingkat Radioaktif: {0}% unit.health = [lightgray]Darah: {0} unit.speed = [lightgray]Kecepatan: {0} -unit.weapon = [lightgray]Weapon: {0} -unit.itemcapacity = [lightgray]Item Capacity: {0} -unit.minespeed = [lightgray]Mining Speed: {0}% -unit.minepower = [lightgray]Mining Power: {0} -unit.ability = [lightgray]Ability: {0} -unit.buildspeed = [lightgray]Building Speed: {0}% +unit.weapon = [lightgray]Senjata: {0} +unit.itemcapacity = [lightgray]Kapasitas Item: {0} +unit.minespeed = [lightgray]Kecepatan Menambang: {0}% +unit.minepower = [lightgray]Kekuatan Menambang: {0} +unit.ability = [lightgray]Kemampuan: {0} +unit.buildspeed = [lightgray]Kecepatan Membangun: {0}% liquid.heatcapacity = [lightgray]Kapasitas Panas: {0} liquid.viscosity = [lightgray]Kelekatan: {0} @@ -930,7 +935,7 @@ unit.reign.name = Reign unit.vela.name = Vela unit.corvus.name = Corvus -block.resupply-point.name = Resupply Point +block.resupply-point.name = Titik Pemasok Ulang block.parallax.name = Parallax block.cliff.name = Cliff block.sand-boulder.name = Batu Pasir @@ -979,17 +984,17 @@ block.craters.name = Kawah block.sand-water.name = Air Pasir block.darksand-water.name = Air Pasir Hitam block.char.name = Bara -block.dacite.name = Dacite -block.dacite-wall.name = Dacite Wall +block.dacite.name = Dasit +block.dacite-wall.name = Dinding Dasit block.ice-snow.name = Salju Es -block.stone-wall.name = Stone Wall -block.ice-wall.name = Ice Wall -block.snow-wall.name = Snow Wall -block.dune-wall.name = Dune Wall +block.stone-wall.name = Dinding Batu +block.ice-wall.name = Dinding Es +block.snow-wall.name = Dinding Salju +block.dune-wall.name = Dinding Pasir block.pine.name = Cemara -block.dirt.name = Dirt -block.dirt-wall.name = Dirt Wall -block.mud.name = Mud +block.dirt.name = Tanah +block.dirt-wall.name = Dinding Tanah +block.mud.name = Lumpur block.white-tree-dead.name = Pohon Putih Mati block.white-tree.name = Pohon Putih block.spore-cluster.name = Kumpulan Spora @@ -1005,7 +1010,7 @@ block.dark-panel-4.name = Panel Gelap 4 block.dark-panel-5.name = Panel Gelap 5 block.dark-panel-6.name = Panel Gelap 6 block.dark-metal.name = Besi Gelap -block.basalt.name = Basalt +block.basalt.name = Basal block.hotrock.name = Batu Panas block.magmarock.name = Batu Lahar block.copper-wall.name = Dinding Tembaga @@ -1021,13 +1026,13 @@ block.thorium-wall-large.name = Dinding Thorium Besar block.door.name = Pintu block.door-large.name = Pintu Besar block.duo.name = Duo -block.scorch.name = Penghangus -block.scatter.name = Penabur -block.hail.name = Penghujan +block.scorch.name = Scorch +block.scatter.name = Scatter +block.hail.name = Hail block.lancer.name = Lancer block.conveyor.name = Pengantar block.titanium-conveyor.name = Pengantar Berbahan Titanium -block.plastanium-conveyor.name = Plastanium Conveyor +block.plastanium-conveyor.name = Pengantar Berbahan Plastanium block.armored-conveyor.name = Pengantar Berlapis Pelindung block.armored-conveyor.description = Memindahkan barang sama cepatnya dengan pengantar titanium, namun memiliki lebih banyak armor. Tidak dapat menerima masukan dari samping dari apapun kecuali dari pengantar. block.junction.name = Simpangan @@ -1074,10 +1079,11 @@ block.power-void.name = Penghilang Tenaga block.power-source.name = Sumber Tenaga block.unloader.name = Pembongkar Muatan block.vault.name = Gudang -block.wave.name = Ombak -block.swarmer.name = Pengurung +block.wave.name = Wave +block.tsunami.name = Tsunami +block.swarmer.name = Swarmer block.salvo.name = Salvo -block.ripple.name = Periak +block.ripple.name = Ripple block.phase-conveyor.name = Pengantar Berbahan Phase block.bridge-conveyor.name = Jembatan Pengantar block.plastanium-compressor.name = Kompresor Plastanium @@ -1105,46 +1111,48 @@ block.mender.name = Reparator block.mend-projector.name = Proyeksi Reparator block.surge-wall.name = Dinding Listrik block.surge-wall-large.name = Dinding Listrik Besar -block.cyclone.name = Topan -block.fuse.name = Padu +block.cyclone.name = Cyclone +block.fuse.name = Fuse block.shock-mine.name = Ranjau Listrik block.overdrive-projector.name = Proyeksi Pencepat block.force-projector.name = Proyeksi Medan Gaya -block.arc.name = Arca +block.arc.name = Arc block.rtg-generator.name = Generator RTG -block.spectre.name = Iblis -block.meltdown.name = Pelebur +block.spectre.name = Spectre +block.meltdown.name = Meltdown +block.foreshadow.name = Foreshadow block.container.name = Kontainer block.launch-pad.name = Alas Peluncur block.launch-pad-large.name = Alas Peluncur Besar block.segment.name = Segment -block.command-center.name = Command Center -block.ground-factory.name = Ground Factory -block.air-factory.name = Air Factory -block.naval-factory.name = Naval Factory -block.additive-reconstructor.name = Additive Reconstructor -block.multiplicative-reconstructor.name = Multiplicative Reconstructor -block.exponential-reconstructor.name = Exponential Reconstructor -block.tetrative-reconstructor.name = Tetrative Reconstructor -block.payload-conveyor.name = Mass Conveyor -block.payload-router.name = Payload Router -block.disassembler.name = Disassembler -block.silicon-crucible.name = Silicon Crucible -block.overdrive-dome.name = Overdrive Dome +block.command-center.name = Pusat Perintah +block.ground-factory.name = Pabrik Angkatan Darat +block.air-factory.name = Pabrik Angkatan Udara +block.naval-factory.name = Pabrik Angkatan Laut +block.additive-reconstructor.name = Rekonstruktor Aditif +block.multiplicative-reconstructor.name = Rekonstruktor Multiplikatif +block.exponential-reconstructor.name = Rekonstruktor Eksponensial +block.tetrative-reconstructor.name = Rekonstruktor Tetratif +block.payload-conveyor.name = Pengantar Massa +block.payload-router.name = Pengarah Massa +block.disassembler.name = Pembongkar +block.silicon-crucible.name = Multi-Lebur +block.overdrive-dome.name = Kubah Proyeksi Percepat -block.switch.name = Switch -block.micro-processor.name = Micro Processor -block.logic-processor.name = Logic Processor -block.hyper-processor.name = Hyper Processor -block.logic-display.name = Logic Display -block.large-logic-display.name = Large Logic Display -block.memory-cell.name = Memory Cell +block.switch.name = Saklar +block.micro-processor.name = Prosesor Mikro +block.logic-processor.name = Prosesor Logika +block.hyper-processor.name = Prosesor Cepat +block.logic-display.name = Tampilan Logika +block.large-logic-display.name = Tampilan Logika Besar +block.memory-cell.name = Sel Memori +block.memory-bank.name = Bank Memori team.blue.name = biru team.crux.name = merah team.sharded.name = oranye team.orange.name = jingga -team.derelict.name = derelict +team.derelict.name = abu-abu team.green.name = hijau team.purple.name = ungu @@ -1235,7 +1243,7 @@ block.force-projector.description = Membentuk medan gaya berbentuk heksagon dise block.shock-mine.description = Mencedera musuh yang menginjak ranjau. Hampir tak kasat mata kepada musuh. block.conveyor.description = Blok transportasi dasar. Memindahkan item ke kubah ataupun pabrik. Bisa diputar. block.titanium-conveyor.description = Blok transportasi canggih. Memindahkan item lebih cepat daripada pengantar biasa. -block.plastanium-conveyor.description = Moves items in batches.\nAccepts items at the back, and unloads them in three directions at the front. +block.plastanium-conveyor.description = Memindahkan barang secara bertumpuk.\nMenerima barang dari belakang, dan membaginya ke tiga arah di depan.\nMembutuhkan beberapa titik pemuat dan pembongkar untuk hasil yang maksimal. block.junction.description = Berguna seperti jembatan untuk dua pengantar yang bersimpangan. Berguna di situasi dimana dua pengantar berbeda membawa bahan berbeda ke lokasi yang berbeda. block.bridge-conveyor.description = Blok transportasi item canggih. bisa memindahkan item hingga 3 blok panjang melewati apapun lapangan atau bangunan. block.phase-conveyor.description = Blok transportasi canggih. Menggunakan tenaga untuk teleportasi item ke sambungan pengantar phase melewati beberapa blok. @@ -1302,4 +1310,4 @@ block.cyclone.description = Menara penembak beruntun besar. block.spectre.description = Menara besar yang menembak dua peluru kuat sekaligus. block.meltdown.description = Menara besar ini menembak sinar panjang yang kuat. block.repair-point.description = Terus menerus memulihkan unit terluka disekitar. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Merusakkan dan menghancurkan proyektil yang datang. Proyektil laser tidak akan ditargetkan. \ No newline at end of file diff --git a/core/assets/bundles/bundle_it.properties b/core/assets/bundles/bundle_it.properties index c10f894851..5fc3245ed6 100644 --- a/core/assets/bundles/bundle_it.properties +++ b/core/assets/bundles/bundle_it.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [crimson]Si è verificato un errore error.crashtitle = Si è verificato un errore unit.nobuild = [scarlet]L'unità non può costruire -blocks.input = Ingresso -blocks.output = Uscita -blocks.booster = Potenziamenti -blocks.tiles = Blocchi Richiesti -blocks.affinities = Affinità +stat.input = Ingresso +stat.output = Uscita +stat.booster = Potenziamenti +stat.tiles = Blocchi Richiesti +stat.affinities = Affinità block.unknown = [lightgray]??? -blocks.powercapacity = Capacità Energetica -blocks.powershot = Danno/Colpo -blocks.damage = Danno -blocks.targetsair = Attacca Nemici Aerei -blocks.targetsground = Attacca Nemici Terreni -blocks.itemsmoved = Velocità di Movimento -blocks.launchtime = Tempo fra Decolli -blocks.shootrange = Raggio -blocks.size = Dimensioni -blocks.displaysize = Display Size -blocks.liquidcapacity = Capacità del Liquido -blocks.powerrange = Raggio Energia -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Connessioni Massime -blocks.poweruse = Utilizzo Energia -blocks.powerdamage = Energia/Danno -blocks.itemcapacity = Capacità -blocks.basepowergeneration = Generazione Energia di Base -blocks.productiontime = Tempo di Produzione -blocks.repairtime = Tempo di Riparazione Completa -blocks.speedincrease = Aumento Velocità -blocks.range = Raggio -blocks.drilltier = Scavabili -blocks.drillspeed = Velocità di Scavo Stabile -blocks.boosteffect = Effetto Boost -blocks.maxunits = Unità Attive Max -blocks.health = Salute -blocks.buildtime = Tempo di Costruzione -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Costo di Costruzione -blocks.inaccuracy = Inaccuratezza -blocks.shots = Colpi -blocks.reload = Ricarica -blocks.ammo = Munizioni -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Capacità Energetica +stat.powershot = Danno/Colpo +stat.damage = Danno +stat.targetsair = Attacca Nemici Aerei +stat.targetsground = Attacca Nemici Terreni +stat.itemsmoved = Velocità di Movimento +stat.launchtime = Tempo fra Decolli +stat.shootrange = Raggio +stat.size = Dimensioni +stat.displaysize = Display Size +stat.liquidcapacity = Capacità del Liquido +stat.powerrange = Raggio Energia +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Connessioni Massime +stat.poweruse = Utilizzo Energia +stat.powerdamage = Energia/Danno +stat.itemcapacity = Capacità +stat.basepowergeneration = Generazione Energia di Base +stat.productiontime = Tempo di Produzione +stat.repairtime = Tempo di Riparazione Completa +stat.speedincrease = Aumento Velocità +stat.range = Raggio +stat.drilltier = Scavabili +stat.drillspeed = Velocità di Scavo Stabile +stat.boosteffect = Effetto Boost +stat.maxunits = Unità Attive Max +stat.health = Salute +stat.buildtime = Tempo di Costruzione +stat.maxconsecutive = Max Consecutive +stat.buildcost = Costo di Costruzione +stat.inaccuracy = Inaccuratezza +stat.shots = Colpi +stat.reload = Ricarica +stat.ammo = Munizioni +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Miglior Trivella Richiesta bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Una grande torretta a fuoco rapido. block.spectre.description = Una grande torretta che spara due potenti proiettili contemporaneamente. block.meltdown.description = Una grande torretta che spara un potente laser a lungo raggio. block.repair-point.description = Cura continuamente l'unità danneggiata più vicina. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_ja.properties b/core/assets/bundles/bundle_ja.properties index fdb915ff96..68c766e79b 100644 --- a/core/assets/bundles/bundle_ja.properties +++ b/core/assets/bundles/bundle_ja.properties @@ -570,49 +570,49 @@ info.title = 情報 error.title = [crimson]エラーが発生しました error.crashtitle = エラーが発生しました unit.nobuild = [scarlet]ユニットを構築できません -blocks.input = 搬入 -blocks.output = 搬出 -blocks.booster = ブースト -blocks.tiles = 必要なタイル -blocks.affinities = 親和性 +stat.input = 搬入 +stat.output = 搬出 +stat.booster = ブースト +stat.tiles = 必要なタイル +stat.affinities = 親和性 block.unknown = [lightgray]??? -blocks.powercapacity = 電力容量 -blocks.powershot = 電力/ショット -blocks.damage = ダメージ -blocks.targetsair = 対空攻撃 -blocks.targetsground = 対地攻撃 -blocks.itemsmoved = 輸送速度 -blocks.launchtime = 発射の待機時間 -blocks.shootrange = 範囲 -blocks.size = 大きさ -blocks.displaysize = Display Size -blocks.liquidcapacity = 液体容量 -blocks.powerrange = 電力範囲 -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = 最大接続数 -blocks.poweruse = 電力使用量 -blocks.powerdamage = 電力/ダメージ -blocks.itemcapacity = アイテム容量 -blocks.basepowergeneration = 基本発電量 -blocks.productiontime = 製造速度 -blocks.repairtime = ブロックの完全修復速度 -blocks.speedincrease = 速度向上 -blocks.range = 範囲 -blocks.drilltier = ドリル -blocks.drillspeed = 基本採掘速度 -blocks.boosteffect = ブースト効果 -blocks.maxunits = 最大ユニット数 -blocks.health = 耐久値 -blocks.buildtime = 建設時間 -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = 建設費用 -blocks.inaccuracy = 誤差 -blocks.shots = ショット -blocks.reload = リロード速度 -blocks.ammo = 弾薬 -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = 電力容量 +stat.powershot = 電力/ショット +stat.damage = ダメージ +stat.targetsair = 対空攻撃 +stat.targetsground = 対地攻撃 +stat.itemsmoved = 輸送速度 +stat.launchtime = 発射の待機時間 +stat.shootrange = 範囲 +stat.size = 大きさ +stat.displaysize = Display Size +stat.liquidcapacity = 液体容量 +stat.powerrange = 電力範囲 +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = 最大接続数 +stat.poweruse = 電力使用量 +stat.powerdamage = 電力/ダメージ +stat.itemcapacity = アイテム容量 +stat.basepowergeneration = 基本発電量 +stat.productiontime = 製造速度 +stat.repairtime = ブロックの完全修復速度 +stat.speedincrease = 速度向上 +stat.range = 範囲 +stat.drilltier = ドリル +stat.drillspeed = 基本採掘速度 +stat.boosteffect = ブースト効果 +stat.maxunits = 最大ユニット数 +stat.health = 耐久値 +stat.buildtime = 建設時間 +stat.maxconsecutive = Max Consecutive +stat.buildcost = 建設費用 +stat.inaccuracy = 誤差 +stat.shots = ショット +stat.reload = リロード速度 +stat.ammo = 弾薬 +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = より高性能なドリルを使用してください bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = 大型の連射型ターレットです。 block.spectre.description = 一度に2発の強力な弾を放つ大型のターレットです。 block.meltdown.description = 強力な長距離攻撃が可能な大型のターレットです。 block.repair-point.description = 近くの負傷したユニットを修復します。 -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index 87f3d00a1b..82bb299642 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -115,7 +115,7 @@ mod.disable = 비활성화 mod.content = 콘텐츠: mod.delete.error = 모드를 삭제할 수 없습니다. 파일이 사용 중일 수 있습니다. mod.requiresversion = [scarlet]필요한 최소 게임 버전: [accent]{0} -mod.outdated = [scarlet]Not compatible with V6 (no minGameVersion: 105) +mod.outdated = [scarlet]V6 전용이 아닌 모드 (minGameVersion: 105 누락) mod.missingdependencies = [scarlet]누락된 요구 모드: {0} mod.erroredcontent = [scarlet]콘텐츠 오류 mod.errors = 콘텐츠를 로드하는 동안 오류가 발생함. @@ -148,7 +148,7 @@ techtree = 연구 기록 research.list = [lightgray]연구: research = 연구 researched = [lightgray]{0} 연구 완료. -research.progress = {0}% complete +research.progress = {0}% 완료 players = {0} 플레이어들 players.single = {0} 플레이어 players.search = 검색 @@ -335,7 +335,7 @@ waves.never = 여기까지 유닛생성 waves.every = 매 waves.waves = 웨이브마다 waves.perspawn = 생성 -waves.shields = 보호막/웨이브 +waves.shields = 방어막/웨이브 waves.to = 부터 waves.guardian = 보호자 waves.preview = 미리보기 @@ -469,8 +469,8 @@ locked = 잠김 complete = [lightgray]해금 조건 : requirement.wave = {1}지역에서 {0}웨이브 달성 requirement.core = {0}지역에서 적 코어를 파괴 -requirement.research = Research {0} -requirement.capture = Capture {0} +requirement.research = {0} 연구 +requirement.capture = {0} 점령 resume = 지역 재개:\n[lightgray]{0} bestwave = [lightgray]최고 웨이브: {0} launch = < 출격 > @@ -508,10 +508,10 @@ error.io = 네트워크 I/O 오류. error.any = 알 수 없는 네트워크 오류. error.bloom = 블룸 그래픽 효과를 적용하지 못했습니다.\n당신의 기기가 이 기능을 지원하지 않는 것일 수도 있습니다. -weather.rain.name = Rain -weather.snow.name = Snow -weather.sandstorm.name = Sandstorm -weather.sporestorm.name = Sporestorm +weather.rain.name = 비 +weather.snow.name = 눈 +weather.sandstorm.name = 모래폭풍 +weather.sporestorm.name = 포자폭풍 sectors.unexplored = [lightgray]Unexplored sectors.resources = Resources: @@ -570,49 +570,49 @@ info.title = 정보 error.title = [scarlet]오류가 발생했습니다. error.crashtitle = 오류가 발생했습니다 unit.nobuild = [scarlet]이 유닛은 건설할 수 없습니다. -blocks.input = 입력 -blocks.output = 출력 -blocks.booster = 가속 -blocks.tiles = 필요한 타일 -blocks.affinities = 친화력 +stat.input = 입력 +stat.output = 출력 +stat.booster = 가속 +stat.tiles = 필요한 타일 +stat.affinities = 친화력 block.unknown = [lightgray]??? -blocks.powercapacity = 전력 용량 -blocks.powershot = 전력/발 -blocks.damage = 공격력 -blocks.targetsair = 공중 공격 -blocks.targetsground = 지상 공격 -blocks.itemsmoved = 이동 속도 -blocks.launchtime = 출격 간격 -blocks.shootrange = 사거리 -blocks.size = 크기 -blocks.displaysize = Display Size -blocks.liquidcapacity = 액체 용량 -blocks.powerrange = 전력 범위 -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = 최대 연결 수 -blocks.poweruse = 전력 사용 -blocks.powerdamage = 전력/데미지 -blocks.itemcapacity = 저장 용량 -blocks.basepowergeneration = 기본 전력 생성량 -blocks.productiontime = 제작 시간 -blocks.repairtime = 전체 블록 수리시간 -blocks.speedincrease = 속도 증가 -blocks.range = 사거리 -blocks.drilltier = 드릴 -blocks.drillspeed = 기본 드릴 속도 -blocks.boosteffect = 가속 효과 -blocks.maxunits = 최대 활성 유닛수 -blocks.health = 체력 -blocks.buildtime = 건설 시간 -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = 건설 재료 -blocks.inaccuracy = 오차각 -blocks.shots = 공격 속도 -blocks.reload = 발/초 -blocks.ammo = 탄약 -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = 전력 용량 +stat.powershot = 전력/발 +stat.damage = 공격력 +stat.targetsair = 공중 공격 +stat.targetsground = 지상 공격 +stat.itemsmoved = 이동 속도 +stat.launchtime = 출격 간격 +stat.shootrange = 사거리 +stat.size = 크기 +stat.displaysize = Display Size +stat.liquidcapacity = 액체 용량 +stat.powerrange = 전력 범위 +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = 최대 연결 수 +stat.poweruse = 전력 사용 +stat.powerdamage = 전력/데미지 +stat.itemcapacity = 저장 용량 +stat.basepowergeneration = 기본 전력 생성량 +stat.productiontime = 제작 시간 +stat.repairtime = 전체 블록 수리시간 +stat.speedincrease = 속도 증가 +stat.range = 사거리 +stat.drilltier = 드릴 +stat.drillspeed = 기본 드릴 속도 +stat.boosteffect = 가속 효과 +stat.maxunits = 최대 활성 유닛수 +stat.health = 체력 +stat.buildtime = 건설 시간 +stat.maxconsecutive = Max Consecutive +stat.buildcost = 건설 재료 +stat.inaccuracy = 오차각 +stat.shots = 공격 속도 +stat.reload = 발/초 +stat.ammo = 탄약 +stat.shieldhealth = 보호막 체력 +stat.cooldowntime = Cooldown Time bar.drilltierreq = 더 좋은 드릴이 필요 bar.noresources = 자원 부족 @@ -1109,7 +1109,7 @@ block.cyclone.name = 사이클론 block.fuse.name = 퓨즈 block.shock-mine.name = 전격 지뢰 block.overdrive-projector.name = 과부하 프로젝터 -block.force-projector.name = 포스 프로젝터 +block.force-projector.name = 보호막 프로젝터 block.arc.name = 아크 block.rtg-generator.name = RTG 발전기 block.spectre.name = 스펙터 @@ -1118,27 +1118,27 @@ block.container.name = 컨테이너 block.launch-pad.name = 출격 패드 block.launch-pad-large.name = 대형 출격 패드 block.segment.name = 세그먼트 -block.command-center.name = Command Center +block.command-center.name = 지휘소 block.ground-factory.name = 지상 공장 block.air-factory.name = 항공 공장 block.naval-factory.name = 해양 공장 block.additive-reconstructor.name = 첨가물 재구성기 block.multiplicative-reconstructor.name = 다중 재구성기 block.exponential-reconstructor.name = 지수 재구성기 -block.tetrative-reconstructor.name = 정서 재구성기 +block.tetrative-reconstructor.name = 발산 재구성기 block.payload-conveyor.name = 화물 컨베이어 block.payload-router.name = 화물 분배기 block.disassembler.name = 가속 분해기 block.silicon-crucible.name = 실리콘 도가니 block.overdrive-dome.name = 대형 과부하 프로젝터 -block.switch.name = Switch -block.micro-processor.name = Micro Processor -block.logic-processor.name = Logic Processor -block.hyper-processor.name = Hyper Processor -block.logic-display.name = Logic Display -block.large-logic-display.name = Large Logic Display -block.memory-cell.name = Memory Cell +block.switch.name = 스위치 +block.micro-processor.name = 소형 프로세서 +block.logic-processor.name = 명령 프로세서 +block.hyper-processor.name = 하이퍼 프로세서 +block.logic-display.name = 화면 +block.large-logic-display.name = 대형 화면 +block.memory-cell.name = 기억 블록 team.blue.name = 파랑색 팀 team.crux.name = 빨강색 팀 @@ -1241,7 +1241,7 @@ block.bridge-conveyor.description = 고급 자원 운송 블록. 지형이나 block.phase-conveyor.description = 고급 자원 운송 블록. 전력을 사용하여 여러 타일을 통해 연결된 컨베이어로 자원을 순간이동 시킵니다. block.sorter.description = 자원을 정렬합니다. 자원이 선택과 일치하면 앞방향으로 통과하며, 그렇지 않을 경우 왼쪽과 오른쪽으로 출력됩니다. block.inverted-sorter.description = 표준 분류기와 같은 자원을 처리하지만, 대신 선택된 자원을 측면으로 출력합니다. -block.router.description = 자원을 받아서 최대 3개의 다른 방향으로 동일하게 출력합니다. 하나의 소스에서 여러 대상으로 재료를 분할하는 데 유용합니다.\n\n[scarlet]공장에서 생산된 재료는 출력에 의해 막히게 되므로, 절대로 공장 옆에서 사용하지 마십시오. +block.router.description = 자원을 받아서 최대 3개의 다른 방향으로 동일하게 출력합니다. 하나의 공급원에서 여러 대상으로 재료를 분할하는 데 유용합니다.\n\n[scarlet]공장에서 생산된 재료는 출력에 의해 막히게 되므로, 절대로 공장 옆에서 사용하지 마십시오. block.distributor.description = 고급 분배기. 자원을 최대 7개의 다른 방향으로 동일하게 분할합니다. block.overflow-gate.description = 전면 경로가 차단 된 경우에만 왼쪽과 오른쪽으로 출력됩니다. block.underflow-gate.description = 오버플로 게이트의 반대. 왼쪽 및 오른쪽 경로가 차단되면 전면으로 출력됩니다. @@ -1252,7 +1252,7 @@ block.thermal-pump.description = 가장 강력한 펌프. block.conduit.description = 기본 액체 운송 블록. 액체를 앞으로 이동시킵미다. 펌프 및 기타 파이프와 함께 사용됩니다. block.pulse-conduit.description = 고급 액체 운송 블록. 액체를 더 빠르게 운반하고 표준 파이프보다 더 많이 저장합니다. block.plated-conduit.description = 펄스 파이프와 같은 속도로 이동하지만 더 높은 방어력을 가지고 있습니다. 파이프 이외의 물체로 측면의 액체를 받아들이지 않습니다.\n누설이 적습니다. -block.liquid-router.description = 한 방향에서 액체를 받아 최대 3개의 다른 방향으로 동일하게 출력합니다. 일정량의 액체를 저장할 수도 있으며 한 소스에서 여러 대상으로 액체를 분할하는 데 유용합니다. +block.liquid-router.description = 한 방향에서 액체를 받아 최대 3개의 다른 방향으로 동일하게 출력합니다. 일정량의 액체를 저장할 수도 있으며 한 공급원에서 여러 대상으로 액체를 분할하는 데 유용합니다. block.liquid-tank.description = 대량의 액체를 저장합니다. 재료가 일정하지 않은 상황에서 버퍼를 생성하거나 중요한 블록을 냉각하기 위한 보호 장치로 사용하세요. block.liquid-junction.description = 두 개의 교차 파이프를 위한 다리 역할을 합니다. 다른 액체를 다른 위치로 운반하는 두 개의 다른 파이프가 있는 상황에서 유용합니다. block.bridge-conduit.description = 고급 액체 운송 블록. 지형이나 건물을 넘어 최대 3개 타일 위로 액체를 운반할 수 있습니다. @@ -1302,4 +1302,4 @@ block.cyclone.description = 대공 및 대지 포탑. 근처 유닛에게 폭발 block.spectre.description = 거대한 이중 배럴 대포. 공중 및 지상 목표물에 큰 관통 철갑탄을 발사합니다. block.meltdown.description = 거대한 레이저 대포. 근처의 적에게 지속적인 레이버 빔을 충전하여 발사합니다. 냉각수가 있어야 작동합니다. block.repair-point.description = 주변에서 가장 가까운 유닛을 지속적으로 치료합니다. -block.segment.description = 날아오는 발사체를 요격합니다. 레이저는 목표 대상이 아닙니다. +block.segment.description = 날아오는 발사체를 요격합니다. 레이저는 목표 대상이 아닙니다. \ No newline at end of file diff --git a/core/assets/bundles/bundle_lt.properties b/core/assets/bundles/bundle_lt.properties index a318c53f5f..2ebd273b5a 100644 --- a/core/assets/bundles/bundle_lt.properties +++ b/core/assets/bundles/bundle_lt.properties @@ -570,49 +570,49 @@ info.title = Informacija error.title = [crimson]Įvyko klaida error.crashtitle = Įvyko klaida unit.nobuild = [scarlet]Unit can't build -blocks.input = Įeiga -blocks.output = Išeiga -blocks.booster = Stiprintuvas -blocks.tiles = Privalomi -blocks.affinities = Affinities +stat.input = Įeiga +stat.output = Išeiga +stat.booster = Stiprintuvas +stat.tiles = Privalomi +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Energijos Talpumas -blocks.powershot = Energija per šūvį -blocks.damage = Žala -blocks.targetsair = Šaudo į oro taikinius -blocks.targetsground = Šaudo į žemės taikinius -blocks.itemsmoved = Judėjimo Greitis -blocks.launchtime = Laikas Tarp Paleidimų -blocks.shootrange = Atstumas -blocks.size = Dydis -blocks.displaysize = Display Size -blocks.liquidcapacity = Skysčių Talpumas -blocks.powerrange = Energijos Skleidimo Atstumas -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Maks. Jungčių Kiekis -blocks.poweruse = Energijos Suvartojimas -blocks.powerdamage = Power/Damage -blocks.itemcapacity = Daiktų Talpumas -blocks.basepowergeneration = Bazinis Energijos Generavimas -blocks.productiontime = Gamybos Laikas -blocks.repairtime = Pilnas bloko sutaisymo laikas -blocks.speedincrease = Greičio Padidėjimas -blocks.range = Atstumas -blocks.drilltier = Gręžiama -blocks.drillspeed = Bazinis Grąžto Greitis -blocks.boosteffect = Pastiprinimo Efektas -blocks.maxunits = Maks. Aktyvių Vienetų Kiekis -blocks.health = Gyvybės -blocks.buildtime = Statymo Laikas -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Statymo Kaina -blocks.inaccuracy = Netikslumas -blocks.shots = Šūviai -blocks.reload = Šūviai per sekundę -blocks.ammo = Šoviniai -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Energijos Talpumas +stat.powershot = Energija per šūvį +stat.damage = Žala +stat.targetsair = Šaudo į oro taikinius +stat.targetsground = Šaudo į žemės taikinius +stat.itemsmoved = Judėjimo Greitis +stat.launchtime = Laikas Tarp Paleidimų +stat.shootrange = Atstumas +stat.size = Dydis +stat.displaysize = Display Size +stat.liquidcapacity = Skysčių Talpumas +stat.powerrange = Energijos Skleidimo Atstumas +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Maks. Jungčių Kiekis +stat.poweruse = Energijos Suvartojimas +stat.powerdamage = Power/Damage +stat.itemcapacity = Daiktų Talpumas +stat.basepowergeneration = Bazinis Energijos Generavimas +stat.productiontime = Gamybos Laikas +stat.repairtime = Pilnas bloko sutaisymo laikas +stat.speedincrease = Greičio Padidėjimas +stat.range = Atstumas +stat.drilltier = Gręžiama +stat.drillspeed = Bazinis Grąžto Greitis +stat.boosteffect = Pastiprinimo Efektas +stat.maxunits = Maks. Aktyvių Vienetų Kiekis +stat.health = Gyvybės +stat.buildtime = Statymo Laikas +stat.maxconsecutive = Max Consecutive +stat.buildcost = Statymo Kaina +stat.inaccuracy = Netikslumas +stat.shots = Šūviai +stat.reload = Šūviai per sekundę +stat.ammo = Šoviniai +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Privalomas Geresnis Grąžtas bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Didelis bokštas puolantis, tiek žemę, tiek orą. block.spectre.description = Milžiniškas dvivamzdis bokštas. Šaudo didelius, kiaurai per šarvus einančius šovinius į taikinius esančius ant žemės ir ore. block.meltdown.description = Milžiniška lazerinė patranka. Užsikrauna ir šaudo lazerinius spindulius į aplinkinius priešus. Veikimui reikalingas aušinimo skystis. block.repair-point.description = Pastoviai gydo artimiausius netoliese esančius vienetus. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_nl.properties b/core/assets/bundles/bundle_nl.properties index 634b6eb00e..41d6e8a8fc 100644 --- a/core/assets/bundles/bundle_nl.properties +++ b/core/assets/bundles/bundle_nl.properties @@ -570,49 +570,49 @@ info.title = Informatie error.title = [crimson]Een fout is opgetreden error.crashtitle = Een fout is opgetreden unit.nobuild = [scarlet]Unit can't build -blocks.input = Input -blocks.output = Output -blocks.booster = Booster -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Input +stat.output = Output +stat.booster = Booster +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Stroomcapaciteit -blocks.powershot = Stroom/Schot -blocks.damage = Schade -blocks.targetsair = Luchtdoelwitten -blocks.targetsground = Gronddoelwitten -blocks.itemsmoved = Beweegingssnelheid -blocks.launchtime = Tijd tussen lanceringen -blocks.shootrange = Bereik -blocks.size = Formaat -blocks.displaysize = Display Size -blocks.liquidcapacity = Vloeistofcapaciteit -blocks.powerrange = Stroombereik -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Maximale Hoeveelheid Connecties -blocks.poweruse = Stroomverbruik -blocks.powerdamage = Stroom/Schade -blocks.itemcapacity = Materiaalcapaciteit -blocks.basepowergeneration = Standaard Stroom Generatie -blocks.productiontime = Productie Tijd -blocks.repairtime = Volledige Blok Repareertijd -blocks.speedincrease = Snelheidsverhoging -blocks.range = Bereik -blocks.drilltier = Valt te delven -blocks.drillspeed = Standaard mine snelheid -blocks.boosteffect = Boost Effect -blocks.maxunits = Maximaal Actieve Units -blocks.health = Levenspunten -blocks.buildtime = Bouwtijd -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Bouwkosten -blocks.inaccuracy = Onnauwkeurigheid -blocks.shots = Shoten -blocks.reload = Schoten/Seconde -blocks.ammo = Ammunitie -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Stroomcapaciteit +stat.powershot = Stroom/Schot +stat.damage = Schade +stat.targetsair = Luchtdoelwitten +stat.targetsground = Gronddoelwitten +stat.itemsmoved = Beweegingssnelheid +stat.launchtime = Tijd tussen lanceringen +stat.shootrange = Bereik +stat.size = Formaat +stat.displaysize = Display Size +stat.liquidcapacity = Vloeistofcapaciteit +stat.powerrange = Stroombereik +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Maximale Hoeveelheid Connecties +stat.poweruse = Stroomverbruik +stat.powerdamage = Stroom/Schade +stat.itemcapacity = Materiaalcapaciteit +stat.basepowergeneration = Standaard Stroom Generatie +stat.productiontime = Productie Tijd +stat.repairtime = Volledige Blok Repareertijd +stat.speedincrease = Snelheidsverhoging +stat.range = Bereik +stat.drilltier = Valt te delven +stat.drillspeed = Standaard mine snelheid +stat.boosteffect = Boost Effect +stat.maxunits = Maximaal Actieve Units +stat.health = Levenspunten +stat.buildtime = Bouwtijd +stat.maxconsecutive = Max Consecutive +stat.buildcost = Bouwkosten +stat.inaccuracy = Onnauwkeurigheid +stat.shots = Shoten +stat.reload = Schoten/Seconde +stat.ammo = Ammunitie +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Betere miner nodig bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = A large rapid fire turret. block.spectre.description = A large turret which shoots two powerful bullets at once. block.meltdown.description = A large turret which shoots powerful long-range beams. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_nl_BE.properties b/core/assets/bundles/bundle_nl_BE.properties index ce59b257f7..4f2ed1fdcd 100644 --- a/core/assets/bundles/bundle_nl_BE.properties +++ b/core/assets/bundles/bundle_nl_BE.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [crimson]An error has occured error.crashtitle = An error has occured unit.nobuild = [scarlet]Unit can't build -blocks.input = Input -blocks.output = Output -blocks.booster = Booster -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Input +stat.output = Output +stat.booster = Booster +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Power Capacity -blocks.powershot = Power/Shot -blocks.damage = Damage -blocks.targetsair = Targets Air -blocks.targetsground = Targets Ground -blocks.itemsmoved = Move Speed -blocks.launchtime = Time Between Launches -blocks.shootrange = Range -blocks.size = Size -blocks.displaysize = Display Size -blocks.liquidcapacity = Liquid Capacity -blocks.powerrange = Power Range -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Power Use -blocks.powerdamage = Power/Damage -blocks.itemcapacity = Item Capacity -blocks.basepowergeneration = Base Power Generation -blocks.productiontime = Production Time -blocks.repairtime = Block Full Repair Time -blocks.speedincrease = Speed Increase -blocks.range = Range -blocks.drilltier = Drillables -blocks.drillspeed = Base Drill Speed -blocks.boosteffect = Boost Effect -blocks.maxunits = Max Active Units -blocks.health = Health -blocks.buildtime = Build Time -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Build Cost -blocks.inaccuracy = Inaccuracy -blocks.shots = Shots -blocks.reload = Shots/Second -blocks.ammo = Ammo -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Power Capacity +stat.powershot = Power/Shot +stat.damage = Damage +stat.targetsair = Targets Air +stat.targetsground = Targets Ground +stat.itemsmoved = Move Speed +stat.launchtime = Time Between Launches +stat.shootrange = Range +stat.size = Size +stat.displaysize = Display Size +stat.liquidcapacity = Liquid Capacity +stat.powerrange = Power Range +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Power Use +stat.powerdamage = Power/Damage +stat.itemcapacity = Item Capacity +stat.basepowergeneration = Base Power Generation +stat.productiontime = Production Time +stat.repairtime = Block Full Repair Time +stat.speedincrease = Speed Increase +stat.range = Range +stat.drilltier = Drillables +stat.drillspeed = Base Drill Speed +stat.boosteffect = Boost Effect +stat.maxunits = Max Active Units +stat.health = Health +stat.buildtime = Build Time +stat.maxconsecutive = Max Consecutive +stat.buildcost = Build Cost +stat.inaccuracy = Inaccuracy +stat.shots = Shots +stat.reload = Shots/Second +stat.ammo = Ammo +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Better Drill Required bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = A large rapid fire turret. block.spectre.description = A large turret which shoots two powerful bullets at once. block.meltdown.description = A large turret which shoots powerful long-range beams. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties index 3760ea4ed2..84bf25d5e2 100644 --- a/core/assets/bundles/bundle_pl.properties +++ b/core/assets/bundles/bundle_pl.properties @@ -572,50 +572,51 @@ info.title = Informacje error.title = [crimson]Wystąpił błąd error.crashtitle = Wystąpił błąd unit.nobuild = [scarlet]Jednostka nie może budować -blocks.input = Wejście -blocks.output = Wyjście -blocks.booster = Wzmacniacz -blocks.tiles = Wymagane Pola -blocks.affinities = Uwydajnienie +stat.input = Wejście +stat.output = Wyjście +stat.booster = Wzmacniacz +stat.tiles = Wymagane Pola +stat.affinities = Uwydajnienie block.unknown = [lightgray]??? -blocks.powercapacity = Pojemność mocy -blocks.powershot = moc/strzał -blocks.damage = Obrażenia -blocks.targetsair = Namierzanie wrogów powietrznych -blocks.targetsground = Namierzanie wrogów lądowych -blocks.itemsmoved = Prędkość poruszania się -blocks.launchtime = Czas pomiędzy wystrzeleniami -blocks.shootrange = Zasięg -blocks.size = Rozmiar -blocks.displaysize = Display Size -blocks.liquidcapacity = Pojemność cieczy -blocks.powerrange = Zakres mocy -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Maksymalna ilość połączeń -blocks.poweruse = Zużycie prądu -blocks.powerdamage = Moc/Zniszczenia -blocks.itemcapacity = Pojemność przedmiotów -blocks.memorycapacity = Memory Capacity -blocks.basepowergeneration = Podstawowa generacja mocy -blocks.productiontime = Czas produkcji -blocks.repairtime = Czas pełnej naprawy bloku -blocks.speedincrease = Zwiększenie prędkości -blocks.range = Zasięg -blocks.drilltier = Co może wykopać -blocks.drillspeed = Podstawowa szybkość kopania -blocks.boosteffect = Efekt wzmocnienia -blocks.maxunits = Maksymalna ilość jednostek -blocks.health = Zdrowie -blocks.buildtime = Czas budowy -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Koszt budowy -blocks.inaccuracy = Niecelność -blocks.shots = Strzały -blocks.reload = Strzałów/sekundę -blocks.ammo = Amunicja -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time + +stat.powercapacity = Pojemność mocy +stat.powershot = moc/strzał +stat.damage = Obrażenia +stat.targetsair = Namierzanie wrogów powietrznych +stat.targetsground = Namierzanie wrogów lądowych +stat.itemsmoved = Prędkość poruszania się +stat.launchtime = Czas pomiędzy wystrzeleniami +stat.shootrange = Zasięg +stat.size = Rozmiar +stat.displaysize = Display Size +stat.liquidcapacity = Pojemność cieczy +stat.powerrange = Zakres mocy +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Maksymalna ilość połączeń +stat.poweruse = Zużycie prądu +stat.powerdamage = Moc/Zniszczenia +stat.itemcapacity = Pojemność przedmiotów +stat.memorycapacity = Memory Capacity +stat.basepowergeneration = Podstawowa generacja mocy +stat.productiontime = Czas produkcji +stat.repairtime = Czas pełnej naprawy bloku +stat.speedincrease = Zwiększenie prędkości +stat.range = Zasięg +stat.drilltier = Co może wykopać +stat.drillspeed = Podstawowa szybkość kopania +stat.boosteffect = Efekt wzmocnienia +stat.maxunits = Maksymalna ilość jednostek +stat.health = Zdrowie +stat.buildtime = Czas budowy +stat.maxconsecutive = Max Consecutive +stat.buildcost = Koszt budowy +stat.inaccuracy = Niecelność +stat.shots = Strzały +stat.reload = Strzałów/sekundę +stat.ammo = Amunicja +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Wymagane Lepsze Wiertło bar.noresources = Missing Resources @@ -1311,4 +1312,3 @@ block.spectre.description = Duże działo dwulufowe, które strzela potężnymi block.meltdown.description = Duże działo laserowe, które strzela potężnymi wiązkami dalekiego zasięgu. Wymaga chłodzenia. block.repair-point.description = Bez przerw naprawia najbliższą uszkodzoną jednostkę w jego zasięgu. block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. - diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties index 7754faa059..7f2659d839 100644 --- a/core/assets/bundles/bundle_pt_BR.properties +++ b/core/assets/bundles/bundle_pt_BR.properties @@ -570,49 +570,49 @@ info.title = [accent]Informação error.title = [crimson]Ocorreu um Erro. error.crashtitle = Ocorreu um Erro unit.nobuild = [scarlet]Unit can't build -blocks.input = Entrada -blocks.output = Saída -blocks.booster = Apoio -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Entrada +stat.output = Saída +stat.booster = Apoio +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Capacidade de Energia -blocks.powershot = Energia/tiro -blocks.damage = Dano -blocks.targetsair = Mira no ar -blocks.targetsground = Mira no chão -blocks.itemsmoved = Velocidade de movimento -blocks.launchtime = Tempo entre Disparos. -blocks.shootrange = Alcance -blocks.size = Tamanho -blocks.displaysize = Display Size -blocks.liquidcapacity = Capacidade de Líquido -blocks.powerrange = Alcance da Energia -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Conexões Máximas -blocks.poweruse = Uso de energia -blocks.powerdamage = Dano/Poder -blocks.itemcapacity = Capacidade de Itens -blocks.basepowergeneration = Geração de poder base -blocks.productiontime = Tempo de produção -blocks.repairtime = Tempo de reparo total do bloco -blocks.speedincrease = Aumento de velocidade -blocks.range = Distância -blocks.drilltier = Brocas -blocks.drillspeed = Velocidade base da Broca -blocks.boosteffect = Efeito do Impulso -blocks.maxunits = Máximo de unidades ativas -blocks.health = Saúde -blocks.buildtime = Tempo de construção -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Custo de construção -blocks.inaccuracy = Imprecisão -blocks.shots = Tiros -blocks.reload = Tiros por segundo -blocks.ammo = Munição -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Capacidade de Energia +stat.powershot = Energia/tiro +stat.damage = Dano +stat.targetsair = Mira no ar +stat.targetsground = Mira no chão +stat.itemsmoved = Velocidade de movimento +stat.launchtime = Tempo entre Disparos. +stat.shootrange = Alcance +stat.size = Tamanho +stat.displaysize = Display Size +stat.liquidcapacity = Capacidade de Líquido +stat.powerrange = Alcance da Energia +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Conexões Máximas +stat.poweruse = Uso de energia +stat.powerdamage = Dano/Poder +stat.itemcapacity = Capacidade de Itens +stat.basepowergeneration = Geração de poder base +stat.productiontime = Tempo de produção +stat.repairtime = Tempo de reparo total do bloco +stat.speedincrease = Aumento de velocidade +stat.range = Distância +stat.drilltier = Brocas +stat.drillspeed = Velocidade base da Broca +stat.boosteffect = Efeito do Impulso +stat.maxunits = Máximo de unidades ativas +stat.health = Saúde +stat.buildtime = Tempo de construção +stat.maxconsecutive = Max Consecutive +stat.buildcost = Custo de construção +stat.inaccuracy = Imprecisão +stat.shots = Tiros +stat.reload = Tiros por segundo +stat.ammo = Munição +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Broca melhor necessária. bar.noresources = Missing Resources @@ -1021,7 +1021,7 @@ block.thorium-wall-large.name = Muralha de Tório block.door.name = Porta block.door-large.name = Portão block.duo.name = Torreta dupla -block.scorch.name = Lança-fogo +block.scorch.name = Lança-chamas block.scatter.name = Dispersão block.hail.name = Artilharia block.lancer.name = Lanceiro @@ -1038,8 +1038,8 @@ block.inverted-sorter.name = Ordenador invertido block.message.name = Mensagem block.illuminator.name = Iluminador block.illuminator.description = Uma pequena, compacta e configurável fonte de luz. Precisa de energia para funcionar. -block.overflow-gate.name = Comporta -block.underflow-gate.name = Comporta invertida +block.overflow-gate.name = Portão Sobrecarregado +block.underflow-gate.name = Portão Sobrecarregado invertida block.silicon-smelter.name = Fundidora de silicio block.phase-weaver.name = Palheta de fase block.pulverizer.name = Pulverizador @@ -1077,7 +1077,7 @@ block.vault.name = Cofre block.wave.name = Onda block.swarmer.name = Enxame block.salvo.name = Salvo -block.ripple.name = Ondulação +block.ripple.name = Morteiro block.phase-conveyor.name = Transportador de Fase block.bridge-conveyor.name = Esteira-Ponte block.plastanium-compressor.name = Compressor de Plastânio @@ -1087,8 +1087,8 @@ block.solar-panel.name = Painel Solar block.solar-panel-large.name = Painel Solar Grande block.oil-extractor.name = Bomba de Petróleo block.repair-point.name = Ponto de Reparo -block.pulse-conduit.name = Cano de Tinânio -block.plated-conduit.name = Cano blindado +block.pulse-conduit.name = Cano de Pulso +block.plated-conduit.name = Cano Blindado block.phase-conduit.name = Cano de Fase block.liquid-router.name = Roteador de Líquido block.liquid-tank.name = Tanque de Líquido @@ -1110,7 +1110,7 @@ block.fuse.name = Fusivel block.shock-mine.name = Mina de choque block.overdrive-projector.name = Projetor de sobrecarga block.force-projector.name = Projetor de campo de força -block.arc.name = Bobina de Tesla +block.arc.name = Tesla block.rtg-generator.name = Gerador GTR block.spectre.name = Espectro block.meltdown.name = Fusão @@ -1302,4 +1302,4 @@ block.cyclone.description = Uma grande torre que dispara balas explosivas que se block.spectre.description = Um grande canhão massivo. Dispara grandes tiros perfuradores de blindagem em inimigos aéreos e terrestres. block.meltdown.description = Um grande canhão laser massivo. Carrega e dispara um poderoso e persistente feixe nos seus inimigos. Requer uma refrigeração para ser operada. block.repair-point.description = Continuamente repara a unidade danificada mais proxima. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Destrói projéteis inimigos. Projéteis de laser não são afetados. \ No newline at end of file diff --git a/core/assets/bundles/bundle_pt_PT.properties b/core/assets/bundles/bundle_pt_PT.properties index 0b6948191b..c4b5070b3a 100644 --- a/core/assets/bundles/bundle_pt_PT.properties +++ b/core/assets/bundles/bundle_pt_PT.properties @@ -570,49 +570,49 @@ info.title = [accent]Informação error.title = [crimson]Ocorreu um Erro. error.crashtitle = Ocorreu um Erro unit.nobuild = [scarlet]Unit can't build -blocks.input = Entrada -blocks.output = Saida -blocks.booster = Booster -blocks.tiles = Telhas Requeridas -blocks.affinities = Afinidades +stat.input = Entrada +stat.output = Saida +stat.booster = Booster +stat.tiles = Telhas Requeridas +stat.affinities = Afinidades block.unknown = [lightgray]??? -blocks.powercapacity = Capacidade de Energia -blocks.powershot = Energia/tiro -blocks.damage = Dano -blocks.targetsair = Mirar no ar -blocks.targetsground = Mirar no chão -blocks.itemsmoved = Velocidade de movimento -blocks.launchtime = Tempo entre tiros -blocks.shootrange = Alcance -blocks.size = Tamanho -blocks.displaysize = Display Size -blocks.liquidcapacity = Capacidade de Líquido -blocks.powerrange = Alcance da Energia -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Uso de energia -blocks.powerdamage = Dano/Poder -blocks.itemcapacity = Capacidade de Itens -blocks.basepowergeneration = Geração de poder base -blocks.productiontime = Tempo de produção -blocks.repairtime = Tempo de reparo total do bloco -blocks.speedincrease = Aumento de velocidade -blocks.range = Distância -blocks.drilltier = Furáveis -blocks.drillspeed = Velocidade da broca base -blocks.boosteffect = Efeito do Boost -blocks.maxunits = Máximo de unidades ativas -blocks.health = Saúde -blocks.buildtime = Tempo de construção -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Custo de construção -blocks.inaccuracy = Imprecisão -blocks.shots = Tiros -blocks.reload = Tiros por segundo -blocks.ammo = Munição -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Capacidade de Energia +stat.powershot = Energia/tiro +stat.damage = Dano +stat.targetsair = Mirar no ar +stat.targetsground = Mirar no chão +stat.itemsmoved = Velocidade de movimento +stat.launchtime = Tempo entre tiros +stat.shootrange = Alcance +stat.size = Tamanho +stat.displaysize = Display Size +stat.liquidcapacity = Capacidade de Líquido +stat.powerrange = Alcance da Energia +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Uso de energia +stat.powerdamage = Dano/Poder +stat.itemcapacity = Capacidade de Itens +stat.basepowergeneration = Geração de poder base +stat.productiontime = Tempo de produção +stat.repairtime = Tempo de reparo total do bloco +stat.speedincrease = Aumento de velocidade +stat.range = Distância +stat.drilltier = Furáveis +stat.drillspeed = Velocidade da broca base +stat.boosteffect = Efeito do Boost +stat.maxunits = Máximo de unidades ativas +stat.health = Saúde +stat.buildtime = Tempo de construção +stat.maxconsecutive = Max Consecutive +stat.buildcost = Custo de construção +stat.inaccuracy = Imprecisão +stat.shots = Tiros +stat.reload = Tiros por segundo +stat.ammo = Munição +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Broca melhor necessária. bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Uma grande torre de tiro rapido. block.spectre.description = Uma grande torre que da dois tiros poderosos ao mesmo tempo. block.meltdown.description = Uma grande torre que atira dois raios poderosos ao mesmo tempo. block.repair-point.description = Continuamente repara a unidade danificada mais proxima. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_ro.properties b/core/assets/bundles/bundle_ro.properties index 221ab0aab6..aa9fd2f18d 100644 --- a/core/assets/bundles/bundle_ro.properties +++ b/core/assets/bundles/bundle_ro.properties @@ -55,6 +55,7 @@ schematic.saved = Schemă salvată. schematic.delete.confirm = Schema această va fi ștearsă permanent. schematic.rename = Redenumește Schema schematic.info = {0}x{1}, {2} blocuri +schematic.disabled = [scarlet]Schemele sunt dezactivate[]\nNu ai voie să folosești scheme pe această [accent]hartă[] sau [accent]server. stat.wave = Valuri Învinse:[accent] {0} stat.enemiesDestroyed = Inamici Distruși:[accent] {0} @@ -290,6 +291,8 @@ waiting = [lightgray]În așteptare... waiting.players = Se așteaptă jucătorii... wave.enemies = [lightgray]Mai sunt {0} inamici wave.enemy = [lightgray]Mai e {0} inamic +wave.guardianwarn = Gardianul va veni în [accent]{0}[] valuri. +wave.guardianwarn.one = Gardianul va veni într-[accent]un[] val. loadimage = Încarcă Imagine saveimage = Salvează Imagine unknown = Necunoscut @@ -328,6 +331,7 @@ editor.generation = Generare: editor.ingame = Editează în Joc editor.publish.workshop = Publică pe Workshop editor.newmap = Hartă Nouă +editor.center = Centrează workshop = Workshop waves.title = Valuri waves.remove = Elimină @@ -420,7 +424,7 @@ filter.corespawn = Selectare Nucleu filter.median = Mediană filter.oremedian = Mediană Minereu filter.blend = Amestecare -filter.defaultores = Miercuri Prestabilite +filter.defaultores = Minereuri Prestabilite filter.ore = Minereu filter.rivernoise = Zgomot Vizual Râuri filter.mirror = Oglindă @@ -471,22 +475,16 @@ requirement.wave = Ajungi la valul {0} în {1} requirement.core = Distruge Nucleu Inamic în{0} requirement.research = Cercetează {0} requirement.capture = Capturează {0} -resume = Revin la Zonă:\n[lightgray]{0} bestwave = [lightgray]Cel Mai Bun Val: {0} -launch = < LANSARE > launch.text = Lansează -launch.title = Lansare Finalizată -launch.next = [lightgray]următoarea ocazie la valul {0} -launch.unable2 = [scarlet]Imposibil de LANSAT.[] -launch.confirm = Asta va lansa toate resursele din nucleu.\nNu te vei mai putea întoarce la această bază. -launch.skip.confirm = Dacă sari acum, Nu vei mai putea lansa decât valurile viitoare. +campaign.multiplayer = Când joci muliplayer în campanie, nu poți cerceta noi tehnologii decât folosind materiale din sectoarele [accent]tale[], [scarlet]nu[] din sectorul gazdei jocului, unde te afli acum.\n\nPt a transfera materialele către sectoarele [accent]tale[] în multiplayer, folosește o [accent]platformă de lansare[]. uncover = Descoperă configure = Configurează Încărcarea loadout = Încărcare resources = Resurse bannedblocks = Blocuri Interzise addall = Adaugă-le pe toate -launch.destination = Destination: {0} +launch.destination = Destinație: {0} configure.invalid = Cantitatea trebuie să fie un număr între 0 și {0}. zone.unlocked = [lightgray]{0} deblocat(ă). zone.requirement.complete = Cerințele pt {0} finalizate:[lightgray]\n{1} @@ -519,8 +517,8 @@ sectors.production = Producție: sectors.stored = Stocat: sectors.resume = Revino sectors.launch = Lansare -sectors.select = Select -sectors.nonelaunch = [lightgray]none (sun) +sectors.select = Selectează +sectors.nonelaunch = [lightgray]nimic (soarele) sector.groundZero.name = Ground Zero sector.craters.name = The Craters @@ -570,49 +568,51 @@ info.title = Info error.title = [scarlet]A apărut o eroare. error.crashtitle = A apărut o eroare. unit.nobuild = [scarlet]Unitatea nu poate construi. -blocks.input = Necesită -blocks.output = Produce -blocks.booster = Booster -blocks.tiles = Teren Necesar -blocks.affinities = Efecte Teren +lastaccessed = [lightgray]Ultima Accesare: {0} +stat.input = Necesită +stat.output = Produce +stat.booster = Booster +stat.tiles = Teren Necesar +stat.affinities = Efecte Teren block.unknown = [lightgray]??? -blocks.powercapacity = Capacitate electrică -blocks.powershot = Electricitate/Glonț -blocks.damage = Forță -blocks.targetsair = Lovește Aeronave -blocks.targetsground = Lovește Artilerie -blocks.itemsmoved = Viteza de Mișcare a Materialelor -blocks.launchtime = Timp între Lansări -blocks.shootrange = Rază -blocks.size = Mărime -blocks.displaysize = Mărimea Monitorului Logic -blocks.liquidcapacity = Capacitate Lichid -blocks.powerrange = Raza Electrică -blocks.linkrange = Raza Legăturilor -blocks.instructions = Instrucțiuni -blocks.powerconnections = Maxim Conexiuni -blocks.poweruse = Consum Electricitate -blocks.powerdamage = Electricitate/Forța Glonțului -blocks.itemcapacity = Capacitate Materiale -blocks.basepowergeneration = Generare Electricitate (Bază) -blocks.productiontime = Timp Producție -blocks.repairtime = Durata Reparării Blocului -blocks.speedincrease = Creștere Viteză -blocks.range = Rază -blocks.drilltier = Minabile -blocks.drillspeed = Viteză Burghiu (Bază) -blocks.boosteffect = Efect de Boost -blocks.maxunits = Maxim Unități Active -blocks.health = Viață -blocks.buildtime = Timp Construcție -blocks.maxconsecutive = Maxim Consecutive -blocks.buildcost = Cost Construcție -blocks.inaccuracy = Inacuratețe -blocks.shots = Lovituri -blocks.reload = Lovituri/Secundă -blocks.ammo = Muniție -blocks.shieldhealth = Viața Scutului -blocks.cooldowntime = Timp de Reîncărcare +stat.powercapacity = Capacitate electrică +stat.powershot = Electricitate/Glonț +stat.damage = Forță +stat.targetsair = Lovește Aeronave +stat.targetsground = Lovește Artilerie +stat.itemsmoved = Viteza de Mișcare a Materialelor +stat.launchtime = Timp între Lansări +stat.shootrange = Rază +stat.size = Mărime +stat.displaysize = Mărimea Monitorului Logic +stat.liquidcapacity = Capacitate Lichid +stat.powerrange = Raza Electrică +stat.linkrange = Raza Legăturilor +stat.instructions = Instrucțiuni +stat.powerconnections = Maxim Conexiuni +stat.poweruse = Consum Electricitate +stat.powerdamage = Electricitate/Forța Glonțului +stat.itemcapacity = Capacitate Materiale +stat.memorycapacity = Capacitate Memorie +stat.basepowergeneration = Generare Electricitate (Bază) +stat.productiontime = Timp Producție +stat.repairtime = Durata Reparării Blocului +stat.speedincrease = Creștere Viteză +stat.range = Rază +stat.drilltier = Minabile +stat.drillspeed = Viteză Burghiu (Bază) +stat.boosteffect = Efect de Boost +stat.maxunits = Maxim Unități Active +stat.health = Viață +stat.buildtime = Timp Construcție +stat.maxconsecutive = Maxim Consecutive +stat.buildcost = Cost Construcție +stat.inaccuracy = Inacuratețe +stat.shots = Lovituri +stat.reload = Lovituri/Secundă +stat.ammo = Muniție +stat.shieldhealth = Viața Scutului +stat.cooldowntime = Timp de Reîncărcare bar.drilltierreq = Burghiu Mai Bun Necesar bar.noresources = Resurse lipsă @@ -624,6 +624,7 @@ bar.powerbalance = Electricitate: {0}/s bar.powerstored = Stocată: {0}/{1} bar.poweramount = Electricitate: {0} bar.poweroutput = Electricitate Produsă: {0} +bar.powerlines = Conexiuni: {0}/{1} bar.items = Materiale: {0} bar.capacity = Capacitate: {0} bar.unitcap = {0} {1}/{2} @@ -635,6 +636,8 @@ bar.progress = Progres bar.input = Necesită bar.output = Produce +units.processorcontrol = [lightgray]Controlat de Procesor + bullet.damage = [stat]{0}[lightgray] forță bullet.splashdamage = [stat]{0}[lightgray] forță explozivă ~[stat] {1}[lightgray] pătrate bullet.incendiary = [stat]incendiar @@ -821,7 +824,8 @@ mode.attack.description = Distruge baza inamicului. \n[gray]E nevoie de un nucle mode.custom = Reguli Personalizate rules.infiniteresources = Resurse Infinite -rules.reactorexplosions = Explozia Reactoarelor +rules.reactorexplosions = Reactoarele Explodează +rules.schematic = Se Pot Folosi Scheme rules.wavetimer = Valuri pe Timp rules.waves = Valuri rules.attack = Modul Atac @@ -846,7 +850,8 @@ rules.title.enemy = Inamici rules.title.unit = Unități rules.title.experimental = Experimental rules.title.environment = Mediu -rules.lighting = Luminozitate +rules.lighting = Luminozitate Ambientală +rules.enemyLights = Inamicii Luminează rules.fire = Foc rules.explosions = Explozia Deteriorează Blocul/Unitatea rules.ambientlight = Ambient @@ -936,6 +941,7 @@ block.cliff.name = Deal block.sand-boulder.name = Bolovan de Nisip block.grass.name = Iarbă block.slag.name = Zgură +block.space.name = Cosmos block.salt.name = Sare block.salt-wall.name = Perete de Sare block.pebbles.name = Pietricele @@ -1075,6 +1081,7 @@ block.power-source.name = Electricitate Infinită block.unloader.name = Descărcător block.vault.name = Seif block.wave.name = Wave +block.tsunami.name = Tsunami block.swarmer.name = Swarmer block.salvo.name = Salvo block.ripple.name = Ripple @@ -1114,6 +1121,7 @@ block.arc.name = Arc block.rtg-generator.name = Generator RTG block.spectre.name = Specter block.meltdown.name = Meltdown +block.foreshadow.name = Foreshadow block.container.name = Container block.launch-pad.name = Platformă de Lansare block.launch-pad-large.name = Platformă de Lansare Mare @@ -1139,12 +1147,13 @@ block.hyper-processor.name = Hyperprocesor block.logic-display.name = Monitor Logic block.large-logic-display.name = Monitor Logic Mare block.memory-cell.name = Celulă de Memorie +block.memory-bank.name = Bancă de Memorie team.blue.name = albastră team.crux.name = roșie team.sharded.name = portocalie team.orange.name = portocalie -team.derelict.name = abandon +team.derelict.name = abandonat team.green.name = verde team.purple.name = mov @@ -1251,7 +1260,7 @@ block.rotary-pump.description = O pompă avansată. Pompează mai mult lichid da block.thermal-pump.description = Cea mai bună pompă. block.conduit.description = Un bloc de transport al lichidelor. Împinge lichidele în față. Folosit cu pompe și alte conducte. block.pulse-conduit.description = Un bloc avansat de transport al lichidelor. Transportă lichidele mai rapid și stochează mai mult decât conductele standard. -block.plated-conduit.description = Transportă lichidele lafel de rapid precum conductele cu puls, dar este mai rezistent. Nu acceptă fluide din lateral de la altceva în afară de conducte.\nCurge mai puțin. +block.plated-conduit.description = Transportă lichidele lafel de rapid precum conductele cu puls, dar este mai rezistentă. Nu acceptă fluide din lateral de la altceva în afară de conducte.\nLichidul nu se varsă la exterior. block.liquid-router.description = Acceptă lichide dintr-o direcție și le distribuie în alte 3 direcții în mod egal. Poate stoca o anumită cantitate de lichid. Folositor pt a distribui lichidele dintr-o sursă către mai multe destinații. block.liquid-tank.description = Stochează o mare cantitate de lichid. Util pt depozita lichide pt situațiile în care cererea de materiale nu e constantă sau ca extra securitate pt răcirea blocurilor vitale. block.liquid-junction.description = Acționează ca un pod pt două conducte care se intersectează. Util în situația în care se intersectează 2 conducte diferite ce cară divesre lichide către diverse locații. @@ -1302,4 +1311,4 @@ block.cyclone.description = O mare armă anti-artilerie și anti-aer. Trage cu g block.spectre.description = O armă masivă cu două țevi. Trage cu gloanțe mari care găuresc armurile țintelor aeriene și artileriei. block.meltdown.description = O armă cu laser masivă. Trage cu un laser continuu la inamicii din apropiere. Necesită răcitor pt a opera. block.repair-point.description = Repară încontinuu cea mai deteriorată unitate din vecinătate. -block.segment.description = Deteriorează și distruge proiectilele din apropiere. Laserele nu sunt afectate. +block.segment.description = Deteriorează și distruge proiectilele din apropiere. Laserele nu sunt afectate. \ No newline at end of file diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index 716cf580fa..078a1cf6f4 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -20,7 +20,7 @@ gameover = Игра окончена gameover.pvp = [accent]{0}[] команда победила! highscore = [accent]Новый рекорд! copied = Скопировано. -indev.popup = [accent]v6[] находится на стадии [accent]alpha[].\n[lightgray]Это означает следующее:[]\n[scarlet]- Кампания не завершена[]\n- Отсутствие контента\n- Большинство [scarlet]ИИ единиц[] не работает правильно\n- Множество единиц не готово\n- Всё, что вы видите, может быть изменено или удалено.\n\nСообщайте о багах и вылетах на [accent]GitHub[]. +indev.popup = [accent]v6[] находится на стадии [accent]beta[].\n[lightgray]Это означает следующее:[]\n[scarlet]- Кампания не завершена[]\n- Звуки и музыка не готовы/отсутствуют\n- Всё, что вы видите, может быть изменено или удалено.\n\nСообщайте о багах и вылетах на [accent]GitHub[]. indev.notready = Эта часть игры ещё не готова load.sound = Звуки @@ -291,6 +291,8 @@ waiting = [lightgray]Ожидание… waiting.players = Ожидание игроков… wave.enemies = [lightgray]Враги: {0} wave.enemy = [lightgray]Остался {0} враг +wave.guardianwarn = Волн до прибытия Стража: [accent]{0}[]. +wave.guardianwarn.one = [accent]{0}[] волна до прибытия Стража. loadimage = Загрузить изображение saveimage = Сохранить изображение unknown = Неизвестно @@ -329,6 +331,7 @@ editor.generation = Генерация: editor.ingame = Редактировать в игре editor.publish.workshop = Опубликовать в Мастерской editor.newmap = Новая карта +editor.center = Центрировать workshop = Мастерская waves.title = Волны waves.remove = Удалить @@ -473,19 +476,12 @@ requirement.wave = Достигните {0} волны в зоне {1} requirement.core = Уничтожьте вражеское ядро в зоне {0} requirement.research = Исследуйте {0} requirement.capture = Захватите {0} -resume = Возобновить зону:\n[lightgray]{0} bestwave = [lightgray]Лучшая волна: {0} - -launch = < ЗАПУСК > launch.text = Высадка -launch.title = Запуск успешен -launch.next = [lightgray]следующая возможность на {0}-той волне -launch.unable2 = [scarlet]ЗАПУСК невозможен.[] -launch.confirm = Это [accent]запустит[] все ресурсы в вашем ядре.\nВы не сможете вернуться на эту базу. -launch.skip.confirm = Если вы пропустите сейчас, то вы не сможете произвести [accent]запуск[] до более поздних волн. +campaign.multiplayer = В исследованиях, при игре в кампании по сети, вы можете использовать только [accent]свои[] предметы, а [scarlet]не[] предметы сектора, в котором находитесь.\n\nДля отправки предметов на [accent]свои[] сектора воспользуйтесь [accent]пусковой площадкой[]. uncover = Раскрыть configure = Конфигурация выгрузки - +#TODO loadout = Груз resources = Ресурсы bannedblocks = Запрещённые блоки @@ -579,50 +575,51 @@ info.title = Информация error.title = [scarlet]Произошла ошибка error.crashtitle = Произошла ошибка unit.nobuild = [scarlet]Боевая единица не может строить -blocks.input = Вход -blocks.output = Выход -blocks.booster = Ускоритель -blocks.tiles = Необходимые плитки -blocks.affinities = Увеличение эффективности +lastaccessed = [lightgray]Последняя конфигурация от {0} +stat.input = Вход +stat.output = Выход +stat.booster = Ускоритель +stat.tiles = Необходимые плитки +stat.affinities = Увеличение эффективности block.unknown = [lightgray]??? -blocks.powercapacity = Вместимость энергии -blocks.powershot = Энергия/Выстрел -blocks.damage = Урон -blocks.targetsair = Воздушные цели -blocks.targetsground = Наземные цели -blocks.itemsmoved = Скорость перемещения -blocks.launchtime = Интервал запусков -blocks.shootrange = Радиус действия -blocks.size = Размер -blocks.displaysize = Размер дисплея -blocks.liquidcapacity = Вместимость жидкости -blocks.powerrange = Дальность передачи энергии -blocks.linkrange = Дальность связи -blocks.instructions = Инструкции -blocks.powerconnections = Количество соединений -blocks.poweruse = Потребляет энергии -blocks.powerdamage = Энергия/урон -blocks.itemcapacity = Вместимость предметов -blocks.memorycapacity = Размер памяти -blocks.basepowergeneration = Базовая генерация энергии -blocks.productiontime = Время производства -blocks.repairtime = Время полной регенерации -blocks.speedincrease = Увеличение скорости -blocks.range = Радиус действия -blocks.drilltier = Бурит -blocks.drillspeed = Базовая скорость бурения -blocks.boosteffect = Ускоряющий эффект -blocks.maxunits = Максимальное количество активных единиц -blocks.health = Прочность -blocks.buildtime = Время строительства -blocks.maxconsecutive = Макс. последовательность -blocks.buildcost = Стоимость строительства -blocks.inaccuracy = Разброс -blocks.shots = Выстрелы -blocks.reload = Выстрелы/секунду -blocks.ammo = Боеприпасы -blocks.shieldhealth = Прочность щита -blocks.cooldowntime = Время восстановления +stat.powercapacity = Вместимость энергии +stat.powershot = Энергия/Выстрел +stat.damage = Урон +stat.targetsair = Воздушные цели +stat.targetsground = Наземные цели +stat.itemsmoved = Скорость перемещения +stat.launchtime = Интервал запусков +stat.shootrange = Радиус действия +stat.size = Размер +stat.displaysize = Размер дисплея +stat.liquidcapacity = Вместимость жидкости +stat.powerrange = Дальность передачи энергии +stat.linkrange = Дальность связи +stat.instructions = Инструкции +stat.powerconnections = Количество соединений +stat.poweruse = Потребляет энергии +stat.powerdamage = Энергия/урон +stat.itemcapacity = Вместимость предметов +stat.memorycapacity = Размер памяти +stat.basepowergeneration = Базовая генерация энергии +stat.productiontime = Время производства +stat.repairtime = Время полной регенерации +stat.speedincrease = Увеличение скорости +stat.range = Радиус действия +stat.drilltier = Бурит +stat.drillspeed = Базовая скорость бурения +stat.boosteffect = Ускоряющий эффект +stat.maxunits = Максимальное количество активных единиц +stat.health = Прочность +stat.buildtime = Время строительства +stat.maxconsecutive = Макс. последовательность +stat.buildcost = Стоимость строительства +stat.inaccuracy = Разброс +stat.shots = Выстрелы +stat.reload = Выстрелы/секунду +stat.ammo = Боеприпасы +stat.shieldhealth = Прочность щита +stat.cooldowntime = Время восстановления bar.drilltierreq = Требуется бур получше bar.noresources = Недостаточно ресурсов @@ -634,6 +631,7 @@ bar.powerbalance = Энергия: {0}/с bar.powerstored = Накоплено: {0}/{1} bar.poweramount = Энергия: {0} bar.poweroutput = Выход энергии: {0} +bar.powerlines = Подключений: {0}/{1} bar.items = Предметы: {0} bar.capacity = Вместимость: {0} bar.unitcap = {0} {1}/{2} @@ -645,6 +643,8 @@ bar.progress = Прогресс строительства bar.input = Ввод bar.output = Вывод +units.processorcontrol = [lightgray]Управляется процессором + bullet.damage = [stat]{0}[lightgray] урона bullet.splashdamage = [stat]{0}[lightgray] урона в радиусе ~[stat] {1}[lightgray] блоков bullet.incendiary = [stat]зажигательный @@ -652,18 +652,20 @@ bullet.homing = [stat]самонаводящийся bullet.shock = [stat]шоковый bullet.frag = [stat]осколочный bullet.knockback = [stat]{0}[lightgray] отдачи +bullet.pierce = [stat]{0}[lightgray]x пробитие +bullet.infinitepierce = [stat]бесконечное пробитие bullet.freezing = [stat]замораживающий bullet.tarred = [stat]замедляющий, горючий bullet.multiplier = [stat]{0}[lightgray]x множитель боеприпасов bullet.reload = [stat]{0}[lightgray]x скорость стрельбы -unit.blocks = блоки +unit.blocks = блоков unit.powersecond = единиц энергии/секунду unit.liquidsecond = жидкостных единиц/секунду unit.itemssecond = предметов/секунду unit.liquidunits = жидкостных единиц unit.powerunits = энерг. единиц -unit.degrees = град. +unit.degrees = ° unit.seconds = сек. unit.minutes = мин. unit.persecond = /сек @@ -680,7 +682,7 @@ category.power = Энергия category.liquids = Жидкости category.items = Предметы category.crafting = Ввод/Вывод -category.shooting = Стрельба +category.shooting = Стрельба/Действие category.optional = Дополнительные улучшения setting.landscape.name = Только альбомный (горизонтальный) режим setting.shadows.name = Тени @@ -858,6 +860,7 @@ rules.title.unit = Боевые единицы rules.title.experimental = Экспериментально rules.title.environment = Окружение rules.lighting = Освещение +rules.enemyLights = Вражеские огни rules.fire = Огонь rules.explosions = Урон от взрывов блоков/единиц rules.ambientlight = Окружающий свет @@ -938,7 +941,7 @@ unit.beta.name = Бета unit.gamma.name = Гамма unit.scepter.name = Скипетр unit.reign.name = Власть -# unit.vela.name = Vela +unit.vela.name = Парус unit.corvus.name = Ворон block.resupply-point.name = Пункт снабжения @@ -947,6 +950,7 @@ block.cliff.name = Скала block.sand-boulder.name = Песчаный валун block.grass.name = Трава block.slag.name = Шлак +block.space.name = Космос block.salt.name = Соль block.salt-wall.name = Соляная стена block.pebbles.name = Галька @@ -992,6 +996,7 @@ block.darksand-water.name = Тёмный песок с водой block.char.name = Выжженная земля block.dacite.name = Дацит block.dacite-wall.name = Дацитовая стена +block.dacite-boulder.name = Дацитовый валун block.ice-snow.name = Заснеженный лёд block.stone-wall.name = Каменная стена block.ice-wall.name = Ледяная стена @@ -1086,6 +1091,7 @@ block.power-source.name = Источник энергии block.unloader.name = Разгрузчик block.vault.name = Хранилище block.wave.name = Волна +block.tsunami.name = Цунами block.swarmer.name = Роевик block.salvo.name = Залп block.ripple.name = Рябь @@ -1125,6 +1131,7 @@ block.arc.name = Дуга block.rtg-generator.name = Радиоизотопный термоэлектрический генератор block.spectre.name = Спектр block.meltdown.name = Испепелитель +block.foreshadow.name = Знамение block.container.name = Контейнер block.launch-pad.name = Пусковая площадка block.launch-pad-large.name = Большая пусковая площадка @@ -1188,7 +1195,7 @@ item.metaglass.description = Сверхпрочный сплав стекла. item.graphite.description = Минерализованный углерод, используемый для боеприпасов и электрических компонентов. item.sand.description = Обычный материал, который широко используется при выплавке, как при легировании, так и в качестве флюса. item.coal.description = Окаменелое растительное вещество, образовавшееся задолго до посева. Широко используется для производства топлива и ресурсов. -item.titanium.description = Редкий сверхлёгкий металл, широко используемый для транспортировки жидкостей, буров и авиации. +item.titanium.description = Редкий сверхлёгкий металл, широко используемый в транспортировке жидкостей, бурах и авиации. item.thorium.description = Плотный радиоактивный металл, используемый в качестве структурной опоры и ядерного топлива. item.scrap.description = Остатки старых сооружений и боевых единиц. Содержит небольшие количества многих различных металлов. item.silicon.description = Чрезвычайно полезный полупроводник. Применяется в солнечных панелях, сложной электронике и самонаводящихся боеприпасах. @@ -1206,12 +1213,12 @@ liquid.cryofluid.description = Инертная, неедкая жидкость block.message.description = Сохраняет сообщение. Используется для связи между союзниками. block.graphite-press.description = Сжимает куски угля в чистые листы графита. block.multi-press.description = Обновлённая версия графитового пресса. Использует воду и энергию для быстрой и эффективной обработки угля. -block.silicon-smelter.description = Соединяет песок с чистым углем. Производит кремний. +block.silicon-smelter.description = Соединяет песок с чистым углём. Производит кремний. block.kiln.description = Выплавляет песок и свинец в соединение, известное как метастекло. Требуется небольшое количество энергии для работы. block.plastanium-compressor.description = Производит пластан из нефти и титана. block.phase-weaver.description = Синтезирует фазовую ткань из радиоактивного тория и песка. Требуется огромное количество энергии для работы. -block.alloy-smelter.description = Объединяет титан, свинец, кремний и медь для производства кинетического сплава. -block.cryofluid-mixer.description = Смешивает воду и мелкий титановый порошок в криогенную жидкость. Неотъемлемая часть при использования ториевого реактора +block.alloy-smelter.description = Использует титан, свинец, кремний и медь для производства кинетического сплава. +block.cryofluid-mixer.description = Смешивает воду и мелкий титановый порошок в криогенную жидкость. Неотъемлемая часть при использовании ториевого реактора block.blast-mixer.description = Раздавливает и смешивает скопления спор с пиротитом для получения взрывчатого вещества. block.pyratite-mixer.description = Смешивает уголь, свинец и песок в легковоспламеняющийся пиротит. block.melter.description = Плавит металлолом в шлак для дальнейшей обработки или использования в турелях «Волна». @@ -1263,7 +1270,7 @@ block.rotary-pump.description = Продвинутый насос. Качает block.thermal-pump.description = Наилучший насос. block.conduit.description = Основной блок транспортировки жидкости. Перемещает жидкости вперед. Используется совместно с насосами и другими трубопроводами. block.pulse-conduit.description = Улучшенный блок транспортировки жидкости. Транспортирует жидкости быстрее и хранит больше, чем стандартные трубопроводы. -block.plated-conduit.description = Перемещает жидкости с той же скоростью, что и импульсные трубопроводы, но обладает большей прочностью. Не принимает жидкости со сторон, кроме как от других трубопроводов.\nПротекает меньше. +block.plated-conduit.description = Перемещает жидкости с той же скоростью, что и импульсные трубопроводы, но обладает большей прочностью. Не принимает жидкости со сторон, кроме как от других трубопроводов.\nНе протекает. block.liquid-router.description = Принимает жидкости из одного направления и выводит их до 3 других направлений в равной степени. Также может хранить определенное количество жидкости. Полезен для разделения жидкостей из одного источника на несколько целей. block.liquid-tank.description = Хранит большое количество жидкости. Используется для создания буферов в ситуациях с непостоянной потребностью в материалах или в качестве защиты для охлаждения жизненно важных блоков. block.liquid-junction.description = Действует как мост для двух пересекающихся трубопроводов. Полезен в ситуациях, когда два разных трубопровода переносят разные жидкости в разные места. @@ -1314,4 +1321,4 @@ block.cyclone.description = Большая турель, которая може block.spectre.description = Массивная двуствольная пушка. Стреляет крупными бронебойными снарядами по воздушным и наземным целям. block.meltdown.description = Массивная лазерная пушка. Заряжает и стреляет постоянным лазерным лучом в ближайших врагов. Требуется охлаждающая жидкость для работы. block.repair-point.description = Непрерывно лечит ближайшую поврежденную боевую единицу или мех в своём радиусе. -block.segment.description = Повреждает и разрушает приближающиеся снаряды. Не взаимодействует с лазерными лучами. +block.segment.description = Повреждает и разрушает приближающиеся снаряды. Не взаимодействует с лазерными лучами. \ No newline at end of file diff --git a/core/assets/bundles/bundle_sv.properties b/core/assets/bundles/bundle_sv.properties index 0d29e6a89e..8d3942eccb 100644 --- a/core/assets/bundles/bundle_sv.properties +++ b/core/assets/bundles/bundle_sv.properties @@ -570,49 +570,49 @@ info.title = Info error.title = [crimson]An error has occured error.crashtitle = An error has occured unit.nobuild = [scarlet]Unit can't build -blocks.input = Inmatning -blocks.output = Utmatning -blocks.booster = Booster -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Inmatning +stat.output = Utmatning +stat.booster = Booster +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Power Capacity -blocks.powershot = Power/Shot -blocks.damage = Skada -blocks.targetsair = Targets Air -blocks.targetsground = Targets Ground -blocks.itemsmoved = Move Speed -blocks.launchtime = Time Between Launches -blocks.shootrange = Range -blocks.size = Storlek -blocks.displaysize = Display Size -blocks.liquidcapacity = Liquid Capacity -blocks.powerrange = Power Range -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Power Use -blocks.powerdamage = Power/Damage -blocks.itemcapacity = Item Capacity -blocks.basepowergeneration = Base Power Generation -blocks.productiontime = Production Time -blocks.repairtime = Block Full Repair Time -blocks.speedincrease = Speed Increase -blocks.range = Range -blocks.drilltier = Drillables -blocks.drillspeed = Base Drill Speed -blocks.boosteffect = Boost Effect -blocks.maxunits = Max Active Units -blocks.health = Health -blocks.buildtime = Build Time -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Build Cost -blocks.inaccuracy = Inaccuracy -blocks.shots = Skott -blocks.reload = Shots/Second -blocks.ammo = Ammunition -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Power Capacity +stat.powershot = Power/Shot +stat.damage = Skada +stat.targetsair = Targets Air +stat.targetsground = Targets Ground +stat.itemsmoved = Move Speed +stat.launchtime = Time Between Launches +stat.shootrange = Range +stat.size = Storlek +stat.displaysize = Display Size +stat.liquidcapacity = Liquid Capacity +stat.powerrange = Power Range +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Power Use +stat.powerdamage = Power/Damage +stat.itemcapacity = Item Capacity +stat.basepowergeneration = Base Power Generation +stat.productiontime = Production Time +stat.repairtime = Block Full Repair Time +stat.speedincrease = Speed Increase +stat.range = Range +stat.drilltier = Drillables +stat.drillspeed = Base Drill Speed +stat.boosteffect = Boost Effect +stat.maxunits = Max Active Units +stat.health = Health +stat.buildtime = Build Time +stat.maxconsecutive = Max Consecutive +stat.buildcost = Build Cost +stat.inaccuracy = Inaccuracy +stat.shots = Skott +stat.reload = Shots/Second +stat.ammo = Ammunition +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Bättre Borr Krävs bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets. block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_th.properties b/core/assets/bundles/bundle_th.properties index 6a89ac29ca..1bf27c3387 100644 --- a/core/assets/bundles/bundle_th.properties +++ b/core/assets/bundles/bundle_th.properties @@ -7,21 +7,21 @@ link.reddit.description = ซับเรดดิท (subreddit) ของ Mind link.github.description = source code ของเกม link.changelog.description = รายการที่อัปเดต link.dev-builds.description = เวอร์ชั่นระหว่างพัฒนา (ไม่เสถียร) -link.trello.description = Official Trello board for planned features -link.itch.io.description = itch.io page with PC downloads -link.google-play.description = Google Play store listing -link.f-droid.description = F-Droid catalogue listing -link.wiki.description = Official Mindustry wiki -link.suggestions.description = Suggest new features +link.trello.description = Trello board ทางการสำหรับฟีเจอร์ต่างๆที่วางแผนไว้ +link.itch.io.description = หน้าเว็บ itch.io สำหรับดาวน์โหลดบน PC +link.google-play.description = หน้า Google Play store ของเกม +link.f-droid.description = หน้าแคตาลอค F-Droid ของเกม +link.wiki.description = วิกิของ Mindustry อย่างเป็นทางการ +link.suggestions.description = เสนอฟีเจอร์ใหม่ linkfail = ไม่สามารถเปิดลิ้งค์ได้\nคัดลอก URL ลงในคลิปบอร์ดแล้ว screenshot = Screenshot บันทึกที่ {0} screenshot.invalid = แมพใหญ่เกินไป, หน่วยความจำอาจจะไม่พอสำหรับ screenshot. -gameover = Game Over +gameover = จบเกม gameover.pvp = ทีมที่ชนะคือทีม[accent] {0}[]! highscore = [accent]คะแนนสูงสุดใหม่! copied = คัดลอกแล้ว. -indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[]. -indev.notready = This part of the game isn't ready yet +indev.popup = [accent]เวอร์ชั่น v6[] ณ ขณะนี้อยู่ในช่วง [accent]alpha[].\n[lightgray]นั้นหมายถึง:[]\n[scarlet]- เคมเปญไม่ยังเสร็จสมบูรณ์ []\n- เนื้อหาบางอย่างขาดหาย\n - [scarlet]AI ของยูนิต[] ส่วนใหญ่ทำงานได้แบบไม่สมบูรณ์\n- ยูนิตส่วนมากยังไม่เสร็จ\n- ที่อย่างที่เห็นอาจเปลี่ยนแปลงได้หรือลบออกโดยสิ้นเชิงในอนาคต\n\nแจ้งบัคหรือปัญหาที่พบเจอได้ที่ [accent]Github[]. +indev.notready = ส่วนนี้ของเกมยังไม่พร้อมให้ใช้งาน load.sound = เสียง load.map = แมพ @@ -31,7 +31,7 @@ load.system = ระบบ load.mod = มอด load.scripts = สคริปต์ -be.update = A new Bleeding Edge build is available: +be.update = เวอร์ชั้นล่าสุดออกแล้ว: be.update.confirm = ดาวน์โหลดเวอร์ชั่นใหม่แล้วรีสตาร์ทเลยไหม? be.updating = กำลังอัปเดต... be.ignore = ยกเลิก @@ -42,7 +42,7 @@ schematic = แผนผัง schematic.add = กำลังบันทึกแผนผัง... schematics = แผนผัง schematic.replace = มีแผนผังที่ใช้ชื่อนี้แล้ว. แทนที่เลยไหม? -schematic.exists = A schematic by that name already exists. +schematic.exists = มีแผนผังในชื่อนั้นอยู่แล้ว schematic.import = นำเข้าแผนผัง... schematic.exportfile = ส่งออกไฟล์ schematic.importfile = นำเข้าไฟล์ @@ -62,17 +62,17 @@ stat.built = จำนวนสิ่งก่อสร้างที่สร stat.destroyed = จำนวนสิ่งก่อสร้างของศัตรูที่ทำลายไปได้:[accent] {0} stat.deconstructed = จำนวนสิ่งก่อสร้างที่ถูกทำลายไป:[accent] {0} stat.delivered = ทรัพยากรที่ส่งไปได้: -stat.playtime = Time Played:[accent] {0} +stat.playtime = ระยะเวลาที่เล่นไป:[accent] {0} stat.rank = ระดับ: [accent]{0} -globalitems = [accent]Global Items +globalitems = [accent]ไอเท็มโกลบอล map.delete = คุณแน่ใจหรือว่าจะลบแมพชื่อ "[accent]{0}[]"? level.highscore = คะแนนสูงสุด: [accent]{0} level.select = เลือกด่าน level.mode = เกมโหมด: coreattack = < แกนกลางกำลังถูกโจมตี! > nearpoint = [[ [scarlet]ออกจากดรอปพอยท์ด่วน IMMEDIATELY[] ]\nการทำลายล้างกำลังใกล้เข้ามา -database = ฐานข้อมูหลัง +database = ฐานข้อมูลหลัก savegame = เซฟเกม loadgame = โหลดเกม joingame = เข้าร่วมเกม @@ -90,12 +90,12 @@ maps.browse = ค้นหาแมพ continue = ต่อ maps.none = [lightgray]ไม่มีแมพ! invalid = ไม่ถูกต้อง -pickcolor = Pick Color +pickcolor = เลือกสี preparingconfig = กำลังเตรียม Config -preparingcontent = กำลังเตรียม Content -uploadingcontent = กำลังอัปโหลด Content +preparingcontent = กำลังเตรียมเนื้อหา +uploadingcontent = กำลังอัปโหลดเนื้อหา uploadingpreviewfile = กำลังอัปโหลดไฟล์พรีวิว -committingchanges = Comitting Changes +committingchanges = กำลังทำการเปลี่ยนแปลง done = เรียบร้อย feature.unsupported = อุปกรณ์ของคุณไม่รองรับฟีเจอร์นี้ @@ -106,53 +106,53 @@ mods.none = [lightgray]ไม่พบมอด! mods.guide = คู่มือการทำมอด mods.report = รายงานบัค mods.openfolder = เปิดมอดโฟลเดอร์ -mods.reload = Reload -mods.reloadexit = The game will now exit, to reload mods. +mods.reload = โหลดใหม่ +mods.reloadexit = เกมจะออกเพื่อจะโหลดมอด mod.display = [gray]Mod:[orange] {0} mod.enabled = [lightgray]เปิดใช้งาน mod.disabled = [scarlet]ปิดใช้งาน mod.disable = ปิดใช้งาน -mod.content = Content: +mod.content = เนื้อหา: mod.delete.error = ไม่สามารถลบมอดได้. ไฟล์อาจอยู่ในระหว่างการใช้งาน. -mod.requiresversion = [scarlet]Requires min game version: [accent]{0} -mod.outdated = [scarlet]Not compatible with V6 (no minGameVersion: 105) +mod.requiresversion = [scarlet]เวอร์ชั่นเกมขั้นต่ำที่ต้องการ: [accent]{0} +mod.outdated = [scarlet]ไม่สามารถใช้ได้ในเวอร์ชั่น V6 (ไม่มี minGameVersion: 105) mod.missingdependencies = [scarlet]dependencies หาย: {0} -mod.erroredcontent = [scarlet]Content Errors -mod.errors = Errors have occurred loading content. -mod.noerrorplay = [scarlet]You have mods with errors.[] Either disable the affected mods or fix the errors before playing. +mod.erroredcontent = [scarlet]เนื้อหาผิดพลาด +mod.errors = มีข้อผิดพลาดเกิดขึ้นระหว่าโหลดเนื้อหา +mod.noerrorplay = [scarlet]คุณมีมอดที่มีข้อผิดพลาด.[] กรุณาปิดมอดนั้นๆหรือแก้ไขข้อผิดพลาดก่อนที่จะเล่น mod.nowdisabled = [scarlet]มอด '{0}' ไม่มี dependencies:[accent] {1}\n[lightgray]จำเป็นต้องโหลดมอดพวกนี้ก่อน\nมอดนี้จะถูกปิดใช้งานโดยอัตโนมัติ mod.enable = เปิดใช้งาน mod.requiresrestart = เกมจะปิดลงเพื่อใส่มอด mod.reloadrequired = [scarlet]จำเป็นต้องรีโหลด mod.import = นำเข้ามอด -mod.import.file = Import File +mod.import.file = นำเข้าไฟล์ mod.import.github = นำเข้ามอดจาก Github -mod.jarwarn = [scarlet]JAR mods are inherently unsafe.[]\nMake sure you're importing this mod from a trustworthy source! -mod.item.remove = This item is part of the[accent] '{0}'[] mod. To remove it, uninstall that mod. +mod.jarwarn = [scarlet]มอดไฟล์ JAR นั้นค่อนข้างไม่ปลอดภัย.[]\nกรุณาเช็คให้แน่ใจว่าคุณนำเข้ามอดนี้จะแหล่งที่เชื่อถือได้! +mod.item.remove = ไอเทมนี้เป็นส่วนหนึ่งของมอด[accent] '{0}'[]. หากต้องการนำออก กรุณาถอดการติดตั้งมอดนั้น mod.remove.confirm = มอดนี้จะถูกลบ mod.author = [lightgray]ผู้สร้าง:[] {0} -mod.missing = เซฟนี้มีมอดที่คุณอัปเดตหรือไม่ได้ติดตั้งแล้ว. อาจทำให้เซฟเสีย. คุณแน่จะหรือว่าจะโหลดเซฟนี้?\n[lightgray]Mods:\n{0} +mod.missing = เซฟนี้มีมอดที่คุณอัปเดตหรือไม่ได้ติดตั้งแล้ว. อาจทำให้เซฟเสีย. คุณแน่จะหรือว่าจะโหลดเซฟนี้?\n[lightgray]มอดที่ใช้:\n{0} mod.preview.missing = ก่อนที่จะนำมอดไปลงใน workshop, คุณต้องใส่รูปพรีวิวก่อน\nใส่รูปชื่อ[accent] preview.png[] ลงในโฟลเดอร์ของมอดแล้วลองอีกครั้ง mod.folder.missing = มอดที่อยู่ในรูปแบบโฟลเดอร์เท่านั้นที่สามารถลงใน workshop ได้\nunzip ไฟล์แล้วลบไฟล์ zip เก่า แล้วรีสตาร์ทเกมหรือรีโหลดมอด -mod.scripts.disable = Your device does not support mods with scripts. You must disable these mods to play the game. +mod.scripts.disable = เครื่องของคุณไม่รองรับมอดที่มี scripts. คุณจำเป็นต้องปิดมอดเหล่านี้ก่อนจึงจะสามารถเล่นได้. about.button = เกี่ยวกับ name = ชื่อ: noname = ใส่ชื่อ[accent] ผู้เล่น[] ก่อน. -planetmap = Planet Map -launchcore = Launch Core +planetmap = แผนที่ดาวเคราะห์ +launchcore = ส่ง Core filename = ชื่อไฟล์: -unlocked = content ใหม่ปลดล็อค! +unlocked = เนื้อหาใหม่ปลดล็อค! completed = [accent]สำเร็จ techtree = ความคืบหน้าในการวิจัย research.list = [lightgray]วิจัย: research = วิจัย researched = [lightgray]{0} วิจัยแล้ว. -research.progress = {0}% complete +research.progress = เสร็จแล้ว {0}% players = {0} ผู้เล่น players.single = {0} ผู้เล่น -players.search = search -players.notfound = [gray]no players found +players.search = ค้นหา +players.notfound = [gray]ไม่พบผู้เล่น server.closing = [accent]กำลังปิดเซิฟเวอร์... server.kicked.kick = คุณถูกเตะออกจากเซิฟเวอร์! server.kicked.whitelist = คุณไม่ได้อยู่ใน whitelisted @@ -168,8 +168,8 @@ server.kicked.nameInUse = มีคนที่ใช้ชืชื่อนี server.kicked.nameEmpty = ชื่อของคุณไม่สามารถใช้ได้ server.kicked.idInUse = คุณเชื่อมต่อกับเซิฟเวอร์นี้อยู่แล้ว เราไม่อนุญาตให้เชื่อมต่อ 2 บัญชีในเซฟเวอร์เดียวกัน server.kicked.customClient = เซิฟเวอร์นี้ไม่รองรับ builds ปรับแต่ง. กรุณาโหลดของ official. -server.kicked.gameover = Game over! -server.kicked.serverRestarting = The server is restarting. +server.kicked.gameover = จบเกม! +server.kicked.serverRestarting = เซิฟเวอร์กำลังเริ่มใหม่. server.versions = เวอร์ชั่นของคุณ:[accent] {0}[]\nเวอร์ชั่นของเซิฟเวอร์:[accent] {1}[] host.info = ปุ่ม [accent]โฮสต์[] นั้นโฮสต์เซฟเวอร์ที่พอร์ท [scarlet]6567[]. \nทุกคนที่อยู่ใน [lightgray]wifi หรือ local network[] เดียวกันจะสามารถเห็นเซิฟเวอร์ของคุณในลิสของเซิฟเวอร์ได้\n\nถ้าคุณต้องการให้ผู้เล่นอื่นๆสามารถเชื่อมต่อได้จากทุกที่โดยใช้ IP, จำเป็นจะต้องใช้การ [accent]port forwarding[] \n\n[lightgray]Note: ถ้าผู้เล่นคนใดมีปัญหาในการเชื่อมต่อ LAN ของคุณ เช็คให้แน่ใจว่าคุณได้อนุญาตให้ Mindustry เข้าถึง local network ของคุณในการตั้งค่า firewall. จำให้ว่า network สาธารณะบางครั้งไม่อนุญาตการค้นหาเซิฟเวอร์ join.info = คุณสามารถใส่ [accent]IP ของเซิฟเวอร์[] เพื่อที่จะเชื่อมต่อหรือค้นหา เซิฟเวอร์ที่ใช้[accent]local network[] จะสามารถเชื่อมโดยใช้\n LAN หรือ WAN ก็ได้\n\n[lightgray]โน้ต: เกมนี้ไม่มีระบบค้นหาเซิฟเวอร์ global ให้อัตโนมัติserver list; ถ้าคุณต้องการเชื่อมต่อกับเซิฟเวอร์โดยใช้ IP, คุณจำเป็นต้องถาม IP ผู้เล่นที่โฮสต์เซิฟเวอร์นั้นๆ. @@ -185,9 +185,9 @@ server.refreshing = กำลังรีเฟรชเซิฟเวอร์ hosts.none = [lightgray]ไม่พบเซิฟเวอร์ใน local! host.invalid = [scarlet]ไม่สามารถเชื่อมต่อกับโฮสต์ได้ -servers.local = Local Servers -servers.remote = Remote Servers -servers.global = Community Servers +servers.local = เซิฟเวอร์ Local +servers.remote = เซิฟเวอร์ Remote +servers.global = เซิฟเวอร์ Community trace = Trace ผู้เล่น/ แกะรอยผู้เล่น trace.playername = ชื่อผู้เล่น: [accent]{0} @@ -269,7 +269,7 @@ copylink = คัดลอกลิ้งค์ back = กลับ data.export = ส่งออกข้อมูล data.import = นำเข้าข้อมูล -data.openfolder = Open Data Folder +data.openfolder = เปิดโฟลเดอร์ข้อมูล data.exported = ข้อมูลส่งออกแล้ว data.invalid = นี่ไม่ใช่ข้อมูลเกมที่ถูกต้อง. data.import.confirm = การนำเข้าข้อมูลจากภายนอกจะเขียนทับข้อมูลเก่า[scarlet]ทั้งหมด[]\n[accent]และไม่สามารถย้อนกลับได้![]\n\nหลังจากที่นำข้อมูลแล้วเกมจะปิดลงโดยทันที @@ -278,7 +278,7 @@ quit.confirm.tutorial = คุณแน่ใจหรือว่าคุณ loading = [accent]กำลังโหลด... reloading = [accent]กำลังรีโหลดมอด... saving = [accent]กำลังเซฟ... -respawn = [accent][[{0}][] to respawn in core +respawn = [accent][[{0}]][]เพื่อเกิดใหม่ที่ core cancelbuilding = [accent][[{0}][]เพื่อเคลียแผน selectschematic = [accent][[{0}][]เพื่อเลือกและคัดลอก pausebuilding = [accent][[{0}][]เพื่อหยุดการสร้างชั่วคราว @@ -315,7 +315,7 @@ publish.error = การเผยแพร่ไอเท็มดังต่ steam.error = ไม่สามารถเริ่ม Steam service ได้\nError: {0} editor.brush = แปรง -editor.openin = เปิดมน Editor +editor.openin = เปิดใน Editor editor.oregen = การเกิดของแร่ editor.oregen.info = การเกิดของแร่: editor.mapinfo = ข้อมูลของแมพ @@ -331,13 +331,13 @@ editor.newmap = แมพใหม่ workshop = Workshop waves.title = Waves waves.remove = ลบ -waves.never = +waves.never = <ไม่เคย> waves.every = ทุกๆ waves.waves = wave(s) waves.perspawn = ต่อสปาวน์ -waves.shields = shields/wave -waves.to = to -waves.guardian = Guardian +waves.shields = เกราะ/wave +waves.to = ถึง +waves.guardian = การ์เดียน waves.preview = พรีวิว waves.edit = แก้ไข... waves.copy = คัดลอกไปยังคลิปบอร์ด @@ -346,8 +346,8 @@ waves.invalid = waves ในคลิปบอร์ดไม่ถูกต้ waves.copied = คัดลอก Waves แล้ว waves.none = ไม่ได้กำหนดศัตรู\nwave layouts เปล่าจะถูกแทนที่โดย layout ค่าเริ่มต้นของเกม -wavemode.counts = counts -wavemode.totals = totals +wavemode.counts = จำนวน +wavemode.totals = ทั้งหมด wavemode.health = health editor.default = [lightgray]<ค่าเริ่่มต้น> @@ -415,8 +415,8 @@ toolmode.drawteams.description = วาดทีมแทนที่จะเ filters.empty = [lightgray]ไม่มีฟิลเตอร์! เพิ่มด้วยปุ่มด้านล่างนี้ filter.distort = บิดเบือน filter.noise = นอยส์ -filter.enemyspawn = Enemy Spawn Select -filter.corespawn = Core Select +filter.enemyspawn = เบือกที่เกิดศัตรู +filter.corespawn = เลือก Core filter.median = เฉลี่ย filter.oremedian = เฉลี่ยแร่ filter.blend = ผสมผสาน @@ -436,7 +436,7 @@ filter.option.circle-scale = สเกลวงกลม filter.option.octaves = เลอะเลือน filter.option.falloff = หลุด filter.option.angle = มุม -filter.option.amount = Amount +filter.option.amount = จำนวน filter.option.block = บล็อค filter.option.floor = พื้น filter.option.flooronto = พื้น Target @@ -474,7 +474,7 @@ requirement.capture = Capture {0} resume = เล่นต่อในโซน:\n[lightgray]{0} bestwave = [lightgray]Wave สูงสุด: {0} launch = < ส่ง > -launch.text = Launch +launch.text = ส่ง launch.title = ส่งเรียบร้อย launch.next = [lightgray]โอกาสครั้งหน้าที่ wave {0} launch.unable2 = [scarlet]ไม่สามารถส่งได้[] @@ -483,8 +483,8 @@ launch.skip.confirm = ถ้าคุณข้ามตอนนี้, คุ uncover = เปิดเผย configure = ตั้งค่า Loadout loadout = Loadout -resources = Resources -bannedblocks = Banned Blocks +resources = ทรัพยากร +bannedblocks = บล็อคต้องห้าม addall = เพิ่มทั้งหมด launch.destination = Destination: {0} configure.invalid = จำนวนต้อยู่ระหว่าง 0 ถึง {0}. @@ -508,18 +508,18 @@ error.io = Network I/O error. error.any = Unknown network error. error.bloom = ไม่สามารถเริ่มต้น bloom ได้\nอุปกรณ์ของคุณอาจไม่รองรับ -weather.rain.name = Rain -weather.snow.name = Snow -weather.sandstorm.name = Sandstorm -weather.sporestorm.name = Sporestorm +weather.rain.name = ฝน +weather.snow.name = หิมะ +weather.sandstorm.name = พายุทราย +weather.sporestorm.name = พายุสปอร์ -sectors.unexplored = [lightgray]Unexplored -sectors.resources = Resources: -sectors.production = Production: -sectors.stored = Stored: -sectors.resume = Resume -sectors.launch = Launch -sectors.select = Select +sectors.unexplored = [lightgray]ยังไม่ได้สำรวจ +sectors.resources = ทรัพยากร: +sectors.production = การผลิต: +sectors.stored = เก็บ: +sectors.resume = ทำต่อ +sectors.launch = ส่ง +sectors.select = เลือก sectors.nonelaunch = [lightgray]none (sun) sector.groundZero.name = Ground Zero @@ -534,22 +534,22 @@ sector.tarFields.name = Tar Fields sector.saltFlats.name = Salt Flats sector.fungalPass.name = Fungal Pass -sector.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on. -sector.frozenForest.description = Even here, closer to mountains, the spores have spread. The frigid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders. -sector.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing. -sector.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills. -sector.ruinousShores.description = Past the wastes, is the shoreline. Once, this location housed a coastal defense array. Not much of it remains. Only the most basic defense structures have remained unscathed, everything else reduced to scrap.\nContinue the expansion outwards. Rediscover the technology. -sector.stainedMountains.description = Further inland lie the mountains, yet untainted by spores.\nExtract the abundant titanium in this area. Learn how to use it.\n\nThe enemy presence is greater here. Do not give them time to send their strongest units. -sector.overgrowth.description = This area is overgrown, closer to the source of the spores.\nThe enemy has established an outpost here. Build Titan units. Destroy it. Reclaim that which was lost. -sector.tarFields.description = The outskirts of an oil production zone, between the mountains and desert. One of the few areas with usable tar reserves.\nAlthough abandoned, this area has some dangerous enemy forces nearby. Do not underestimate them.\n\n[lightgray]Research oil processing technology if possible. -sector.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks. -sector.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers. -sector.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores. +sector.groundZero.description = ที่ที่ดีที่สุดในการเริ่มต้นอีกครั้ง. ศัตรูมีน้อย. ทรัพยากรน้อยฃ.\nเก็บตะกั่วและทองแดงให้ได้มากที่สุด.\nแล้วไปต่อ. +sector.frozenForest.description = แม้แต่ที่นี่, ที่ที่อยู่ใกล้ภูเขา, สปอร์ก็ยังแพร่มาถึงที่นี่. อากาศที่เย็นเยือกไม่สามารถหยุดยั้งพวกมันได้ตลอดไป.\n\nเริ่มต้นการใช้ไฟฟ้า. สร้างเครื่องกำเนิดไฟฟ้าเผาไหม้ถ่าน. เรียนรู้ที่จะใช้เครื่องซ่อมแซม. +sector.saltFlats.description = ณ ขอบของทะเลทราย เป็นที่ตั้งของ Salt Flats. สามารถพบทรัพยากรบางอย่างได้ที่นี่.\n\nศัตรูได้ตั้งฐานเก็บทรัพยากรไว้ที่นี่. ทำลาย core ของพวกมัน. อย่าให้มีอะไรเหลือ. +sector.craters.description = น้ำขังอยู่ในหลุมอุกกาบาศนี้, ที่นี้เป็นอนุสรณ์ของสองคราม. ยึดพื้นที่นี่มา. เก็บทราย. เผากระจกเมต้า. ปั๊มน้ำเพื่อมาหล่อเย็นป้อมปืนและแท่นขุดเจาะ. +sector.ruinousShores.description = ต่อจากของเสียต่างๆ, เป็นที่ตั้งของชายฝั่ง. ครั้งก่อน, ที่นี่เคยเป็นที่ตั้งของฐานป้องกันชายฝั่ง. ณ ตอนนี้แทบจะไม่เหลือแล้ว. มีเหลือแค่ระบบการป้องกันพื้นฐาน, ทุกอย่างที่เหลือถูกทำลายเหลือเพียงแค่เศษเหล็ก.\nทำการขยายการสำรวจต่อไป. ค้นพบกับเทคโนโลยีอีกครั้ง. +sector.stainedMountains.description = เข้าลึกไปในพื้นที่ จะพบกับภูเขา, ซึ่งยังไม่ถูกสปอร์แตะต้อง.\nขุดไทเทเนียมที่อุดมสมบูรณ์ในพื้นที่นี้. เรียนรู้ที่จะใช้มัน.\n\nมีศัตรูมากขึ้นในบริเวณนี้. อย่าปล่อยให้พวกมันปล่อยยูนิตที่แข็งแกร่งที่สุดของพวกมันออกมา. +sector.overgrowth.description = พื้นที่นี้ถูกปกคลุมไปด้วยพืช, ใกล้กับแหล่งกำเนิของสปอร์.\nศัตรูได้ตั้งฐานเฝ้าระวังไว้ที่นี่. สร้างยูนิตไททัน. ทำลายฐานซะ. แล้วนำสิ่งที่ถูกยึดไปกลับคืนมา. +sector.tarFields.description = ขอบของพื้นที่ผลิตน้ำมัน, อยู่ระหว่างภูเขาและทะเลทราย. หนึ่งในพื้นที่ที่มีแหล่งน้ำมันดิบที่ใช้ได้.\nแม้ว่าจะถูกทิ้งร้าง, พื้นที่นี้ยังคงมีทัพของศัตรูอยู่ใกล้ๆ. อย่าประมาทกับพวกมัน.\n\n[lightgray]วิจัยเทคโนโลยีการแปรรูปน้ำมันหากเป็นไปได้. +sector.desolateRift.description = เป็นพื้นที่ที่อันตรายมาก. ทรัพยากรมากมาย, แต่พื้นที่น้อย. ความเสี่ยงการโดนทำลายล้างสูง. ออกไปจากที่นี่ให้ไวที่สุด. อย่าถูกหลอกโดนระยะเวลาระหว่างการโจมตีของศัตรูที่เว้นไว้นานกว่าปกติ. +sector.nuclearComplex.description = สถานที่ผลิตและแปรรูปทอเรี่ยมเก่า, ถูกทำลายกลายเป็นซาก.\n[lightgray]วิจัยทอเรี่ยมและวิธีการใช้มัน.\n\nศัตรูในบริเวณนี้มีจำนวนมาก, ตรวจตราหาผู้บุกรุกอยู่ตลอดเวลา. +sector.fungalPass.description = พื้นที่ระหว่างพื้นที่สูงและต่ำของภูเขา, พื้นที่นี้เต็มไปด้วยสปอร์. ฐานลาดตระเวนขนาดเล็กของศัตรูตั้งอยู่ที่นี่.\nทำลายมันซะ.\nใช้ยูนิตเด็กเกอร์และครอว์เลอร์. ทำลาย core ทั้งสองซะ. settings.language = ภาษา settings.data = ข้อมูลเกม settings.reset = รีเซ็ตเป็นค่าเริ่มต้น -settings.rebind = Rebind +settings.rebind = แก้ไขปุ่ม settings.resetKey = Reset settings.controls = การควบคุม settings.game = เกม @@ -558,65 +558,65 @@ settings.graphics = กราฟิก settings.cleardata = เคลียร์ข้อมูลเกม... settings.clear.confirm = คุณแน่ใจหรือว่าจะเคลียร์ข้อมูลเกม?\nสิ่งที่ทำไปแล้วจะไม่สามารถย้อนกลับได้! settings.clearall.confirm = [scarlet]คำเตือน![]\nการกระทำนี้จะลบข้อมูลทั้งหมด นั้นรวมไปถึงเซฟ, แมพ, สิ่งที่ปลดล็อคแล้วและ keybinds.\nเมื่อคุณกด 'โอเค' เกมจะลบข้อมูลทุกอย่างและออกโดยอัตโนมัติ -settings.clearsaves.confirm = Are you sure you want to clear all your saves? -settings.clearsaves = Clear Saves +settings.clearsaves.confirm = คุณแน่ใจหรือว่าคุณต้องการเคลียร์เซฟทั้งหมด? +settings.clearsaves = เคลียร์เซฟ paused = [accent]< หยุดชั่วคราว > clear = เคลียร์ banned = [scarlet]แบน -unplaceable.sectorcaptured = [scarlet]Requires captured sector +unplaceable.sectorcaptured = [scarlet]ต้องการ captured sector yes = ใช่ no = ไม่ info.title = ข้อมูล error.title = [crimson]มีบางอย่างผิดพลาดเกิดขึ้น error.crashtitle = มีบางอย่างผิดพลาดเกิดขึ้น -unit.nobuild = [scarlet]Unit can't build -blocks.input = นำเข้า -blocks.output = ส่งออก -blocks.booster = บูสเตอร์ -blocks.tiles = Required Tiles -blocks.affinities = Affinities +unit.nobuild = [scarlet]ยูนิตไม่สามารถสร้างได้ +stat.input = นำเข้า +stat.output = ส่งออก +stat.booster = บูสเตอร์ +stat.tiles = ต้องการ Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = ความจุพลังงาน -blocks.powershot = หน่วยพลังงาน/นัด -blocks.damage = ดาเมจ -blocks.targetsair = ยิงอากาศยาน -blocks.targetsground = ยิงภาคพื้นดิน -blocks.itemsmoved = ความเร็วเคลื่อนที่ -blocks.launchtime = เวลาระหว่างการส่ง -blocks.shootrange = ระยะยิง -blocks.size = ขนาด -blocks.displaysize = Display Size -blocks.liquidcapacity = จุของเหลว -blocks.powerrange = ระยะพลังงาน -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = จำนวนการเชื่อมต่อสูงสุด -blocks.poweruse = ใช้พลังงาน -blocks.powerdamage = หน่วยพลังงาน/ดาเมจ -blocks.itemcapacity = จุไอเท็ม -blocks.basepowergeneration = กำเนิดพลังงานพื้นฐาน -blocks.productiontime = เวลาที่ใช้ในการผลิต -blocks.repairtime = เวลาที่ใช้ในการซ่อมแซมให้สมบูรณ์ -blocks.speedincrease = เพิ่มความเร็ว -blocks.range = ระยะ -blocks.drilltier = ขุดได้ -blocks.drillspeed = ความเร็วขุดพื้นฐาน -blocks.boosteffect = แอฟเฟ็คของบูสต์ -blocks.maxunits = จำนวนยูนิตสูงสุด -blocks.health = เลือด -blocks.buildtime = เวลาในการสร้าง -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = ใช้ -blocks.inaccuracy = ความคลาดเคลื่อน -blocks.shots = นัด -blocks.reload = นัด/วินาที -blocks.ammo = กระสุน -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = ความจุพลังงาน +stat.powershot = หน่วยพลังงาน/นัด +stat.damage = ดาเมจ +stat.targetsair = ยิงอากาศยาน +stat.targetsground = ยิงภาคพื้นดิน +stat.itemsmoved = ความเร็วเคลื่อนที่ +stat.launchtime = เวลาระหว่างการส่ง +stat.shootrange = ระยะยิง +stat.size = ขนาด +stat.displaysize = ขนาดที่โชว์ +stat.liquidcapacity = จุของเหลว +stat.powerrange = ระยะพลังงาน +stat.linkrange = Link Range +stat.instructions = คำแนะนำ +stat.powerconnections = จำนวนการเชื่อมต่อสูงสุด +stat.poweruse = ใช้พลังงาน +stat.powerdamage = หน่วยพลังงาน/ดาเมจ +stat.itemcapacity = จุไอเท็ม +stat.basepowergeneration = กำเนิดพลังงานพื้นฐาน +stat.productiontime = เวลาที่ใช้ในการผลิต +stat.repairtime = เวลาที่ใช้ในการซ่อมแซมให้สมบูรณ์ +stat.speedincrease = เพิ่มความเร็ว +stat.range = ระยะ +stat.drilltier = ขุดได้ +stat.drillspeed = ความเร็วขุดพื้นฐาน +stat.boosteffect = แอฟเฟ็คของบูสต์ +stat.maxunits = จำนวนยูนิตสูงสุด +stat.health = เลือด +stat.buildtime = เวลาในการสร้าง +stat.maxconsecutive = ติดต่อกันสูงสุด +stat.buildcost = ใช้ +stat.inaccuracy = ความคลาดเคลื่อน +stat.shots = นัด +stat.reload = นัด/วินาที +stat.ammo = กระสุน +stat.shieldhealth = เลือดของเกราะ +stat.cooldowntime = เวลา Cooldown bar.drilltierreq = จำเป็นต้องใช้เครื่องขุดที่ดีกว่า -bar.noresources = Missing Resources -bar.corereq = Core Base Required +bar.noresources = ทรัพยากรหาย +bar.corereq = ฐาน Core ที่ต้องการ bar.drillspeed = ความเร็วขุด: {0}/s bar.pumpspeed = ความเร็วปั้ม: {0}/s bar.efficiency = ประสิทธิภาพ: {0}% @@ -627,7 +627,7 @@ bar.poweroutput = พลังงานออก: {0} bar.items = ไอเท็ม: {0} bar.capacity = ความจุ: {0} bar.unitcap = {0} {1}/{2} -bar.limitreached = [scarlet] {0} / {1}[white] {2}\n[lightgray][[unit disabled] +bar.limitreached = [scarlet] {0} / {1}[white] {2}\n[lightgray][[ยูนิตถูกปิด] bar.liquid = ของเหลว bar.heat = ความร้อน bar.power = พลังงาน @@ -660,11 +660,11 @@ unit.persecond = /วินาที unit.perminute = /min unit.timesspeed = เท่าเร็วขึ้น unit.percent = % -unit.shieldhealth = shield health +unit.shieldhealth = เลือดเกราะ unit.items = ไอเท็ม -unit.thousands = k -unit.millions = mil -unit.billions = b +unit.thousands = พัน +unit.millions = ล้าน +unit.billions = พันล้าน category.general = ทั่วไป category.power = พลังงาน category.liquids = ของเหลว @@ -677,13 +677,13 @@ setting.shadows.name = เงา setting.blockreplace.name = แนะนำบล็อคโดยอัตโนมัติ setting.linear.name = การกรองเชิงเส้น setting.hints.name = คำแนะนำ -setting.flow.name = Display Resource Flow Rate[scarlet] (experimental) +setting.flow.name = แสดงอัตราการไหลของทรัพยากร[scarlet] (รุ่นทดลอง) setting.buildautopause.name = หยุดสร้างชั่วคราวแบบอัตโนมัติ -setting.mapcenter.name = Auto Center Map To Player +setting.mapcenter.name = ปรับแมพให้อยู่ตรงกลางตามผู้เล่นโดยอัตโนมัติ setting.animatedwater.name = แอนิเมชั่นน้ำ setting.animatedshields.name = แอนิเมชั่นเกราะ setting.antialias.name = Antialias[lightgray] (จำเป็นต้องรีสตาร์ท)[] -setting.playerindicators.name = Player Indicators +setting.playerindicators.name = ตัวบอกผู้เล่น setting.indicators.name = ตัวบอกศัตรู/พักพวก setting.autotarget.name = เล็งเป้าอัตโนมัติ setting.keyboard.name = การควบคุมแบบ เม้าส์+คีย์บอร์ด @@ -702,25 +702,25 @@ setting.difficulty.name = ระดับความยาก: setting.screenshake.name = การสั่นของจอ setting.effects.name = แสดงเอฟเฟ็ค setting.destroyedblocks.name = แสดงบล็อคที่ถูกทำลาย -setting.blockstatus.name = Display Block Status +setting.blockstatus.name = แสดงสเตตัสของบล็อค setting.conveyorpathfinding.name = Pathfinding setting.sensitivity.name = ความไวของตัวควบคุม setting.saveinterval.name = ระยะห่าวระหว่างเซฟ setting.seconds = {0} วินาที -setting.blockselecttimeout.name = Block Select Timeout -setting.milliseconds = {0} milliseconds +setting.blockselecttimeout.name = การหมดเวลาในการเลือกบล็อค +setting.milliseconds = {0} มิลลิวินาที setting.fullscreen.name = เต็มจอ setting.borderlesswindow.name = วินโดว์แบบไร้ขอบ[lightgray] (อาจจะต้องรีตาร์ท) setting.fps.name = แสดง FPS และ Ping -setting.smoothcamera.name = Smooth Camera -setting.blockselectkeys.name = Show Block Select Keys +setting.smoothcamera.name = กล้องแบบสมูท +setting.blockselectkeys.name = แสดงปุ่มเลือกบล็อค setting.vsync.name = VSync setting.pixelate.name = Pixelate[lightgray] (ปิดใช้งานแอนิเมชั่น) setting.minimap.name = แสดงมินิแมพ -setting.coreitems.name = Display Core Items (WIP) +setting.coreitems.name = แสดงไอเท็มใน Core (ยังไม่เสร็จสมบูรณ์) setting.position.name = แสดงตำแหน่งของผู้เล่น setting.musicvol.name = ระดับเสียงเพลง -setting.atmosphere.name = Show Planet Atmosphere +setting.atmosphere.name = แสดงชั้นบรรยากาศของดาวเคราะห์ setting.ambientvol.name = ระดับเสียงล้อมรอบ setting.mutemusic.name = ปิดเพลง setting.sfxvol.name = ระดับเสียง SFX @@ -728,10 +728,10 @@ setting.mutesound.name = ปิดเสียง setting.crashreport.name = ส่งรายงานการแครชแบบไม่ระบุตัวตน setting.savecreate.name = สร้างเซฟโดยอัตโนมัติ setting.publichost.name = การมองเห็นเซิฟเวอร์สาธารณะ -setting.playerlimit.name = Player Limit +setting.playerlimit.name = จัดกัดผู้เล่น setting.chatopacity.name = ความโปร่งแสงของแชท setting.lasersopacity.name = ความโปร่งแสงของเลเซอร์พลังงาน -setting.bridgeopacity.name = Bridge Opacity +setting.bridgeopacity.name = ความโปร่งแสงของสะพาน setting.playerchat.name = แสดงบับเบิ้ลแชทของผู้เล่น public.confirm = คุณต้องการให้เกมของคุณเปิดเป็นสาธารณะหรือไม่?\n[accent]ทุกคนจะสามารถเข้าร่วมเกมของคุณได้.\n[lightgray]คุณสามารถเปลี่ยนการตั้งค่านี้ได้ที่ ตั้งค่า->เกม->การมองเห็นเซิฟเวอร์สาธารณะ. public.beta = เกมเวอร์ชั่นเบต้าไม่สามารถเปิดเซิฟเวอร์สาธารณะได้ @@ -743,54 +743,54 @@ keybinds.mobile = [scarlet]การตั้งค่าปุ่มส่ว category.general.name = ทั่วไป category.view.name = วิว category.multiplayer.name = ผู้เล่นหลายคน -category.blocks.name = Block Select +category.blocks.name = เลือกบล็อค command.attack = โจมตี command.rally = ชุมนุม command.retreat = ถอยกลับ -command.idle = Idle +command.idle = อยู่เฉยๆ placement.blockselectkeys = \n[lightgray]Key: [{0}, -keybind.respawn.name = Respawn -keybind.control.name = Control Unit +keybind.respawn.name = เกิดใหม่ +keybind.control.name = ควบคุมยูนิต keybind.clear_building.name = เคลียร์สิ่งก็สร้าง keybind.press = กดปุ่มใดก็ได้... keybind.press.axis = กดแกนหรือปุ่มใดก็ได้... keybind.screenshot.name = แมพ Screenshot -keybind.toggle_power_lines.name = Toggle Power Lasers -keybind.toggle_block_status.name = Toggle Block Statuses +keybind.toggle_power_lines.name = เปิดปิดเลเซอร์พลังงาน +keybind.toggle_block_status.name = เปิดปิดสถานะของบล็อค keybind.move_x.name = เคลื่อนที่ในแกน x keybind.move_y.name = เคลี่อนที่ในแกน y keybind.mouse_move.name = ตามเม้าส์ -keybind.pan.name = Pan View -keybind.boost.name = Boost +keybind.pan.name = แพนวิว +keybind.boost.name = บูสต์ keybind.schematic_select.name = เลือกภูมิภาค keybind.schematic_menu.name = เมนู Schematic keybind.schematic_flip_x.name = กลับ Schematic ในแกน X keybind.schematic_flip_y.name = กลับ Schematic ในแกน Y -keybind.category_prev.name = Previous Category -keybind.category_next.name = Next Category -keybind.block_select_left.name = Block Select Left -keybind.block_select_right.name = Block Select Right -keybind.block_select_up.name = Block Select Up -keybind.block_select_down.name = Block Select Down -keybind.block_select_01.name = Category/Block Select 1 -keybind.block_select_02.name = Category/Block Select 2 -keybind.block_select_03.name = Category/Block Select 3 -keybind.block_select_04.name = Category/Block Select 4 -keybind.block_select_05.name = Category/Block Select 5 -keybind.block_select_06.name = Category/Block Select 6 -keybind.block_select_07.name = Category/Block Select 7 -keybind.block_select_08.name = Category/Block Select 8 -keybind.block_select_09.name = Category/Block Select 9 -keybind.block_select_10.name = Category/Block Select 10 +keybind.category_prev.name = หมวดหมู่ก่อนหน้า +keybind.category_next.name = หมวดหมู่ถ้ดไป +keybind.block_select_left.name = เลือกบล็อค ซ้าย +keybind.block_select_right.name = เลือกบล็อค ขวา +keybind.block_select_up.name = เลือกบล็อค ขึ้น +keybind.block_select_down.name = เลือกบล็อค ลง +keybind.block_select_01.name = หมวดหมู่/เลือกบล็อค 1 +keybind.block_select_02.name = หมวดหมู่/เลือกบล็อค 2 +keybind.block_select_03.name = หมวดหมู่/เลือกบล็อค 3 +keybind.block_select_04.name = หมวดหมู่/เลือกบล็อค 4 +keybind.block_select_05.name = หมวดหมู่/เลือกบล็อค 5 +keybind.block_select_06.name = หมวดหมู่/เลือกบล็อค 6 +keybind.block_select_07.name = หมวดหมู่/เลือกบล็อค 7 +keybind.block_select_08.name = หมวดหมู่/เลือกบล็อค 8 +keybind.block_select_09.name = หมวดหมู่/เลือกบล็อค 9 +keybind.block_select_10.name = หมวดหมู่/เลือกบล็อค 10 keybind.fullscreen.name = เปิด/ปิด Fullscreen keybind.select.name = เลือก/ยิง keybind.diagonal_placement.name = วางเป็นแนวทแยง keybind.pick.name = เลือกบล็อค keybind.break_block.name = ทุบบล็อค keybind.deselect.name = ยกเลิกการเบือก -keybind.pickupCargo.name = Pickup Cargo -keybind.dropCargo.name = Drop Cargo -keybind.command.name = Command +keybind.pickupCargo.name = ยกของขึ้น +keybind.dropCargo.name = วางของลง +keybind.command.name = คำสั่ง keybind.shoot.name = ยิง keybind.zoom.name = ซูม keybind.menu.name = เมนู @@ -811,7 +811,7 @@ keybind.zoom_minimap.name = ซูมมินิแมพ mode.help.title = คำอธิบายโหมด mode.survival.name = เอาชีวิตรอด mode.survival.description = โหมดปกติ. ทรัพยากรมีจำกัดและ wave มาโดยอัตโนมัติ.\n[gray]ต้องมีสปาวน์ของศัตรูเพื่อที่จะเล่น. -mode.sandbox.name = Sandbox +mode.sandbox.name = โหมดอิสระ mode.sandbox.description = ทรัพยาดรไม่จำกัดและ wave ไม่จับเวลา. mode.editor.name = Editor mode.pvp.name = PvP @@ -825,10 +825,10 @@ rules.reactorexplosions = การระเบิดของ rules.wavetimer = ตัวนับเวลาปล่อยคลื่น(รอบ) rules.waves = คลื่น(รอบ) rules.attack = โหมดการโจมตี -rules.buildai = AI Building +rules.buildai = สิ่ก่อสร้างของ AI rules.enemyCheat = AI (ทีมสีแดง) มีทรัพยากรไม่จำกัด rules.blockhealthmultiplier = พหุคูณเลือดของบล็อค -rules.blockdamagemultiplier = Block Damage Multiplier +rules.blockdamagemultiplier = พหุคูณดาเมจของบล็อค rules.unitbuildspeedmultiplier = พหุคูณความเร็วในการสร้างยูนิต rules.unithealthmultiplier = พหุคูณเลือดของยูนิต rules.unitdamagemultiplier = พหุคูณพลังโจมตีของยูนิต @@ -836,23 +836,23 @@ rules.enemycorebuildradius = รัศมีห้ามสร้างบริ rules.wavespacing = ระยะเวลาระหว่างคลื่น(รอบ):[lightgray] (วินาที) rules.buildcostmultiplier = พหุคูณจำนวนทรัพยากรที่ใช้ในการสร้าง rules.buildspeedmultiplier = พหุคูณความเร็วในการสร้าง -rules.deconstructrefundmultiplier = Deconstruct Refund Multiplier +rules.deconstructrefundmultiplier = พหุคูณการคืนทรัพยากรเมื่อทำการทำลายสิ่งก่อสร้าง rules.waitForWaveToEnd = คลื่น(รอบ)รอศัตรู rules.dropzoneradius = รัศมีจุดเกิดของศัตรู:[lightgray] (ช่อง) -rules.unitammo = Units Require Ammo +rules.unitammo = ยูนิตต้องใช้กระสุน rules.title.waves = คลื่น(รอบ) rules.title.resourcesbuilding = ทรัพยากรและสิ่งก่อสร้าง rules.title.enemy = ศัตรู rules.title.unit = ยูนิต rules.title.experimental = Experimental -rules.title.environment = Environment -rules.lighting = Lighting -rules.fire = Fire -rules.explosions = Block/Unit Explosion Damage -rules.ambientlight = Ambient Light -rules.weather = Weather -rules.weather.frequency = Frequency: -rules.weather.duration = Duration: +rules.title.environment = สิ่งแวดล้อม +rules.lighting = แสง +rules.fire = ไฟ +rules.explosions = ดาเมจบล็อค/ยูนิตระเบิด +rules.ambientlight = แสงจากแวดล้อม +rules.weather = สภาพอากาศ +rules.weather.frequency = ความถี่: +rules.weather.duration = ระยะเวลา: content.item.name = ไอเท็ม content.liquid.name = ของเหลว @@ -885,73 +885,73 @@ item.radioactivity = [lightgray]ค่ากัมมันตภาพรัง unit.health = [lightgray]เลือด: {0} unit.speed = [lightgray]ความเร็ว: {0} -unit.weapon = [lightgray]Weapon: {0} -unit.itemcapacity = [lightgray]Item Capacity: {0} -unit.minespeed = [lightgray]Mining Speed: {0}% -unit.minepower = [lightgray]Mining Power: {0} -unit.ability = [lightgray]Ability: {0} -unit.buildspeed = [lightgray]Building Speed: {0}% +unit.weapon = [lightgray]อาวุธ: {0} +unit.itemcapacity = [lightgray]ความจุไอเท็ม: {0} +unit.minespeed = [lightgray]ความเร็วการขุด: {0}% +unit.minepower = [lightgray]ความแรงการขุด: {0} +unit.ability = [lightgray]ความสามารถ: {0} +unit.buildspeed = [lightgray]ความเร็วการสร้าง: {0}% liquid.heatcapacity = [lightgray]ความจุความร้อน: {0} liquid.viscosity = [lightgray]ความหนืด: {0} liquid.temperature = [lightgray]อุณหภูมิ: {0} unit.dagger.name = แด็กเกอร์ -unit.mace.name = Mace +unit.mace.name = เมส unit.fortress.name = ฟอร์เทรส -unit.nova.name = Nova -unit.pulsar.name = Pulsar -unit.quasar.name = Quasar +unit.nova.name = โนว่า +unit.pulsar.name = พอวซ่า +unit.quasar.name = ควอซ่า unit.crawler.name = ครอว์เลอร์ -unit.atrax.name = Atrax -unit.spiroct.name = Spiroct -unit.arkyid.name = Arkyid -unit.toxopid.name = Toxopid -unit.flare.name = Flare -unit.horizon.name = Horizon -unit.zenith.name = Zenith -unit.antumbra.name = Antumbra -unit.eclipse.name = Eclipse -unit.mono.name = Mono -unit.poly.name = Poly -unit.mega.name = Mega -unit.quad.name = Quad -unit.oct.name = Oct -unit.risso.name = Risso -unit.minke.name = Minke -unit.bryde.name = Bryde -unit.sei.name = Sei -unit.omura.name = Omura -unit.alpha.name = Alpha -unit.beta.name = Beta -unit.gamma.name = Gamma -unit.scepter.name = Scepter -unit.reign.name = Reign -unit.vela.name = Vela -unit.corvus.name = Corvus +unit.atrax.name = เอแทรซ +unit.spiroct.name = สปิรอคท์ +unit.arkyid.name = อาร์คิดย์ +unit.toxopid.name = โทโสพิด +unit.flare.name = แฟลร์ +unit.horizon.name = ฮอไรซอน +unit.zenith.name = ซีนิท +unit.antumbra.name = แอนทัมบรา +unit.eclipse.name = อีคลิปส์ +unit.mono.name = โมโน +unit.poly.name = โพลี +unit.mega.name = เมก้า +unit.quad.name = ควอด +unit.oct.name = ออกค์ +unit.risso.name = ริสโส +unit.minke.name = มิงค์ +unit.bryde.name = ไบรดย์ +unit.sei.name = ไซย์ +unit.omura.name = โอมูร่า +unit.alpha.name = อัลฟ่า +unit.beta.name = บีตเา +unit.gamma.name = แกมม่า +unit.scepter.name = สเซปเตอร์ +unit.reign.name = เรน +unit.vela.name = เวล่า +unit.corvus.name = คอร์วัส -block.resupply-point.name = Resupply Point -block.parallax.name = Parallax -block.cliff.name = Cliff +block.resupply-point.name = จุดเติมของ +block.parallax.name = พาราแล็ซ +block.cliff.name = หน้าผ่า block.sand-boulder.name = ก้อนหินทราย block.grass.name = หญ้า block.slag.name = Slag block.salt.name = เกลือ -block.salt-wall.name = Salt Wall +block.salt-wall.name = กำแพงเกลือ block.pebbles.name = ก้อนกรวด block.tendrils.name = ไม้เลื้อย -block.sand-wall.name = Sand Wall +block.sand-wall.name = กำแพงทราย block.spore-pine.name = ต้นสนสปอร์ -block.spore-wall.name = Spore Wall -block.boulder.name = Boulder -block.snow-boulder.name = Snow Boulder +block.spore-wall.name = กำแพงสปอร์ +block.boulder.name = ก้อยหินใหญ่ +block.snow-boulder.name = หินหิมะใหญ่ block.snow-pine.name = ต้นสนที่คลุมหิมะ block.shale.name = หินดินดาน block.shale-boulder.name = ก้อนหินดินดาน block.moss.name = ตะไคร่น้ำ block.shrubs.name = พุ่มไม้ block.spore-moss.name = พุ่มไม้สปอร์ -block.shale-wall.name = Shale Wall +block.shale-wall.name = กำแพงหินดินดาน block.scrap-wall.name = กำแพงเศษเหล็ก block.scrap-wall-large.name = กำแพงเศษเหล็กขนาดใหญ่ block.scrap-wall-huge.name = กำแพงเศษเหล็กขนาดใหญ่มาก @@ -969,7 +969,7 @@ block.deepwater.name = น้ำลึก block.water.name = น้ำ block.tainted-water.name = น้ำเสีย block.darksand-tainted-water.name = น้ำเสียบนทรายดำ -block.tar.name = น้ำมันดิน +block.tar.name = น้ำมันดิบ block.stone.name = หิน block.sand.name = ทราย block.darksand.name = ทรายดำ @@ -979,17 +979,17 @@ block.craters.name = หลุมอุกกาบาต block.sand-water.name = น้ำบนทราย block.darksand-water.name = น้ำบนทรายดำ block.char.name = ถ่าน -block.dacite.name = Dacite -block.dacite-wall.name = Dacite Wall +block.dacite.name = ดาไซต์ +block.dacite-wall.name = กำแพงดาไซต์ block.ice-snow.name = น้ำแข็งหิมะ -block.stone-wall.name = Stone Wall -block.ice-wall.name = Ice Wall -block.snow-wall.name = Snow Wall -block.dune-wall.name = Dune Wall +block.stone-wall.name = กำแพงหิน +block.ice-wall.name = กำแพงน้ำแข็ง +block.snow-wall.name = กำแพงหิมะ +block.dune-wall.name = กำแพงเนินทราย block.pine.name = ต้นสน -block.dirt.name = Dirt -block.dirt-wall.name = Dirt Wall -block.mud.name = Mud +block.dirt.name = ดิน +block.dirt-wall.name = กำแพงดิน +block.mud.name = โคลน block.white-tree-dead.name = ต้นไม้ขาวที่ตายแล้ว block.white-tree.name = ต้มไม้ขาว block.spore-cluster.name = กลุ่มสปอร์ @@ -1005,7 +1005,7 @@ block.dark-panel-4.name = แผ่นดำ 4 block.dark-panel-5.name = แผ่นดำ 5 block.dark-panel-6.name = แผ่นดำ 6 block.dark-metal.name = เหล็กดำ -block.basalt.name = Basalt +block.basalt.name = บะซอลต์ block.hotrock.name = หินร้อน block.magmarock.name = หินแมกม่า block.copper-wall.name = กำแพงทองแดง @@ -1027,7 +1027,7 @@ block.hail.name = แฮล block.lancer.name = แลนเซอร์ block.conveyor.name = สายพาน block.titanium-conveyor.name = สายพานไทเทเนี่ยม -block.plastanium-conveyor.name = Plastanium Conveyor +block.plastanium-conveyor.name = สายพานพสาตตาเนี่ยม block.armored-conveyor.name = สายพานเสริมเกราะ block.armored-conveyor.description = เคลื่อนย้ายไอเท็มได้เร็วเทียบเท่าสายพานไทเทเนี่ยม แต่มีเกราะที่แข็งแรงกว่า ไม่สามารถรับไอเท็มจากด้านข้างและจากสายพานชนิดอื่นนอกจากสายพานชนิดเดียวกัน. block.junction.name = ทางแยก @@ -1036,10 +1036,10 @@ block.distributor.name = ตัวแจกจ่าย block.sorter.name = เครื่องแยก block.inverted-sorter.name = เครื่องแยกกลับด้าน block.message.name = ตัวเก็บข้อความ -block.illuminator.name = Illuminator -block.illuminator.description = A small, compact, configurable light source. Requires power to function. +block.illuminator.name = ตัวเปล่งแสง +block.illuminator.description = แหล่งกำเนิดแสงขนาดเล็ก สามารถดัดแปลงได้. จำเป็นต้องใช้พลังงานในการทำงาน. block.overflow-gate.name = ประตูระบายไอเทม -block.underflow-gate.name = Underflow Gate +block.underflow-gate.name = ประตูระบายไอเท็มย้อนกลับ block.silicon-smelter.name = เตาเผาซิลิกอน block.phase-weaver.name = เครื่องทอใยเฟส block.pulverizer.name = เครื่องบด @@ -1055,7 +1055,7 @@ block.surge-tower.name = เสาเสิร์จ block.diode.name = ไดโอดแบตเตอรี่ block.battery.name = แบตเตอรี่ block.battery-large.name = แบตเตอรี่ขนาดใหญ่ -block.combustion-generator.name = เครื่องกำเนิดไฟฟ้าโดยการสันดาป +block.combustion-generator.name = เครื่องกำเนิดไฟฟ้าเผาไหม้ถ่าน block.steam-generator.name = เครื่องกำเนิดไฟฟ้าไอน้ำ block.differential-generator.name = เครื่องกำเนิดไฟฟ้าดิฟเฟอเร่นเตอร์ block.impact-reactor.name = เตาปฏิกรณ์อัดกระแทก @@ -1118,33 +1118,33 @@ block.container.name = ตู้เก็บของ block.launch-pad.name = ฐานส่งของ block.launch-pad-large.name = ฐานส่งของขนาดใหญ่ block.segment.name = Segment -block.command-center.name = Command Center -block.ground-factory.name = Ground Factory -block.air-factory.name = Air Factory -block.naval-factory.name = Naval Factory -block.additive-reconstructor.name = Additive Reconstructor -block.multiplicative-reconstructor.name = Multiplicative Reconstructor -block.exponential-reconstructor.name = Exponential Reconstructor +block.command-center.name = ศูนย์ควบคุม +block.ground-factory.name = โรงงานภาคพื้นดิน +block.air-factory.name = โรงงานภาคอากาศ +block.naval-factory.name = โรงงานทางน้ำ +block.additive-reconstructor.name = Reconstructor แบบบวก +block.multiplicative-reconstructor.name = Reconstructor แบบคูณ +block.exponential-reconstructor.name = Reconstructor แบบเอ็กโพเนนเชียว block.tetrative-reconstructor.name = Tetrative Reconstructor -block.payload-conveyor.name = Mass Conveyor -block.payload-router.name = Payload Router -block.disassembler.name = Disassembler -block.silicon-crucible.name = Silicon Crucible -block.overdrive-dome.name = Overdrive Dome +block.payload-conveyor.name = สายพาน Mass +block.payload-router.name = ตัวเปลี่ยเส้นทาง Payload +block.disassembler.name = ตัวชำแหละ +block.silicon-crucible.name = เบ้าหลอมซิลิคอน +block.overdrive-dome.name = โดม Overdrive -block.switch.name = Switch -block.micro-processor.name = Micro Processor -block.logic-processor.name = Logic Processor -block.hyper-processor.name = Hyper Processor -block.logic-display.name = Logic Display -block.large-logic-display.name = Large Logic Display -block.memory-cell.name = Memory Cell +block.switch.name = สวิชต์ +block.micro-processor.name = ตัวประมวลผล Micro +block.logic-processor.name = ตัวประมวลผล Logic +block.hyper-processor.name = ตัวประมวลผล Hyper +block.logic-display.name = ตัวแสดง Logic +block.large-logic-display.name = ตัวแสดง Logic ขนาดใหญ่ +block.memory-cell.name = เซลล์ความจำ team.blue.name = น้ำเงิน team.crux.name = แดง team.sharded.name = ส้ม team.orange.name = ส้ม -team.derelict.name = derelict +team.derelict.name = ไม่มี team.green.name = เขียว team.purple.name = ม่วง @@ -1208,12 +1208,12 @@ block.spore-press.description = อัดกระเปาะสปอร์ด block.pulverizer.description = บดเศษเหล็กให้เป็นทรายละเอียด. block.coal-centrifuge.description = ทำให้น้ำมันแข็งตัวเป็นก้อนถ่านหิน. block.incinerator.description = ทำลายไอเท็มหรือของเหลวทุกอย่างที่ได้รับมา. -block.power-void.description = ทิ้งพลังงานทั้งหมดที่ได้รับ. เฉพาะ Sandbox เท่านั้น. -block.power-source.description = ส่งออกพลังงานไม่จำกัด. เฉพาะ Sandbox เท่านั้น. -block.item-source.description = ส่งออกไอเท็มไม่จำกัด. เฉพาะ Sandbox เท่านั้น. -block.item-void.description = ทำลายทุกไอเท็ม . เฉพาะ Sandbox เท่านั้น. -block.liquid-source.description = ส่งออกของเหลวไม่จำกัด. เฉพาะ Sandbox เท่านั้น. -block.liquid-void.description = Removes any liquids. Sandbox only. +block.power-void.description = ทิ้งพลังงานทั้งหมดที่ได้รับ. เฉพาะ โหมดอิสระ เท่านั้น. +block.power-source.description = ส่งออกพลังงานไม่จำกัด. เฉพาะ โหมดอิสระ เท่านั้น. +block.item-source.description = ส่งออกไอเท็มไม่จำกัด. เฉพาะ โหมดอิสระ เท่านั้น. +block.item-void.description = ทำลายทุกไอเท็ม . เฉพาะ โหมดอิสระ เท่านั้น. +block.liquid-source.description = ส่งออกของเหลวไม่จำกัด. เฉพาะ โหมดอิสระ เท่านั้น. +block.liquid-void.description = ทิ้งของเหลวทุกชนิด. เฉพาะ โหมดอิสระ เท่านั้น. block.copper-wall.description = บล็อคป้องกันราคาถูก.\nมีประโยชน์สำหรับป้องกัน core และป้อมปืนใน wave แรกๆ. block.copper-wall-large.description = บล็อคป้องกันราคาถูก.\nมีประโยชน์สำหรับป้องกัน core และป้อมปืนใน wave แรกๆ.\nคลอบคลุมหลายข่อง. block.titanium-wall.description = บล็อคป้องกันแข็งแกร่งปานกลาง.\nป้องกันศัตรูได้ในระดับหนึ่ง. @@ -1222,8 +1222,8 @@ block.plastanium-wall.description = กำแพงพิเศษที่ส block.plastanium-wall-large.description = กำแพงพิเศษที่สามารถดูดซับไฟฟ้าและป้องกันการต่อไฟกับโหนดพลังงานโดยอัตโนมัติได้.\nคลอบคลุมหลายช่อง. block.thorium-wall.description = บล็อคป้องกันที่แข็งแรง.\nป้องกันศัตรูได้อย่างดี. block.thorium-wall-large.description = บล็อคป้องกันที่แข็งแรง.\nป้องกันศัตรูได้อย่างดี.\nคลอบคลุมหลายช่อง. -block.phase-wall.description = A wall coated with special phase-based reflective compound. Deflects most bullets upon impact. -block.phase-wall-large.description = A wall coated with special phase-based reflective compound. Deflects most bullets upon impact.\nคลอบคลุมหลายช่อง. +block.phase-wall.description = กำแพงที่เคลือบด้วยวัสดุสะท้อนพิเศษจำพวก phase. เบี่ยงเบนกระสุนส่วนใหญ่ที่รับมา. +block.phase-wall-large.description = กำแพงที่เคลือบด้วยวัสดุสะท้อนพิเศษจำพวก phase. เบี่ยงเบนกระสุนส่วนใหญ่ที่รับมา.\nคลอบคลุมหลายช่อง. block.surge-wall.description = บล็อคป้องกันที่มีทนทานสูง.\nสะสมพลังงานจากกระสุน, แล้วปล่อยออกมาแบบสุ่ม. block.surge-wall-large.description = บล็อคป้องกันที่มีทนทานสูง.\nสะสมพลังงานจากกระสุน, แล้วปล่อยออกมาแบบสุ่ม.\nคลอบคลุมหลายช่อง. block.door.description = ประตูขนาดเล็ก. สามารถเปิดได้โดยการกด. @@ -1235,7 +1235,7 @@ block.force-projector.description = สร้างสนามพลังง block.shock-mine.description = ดาเมจศัตรูที่เหยียบ. แถบจะล่องหนต่อศัตรู. block.conveyor.description = บล็อคขนส่งไอเท็มพื้นฐาน. เคลื่อนไอเท็มไปข้างหน้าและใส่ลงบล็อคโดยอัตโนมัติ. สามารถหมุนได้. block.titanium-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. เคลื่อนไอเท็มเร็วกว่าสายพานทั่วไป. -block.plastanium-conveyor.description = Moves items in batches.\nAccepts items at the back, and unloads them in three directions at the front. +block.plastanium-conveyor.description = เคลื่อนย้ายไอเท็มเป็นชุด.\nรับไอดท็มจากด้านหลัง, และนำออกไปสามทางข้างหน้า. block.junction.description = มีหน้าที่เป็นสะพานสำหรับสายพาน 2 สายข้ามกัน. มีประโยชน์สำหรับเวลาสายพาน 2 สายที่ขนไอเท็มมา 2 ชนิดไปยัง 2 สถานที่. block.bridge-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. ทำให้สามารถส่งไอเท็มข้ามบล็อคใดก็ได้ 3 ช่อง. block.phase-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. ใช้พลังงานเพื่อส่งไอเท็มไปยังสายพานเฟสอีกอัน ข้ามได้หลายช่อง. @@ -1244,14 +1244,14 @@ block.inverted-sorter.description = แยกไอเท็มคล้าย block.router.description = รับไอเท็มแล้วส่งออก 3 ทางเท่าๆกัน. มีประโยชน์สำหรับแยกไอเท็มจากแหล่งเดียวไปหลายที่.\n\n[scarlet]อย่าวางไว้ติดกับทางส่งไอเท็มเข้าเพราะของออกจะไปอุดตันได้.[] block.distributor.description = เร้าเตอร์ขั้นสูง. แยกไอเท็มออก 7 ทางอย่างเท่าๆกัน. block.overflow-gate.description = ของจะออกจากข้างๆเมื่อทางข้างหน้ถูกบล็อคเท่านั้น. -block.underflow-gate.description = The opposite of an overflow gate. Outputs to the front if the left and right paths are blocked. +block.underflow-gate.description = ตรงข้ามกับประตูระบายไอเท็ม. ส่งออกไอเท็มไปข้างหน้าหากทางซ้ายและขวาถูกบล็อค. block.mass-driver.description = บล็อคขนส่งไอเท็มขั้นสุดยอด. รวบรวมไอเท็มจำนวนหนึ่งแล้วยิงไปหาแมสไดรเวอร์อีกอันที่อยู่ไกลออกไป. ต้องใช้พลังงานในการใช้งาน. block.mechanical-pump.description = ปั๊มราคาถูก เอ้าพุธต์ช้า แต่ไม่ใช้พลังงาน. block.rotary-pump.description = ปั๊มขั้นสูง. ปั๊มของเหลวได้มากขึ้นแค่ใช้พลังงาน. block.thermal-pump.description = ปั๊มขั้นสุดยอด. block.conduit.description = บล็อคขนส่งของเหลวพื้นฐาน. เคลื่อนของเหลวไปข้างหน้า. ใช้ร่วมกับปั๊มและรางน้ำอื่นๆ. block.pulse-conduit.description = บล็อคขนส่งของเหลวขั้นสูง. เคลื่อนย้ายของเหลวเร็วขึ้นและเก็บเยอะกว่ารางน้ำธรรมดา. -block.plated-conduit.description = Moves liquids at the same rate as pulse conduits, but possesses more armor. Does not accept fluids from the sides by anything other than conduits.\nLeaks less. +block.plated-conduit.description = เคลื่อนย้ายของเหลวได้เร็วพอๆกับ ท่อน้ำพัลซ์, แต่มีเกราะที่หนากว่า. ไม่รับของเหลวจากด้านข้างจากอย่างอื่นนอกจากท่อน้ำด้วยกันเอง.\nรั่วน้อยกว่า. block.liquid-router.description = รับของเหลวจากทางเดียวแล้วส่งออก 3 ทางเท่าๆกัน. สามารถเก็บของ้หลวได้จำนวนหนึ่ง. มีประโยชน์สำหรับการแยกของเหลวจากแหล่งเดียวไปหลายที่. block.liquid-tank.description = เก็บของเหลวจำนวนมาก. ใช่สำหรับสร้างบัฟเฟอร์ในเวลาที่ความต้องการของทรัพยากรไม่คงที่หรือเป็นตัวเซฟสำหรับบล็อคที่จำเป็นต้องใช้การหล่อเย็น. block.liquid-junction.description = ทำหน้าที่เป็นสะพานสำหรับรางน้ำ 2 รางที่ข้ามกันที่มีของเหลว 2 ชนิด ซึ่งต้องการจะไปคนละที่. @@ -1302,4 +1302,4 @@ block.cyclone.description = ป้อมปืนต่อต้านอาก block.spectre.description = ปืนใหญ่ลำกล้องคูขนาดยักษ์. ยิงกระสุนเจาะเกราะใส่ศัตรูทั้งบนอากาศและภาดพื้นดิน. block.meltdown.description = ปืนใหญ่เลเซอร์ขนาดยักษ์. ชาร์จแล้วยิงลำแสงเลเซอร์ใส่ศัตรูที่อยู่ใกล้. จำเป็นต้องใช้สารหล่อเย็น. block.repair-point.description = ซ่อมแซมยูนิตที่อยู่ในรัศมีอย่างต่อเนื่อง. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = ทำดาเมจและทำลายโปรเจกไตล์ที่กำลังเข้ามา. โปรเจกไตล์เลเซอร์จะไม่ถูกล็อคเป้าด้วยบล็อคนี้. \ No newline at end of file diff --git a/core/assets/bundles/bundle_tk.properties b/core/assets/bundles/bundle_tk.properties index edfae05b29..cfac48c897 100644 --- a/core/assets/bundles/bundle_tk.properties +++ b/core/assets/bundles/bundle_tk.properties @@ -570,49 +570,49 @@ info.title = [accent]Bilgi error.title = [crimson]Bir hata olustu error.crashtitle = Bir hata olustu unit.nobuild = [scarlet]Unit can't build -blocks.input = Input -blocks.output = Output -blocks.booster = Booster -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Input +stat.output = Output +stat.booster = Booster +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Guc kapasitesi -blocks.powershot = Guc/Saldiri hizi -blocks.damage = Damage -blocks.targetsair = Havayi hedef alir mi? -blocks.targetsground = Targets Ground -blocks.itemsmoved = Move Speed -blocks.launchtime = Time Between Launches -blocks.shootrange = Menzil -blocks.size = Buyukluk -blocks.displaysize = Display Size -blocks.liquidcapacity = Sivi kapasitesi -blocks.powerrange = Menzil -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Max Connections -blocks.poweruse = Guc kullanimi -blocks.powerdamage = Power/Damage -blocks.itemcapacity = Esya kapasitesi -blocks.basepowergeneration = Base Power Generation -blocks.productiontime = Production Time -blocks.repairtime = Block Full Repair Time -blocks.speedincrease = Speed Increase -blocks.range = Range -blocks.drilltier = Kazilabilirler -blocks.drillspeed = Ana kazma hizi -blocks.boosteffect = Boost Effect -blocks.maxunits = Max Active Units -blocks.health = Can -blocks.buildtime = Build Time -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = Build Cost -blocks.inaccuracy = sekme -blocks.shots = vuruslar -blocks.reload = Yeniden doldurma -blocks.ammo = Ammo -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Guc kapasitesi +stat.powershot = Guc/Saldiri hizi +stat.damage = Damage +stat.targetsair = Havayi hedef alir mi? +stat.targetsground = Targets Ground +stat.itemsmoved = Move Speed +stat.launchtime = Time Between Launches +stat.shootrange = Menzil +stat.size = Buyukluk +stat.displaysize = Display Size +stat.liquidcapacity = Sivi kapasitesi +stat.powerrange = Menzil +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Max Connections +stat.poweruse = Guc kullanimi +stat.powerdamage = Power/Damage +stat.itemcapacity = Esya kapasitesi +stat.basepowergeneration = Base Power Generation +stat.productiontime = Production Time +stat.repairtime = Block Full Repair Time +stat.speedincrease = Speed Increase +stat.range = Range +stat.drilltier = Kazilabilirler +stat.drillspeed = Ana kazma hizi +stat.boosteffect = Boost Effect +stat.maxunits = Max Active Units +stat.health = Can +stat.buildtime = Build Time +stat.maxconsecutive = Max Consecutive +stat.buildcost = Build Cost +stat.inaccuracy = sekme +stat.shots = vuruslar +stat.reload = Yeniden doldurma +stat.ammo = Ammo +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Better Drill Required bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = A large rapid fire turret. block.spectre.description = A large turret which shoots two powerful bullets at once. block.meltdown.description = A large turret which shoots powerful long-range beams. block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_tr.properties b/core/assets/bundles/bundle_tr.properties index 1fd6a6618e..395e062453 100644 --- a/core/assets/bundles/bundle_tr.properties +++ b/core/assets/bundles/bundle_tr.properties @@ -570,49 +570,49 @@ info.title = Bilgi error.title = [crimson]Bir hata oldu error.crashtitle = Bir hata oldu unit.nobuild = [scarlet]Unit can't build -blocks.input = Giriş -blocks.output = Çıkış -blocks.booster = Güçlendirici -blocks.tiles = Required Tiles -blocks.affinities = Affinities +stat.input = Giriş +stat.output = Çıkış +stat.booster = Güçlendirici +stat.tiles = Required Tiles +stat.affinities = Affinities block.unknown = [lightgray]??? -blocks.powercapacity = Enerji Kapasitesi -blocks.powershot = Enerji/Atış -blocks.damage = Hasar -blocks.targetsair = Havayı Hedefler Mi -blocks.targetsground = Yeri Hedefler Mi -blocks.itemsmoved = Hareket Hızı -blocks.launchtime = Fırlatmalar Arasındaki Süre -blocks.shootrange = Menzil -blocks.size = Boyut -blocks.displaysize = Display Size -blocks.liquidcapacity = Sıvı Kapasitesi -blocks.powerrange = Enerji Menzili -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = Bağlantı sayısı -blocks.poweruse = Enerji Kullanımı -blocks.powerdamage = Enerji/Hasar -blocks.itemcapacity = Eşya Kapasitesi -blocks.basepowergeneration = Temel Enerji Üretimi -blocks.productiontime = Üretim Süresi -blocks.repairtime = Tamir Tamir Edilme Süresi -blocks.speedincrease = Hız Artışı -blocks.range = Menzil -blocks.drilltier = Kazılabilenler -blocks.drillspeed = Temel Matkap Hızı -blocks.boosteffect = Hızlandırma Efekti -blocks.maxunits = Maksimum Aktif Birim -blocks.health = Can -blocks.buildtime = İnşaat Süresi -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = İnşaat Fiyatı -blocks.inaccuracy = İskalama Oranı -blocks.shots = Atışlar -blocks.reload = Atışlar/Sn -blocks.ammo = Mermi -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Enerji Kapasitesi +stat.powershot = Enerji/Atış +stat.damage = Hasar +stat.targetsair = Havayı Hedefler Mi +stat.targetsground = Yeri Hedefler Mi +stat.itemsmoved = Hareket Hızı +stat.launchtime = Fırlatmalar Arasındaki Süre +stat.shootrange = Menzil +stat.size = Boyut +stat.displaysize = Display Size +stat.liquidcapacity = Sıvı Kapasitesi +stat.powerrange = Enerji Menzili +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = Bağlantı sayısı +stat.poweruse = Enerji Kullanımı +stat.powerdamage = Enerji/Hasar +stat.itemcapacity = Eşya Kapasitesi +stat.basepowergeneration = Temel Enerji Üretimi +stat.productiontime = Üretim Süresi +stat.repairtime = Tamir Tamir Edilme Süresi +stat.speedincrease = Hız Artışı +stat.range = Menzil +stat.drilltier = Kazılabilenler +stat.drillspeed = Temel Matkap Hızı +stat.boosteffect = Hızlandırma Efekti +stat.maxunits = Maksimum Aktif Birim +stat.health = Can +stat.buildtime = İnşaat Süresi +stat.maxconsecutive = Max Consecutive +stat.buildcost = İnşaat Fiyatı +stat.inaccuracy = İskalama Oranı +stat.shots = Atışlar +stat.reload = Atışlar/Sn +stat.ammo = Mermi +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = Daha İyi Matkap Gerekli bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = Büyük bir anti hava ve anti kara tareti. Yakının block.spectre.description = Dev bir çift namlulu top. Hava ve kara birimlerine iri, zırh delici mermiler atar. block.meltdown.description = Dev bir lazer topu. Yüklenip yakındaki düşmanlara uzun süreli lazer ışınları yollar. Çalışması için soğutucu gerekir. block.repair-point.description = Kendisine en yakın hasarlı birimi tamir eder. -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties index df5bfc1db1..dfc4bae48b 100644 --- a/core/assets/bundles/bundle_uk_UA.properties +++ b/core/assets/bundles/bundle_uk_UA.properties @@ -1,4 +1,4 @@ -credits.text = Створив [royal]Anuken[] — [sky]anukendev@gmail.com[]\n\nЄ ігрові питання або помилки в перекладі?\nЗавітайте до офіційного Discord-сервера Mindustry\nв канал #український.\nПереклав українською: [blue]Prosta4ok_ua[green]#[yellow]6336 +credits.text = Створив [royal]Anuken[] — [sky]anukendev@gmail.com[]\n\nМаєте питання по грі або знайшли помилки в перекладі?\nДолучайтеся до офіційного сервера Mindustry у Discord\nв канал #українська.\nУкраїнський перекладач — Prosta4ok_ua#6336. credits = Творці contributors = Перекладачі та помічники discord = Офіційний сервер Mindustry в Discord @@ -21,7 +21,7 @@ gameover.pvp = [accent]{0}[] команда перемогла! highscore = [accent]Новий рекорд! copied = Скопійовано. indev.popup = Наразі [accent]6.0[] знаходиться у стадії [accent]альфа[].\n[lightgray]Це означає наступне:[]\n- Не вистачає наповнення гри;\n- Більшість [scarlet]ШІ бойових одиниць[] не працює належним чином;\n- Багато одиниць [scarlet]відсутні[] або незавершені;\n- Кампанія повністю не є завершеною;\n- Усе, що ви бачите, може змінитися або видалитися.\n\nПовідомляйте про вади або збої на [accent]Github[], а про помилки в перекладі в Discord. -indev.notready = Ця частина гри ще не готова +indev.notready = Ця частина гри ще не готова. load.sound = Звуки load.map = Мапи @@ -54,7 +54,8 @@ schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Обернути схему schematic.saved = Схема збережена. schematic.delete.confirm = Ви справді хочете видалити цю схему? schematic.rename = Перейменувати схему -schematic.info = {0}x{1}, {2} блоків +schematic.info = {0}x{1}, блоків: {2} +schematic.disabled = [scarlet]Схеми вимкнені[]\nВам не дозволяється використовувати схеми на цій [accent]мапі[] чи [accent]сервері. stat.wave = Хвиль відбито:[accent] {0} stat.enemiesDestroyed = Противників знищено:[accent] {0} @@ -471,22 +472,16 @@ requirement.wave = Досягніть хвилі {0} у зоні «{1}» requirement.core = Знищте вороже ядро в зоні «{0}» requirement.research = Research {0} requirement.capture = Capture {0} -resume = Відновити зону:\n[lightgray]{0} bestwave = [lightgray]Найкраща хвиля: {0} -launch = < ЗАПУСК > launch.text = Запуск -launch.title = Запуск вдалий -launch.next = [lightgray]наступна можливість буде на {0}-тій хвилі -launch.unable2 = [scarlet]ЗАПУСК неможливий.[] -launch.confirm = Це видалить усі ресурси у вашому ядрі.\nВи не зможете повернутися до цієї бази. -launch.skip.confirm = Якщо ви пропустите зараз, ви не зможете не запускати до більш пізніх хвиль. +campaign.multiplayer = Коли ви граєте з кимось в кампанії, то ви можете дослідити лише використовуючи предмети з [accent]ваших[] секторів, [scarlet]гн[] з сектора власника, на якому ви перебуваєте прямо зараз.\n\nЗадля отримання предметів у [accent]своїх[] секторах в багатокористувацькій грі використайте [accent]Стартовий майданчик[]. uncover = Розкрити configure = Налаштувати вивантаження loadout = Вивантаження resources = Ресурси bannedblocks = Заборонені блоки addall = Додати все -launch.destination = Destination: {0} +launch.destination = Пункт призначення: {0} configure.invalid = Кількість має бути числом між 0 та {0}. zone.unlocked = Зона «[lightgray]{0}» тепер розблокована. zone.requirement.complete = Вимоги до зони «{0}» виконані:[lightgray]\n{1} @@ -519,8 +514,8 @@ sectors.production = Виробництво: sectors.stored = Зберігає: sectors.resume = Продовжити sectors.launch = Запуск -sectors.select = Select -sectors.nonelaunch = [lightgray]none (sun) +sectors.select = Вибрати +sectors.nonelaunch = [lightgray]нічого (сонце) sector.groundZero.name = Відправний пункт sector.craters.name = Кратери @@ -570,49 +565,50 @@ info.title = Інформація error.title = [crimson]Виникла помилка error.crashtitle = Виникла помилка unit.nobuild = [scarlet]Ця одиниця не може будувати -blocks.input = Ввід -blocks.output = Вивід -blocks.booster = Прискорювач -blocks.tiles = Необхідні плитки -blocks.affinities = Збільшення ефективності +stat.input = Ввід +stat.output = Вивід +stat.booster = Прискорювач +stat.tiles = Необхідні плитки +stat.affinities = Збільшення ефективності block.unknown = [lightgray]??? -blocks.powercapacity = Місткість енергії -blocks.powershot = Енергія за постріл -blocks.damage = Шкода -blocks.targetsair = Повітряні противники -blocks.targetsground = Наземні противники -blocks.itemsmoved = Швидкість переміщення -blocks.launchtime = Час між запусками -blocks.shootrange = Радіус дії -blocks.size = Розмір -blocks.displaysize = Розмір дисплею -blocks.liquidcapacity = Рідинна місткість -blocks.powerrange = Радіус передачі енергії -blocks.linkrange = Радіус з’єднання -blocks.instructions = Інструкції -blocks.powerconnections = Максимальна кількість з’єднань -blocks.poweruse = Енергії використовує -blocks.powerdamage = Енергії за од. шкоди -blocks.itemcapacity = Місткість предметів -blocks.basepowergeneration = Базова генерація енергії -blocks.productiontime = Час виробництва -blocks.repairtime = Час повного відновлення блоку -blocks.speedincrease = Збільшення швидкості -blocks.range = Радіус дії -blocks.drilltier = Видобуває -blocks.drillspeed = Базова швидкість буріння -blocks.boosteffect = Прискорювальний ефект -blocks.maxunits = Максимальна кількість активних одиниць -blocks.health = Здоров’я -blocks.buildtime = Час будування -blocks.maxconsecutive = Максимальна послідовність -blocks.buildcost = Вартість будування -blocks.inaccuracy = Розкид -blocks.shots = Постріли -blocks.reload = Постріли/секунду -blocks.ammo = Боєприпаси -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = Місткість енергії +stat.powershot = Енергія за постріл +stat.damage = Шкода +stat.targetsair = Повітряні противники +stat.targetsground = Наземні противники +stat.itemsmoved = Швидкість переміщення +stat.launchtime = Час між запусками +stat.shootrange = Радіус дії +stat.size = Розмір +stat.displaysize = Розмір дисплею +stat.liquidcapacity = Рідинна місткість +stat.powerrange = Радіус передачі енергії +stat.linkrange = Радіус з’єднання +stat.instructions = Інструкції +stat.powerconnections = Максимальна кількість з’єднань +stat.poweruse = Енергії використовує +stat.powerdamage = Енергії за од. шкоди +stat.itemcapacity = Місткість предметів +stat.memorycapacity = Ємність пам’яті +stat.basepowergeneration = Базова генерація енергії +stat.productiontime = Час виробництва +stat.repairtime = Час повного відновлення блоку +stat.speedincrease = Збільшення швидкості +stat.range = Радіус дії +stat.drilltier = Видобуває +stat.drillspeed = Базова швидкість буріння +stat.boosteffect = Прискорювальний ефект +stat.maxunits = Максимальна кількість активних одиниць +stat.health = Здоров’я +stat.buildtime = Час будування +stat.maxconsecutive = Максимальна послідовність +stat.buildcost = Вартість будування +stat.inaccuracy = Розкид +stat.shots = Постріли +stat.reload = Постріли/секунду +stat.ammo = Боєприпаси +stat.shieldhealth = Міцність щита +stat.cooldowntime = Тривалість охолодження bar.drilltierreq = Потребується кращий бур bar.noresources = Бракує ресурсів @@ -660,7 +656,7 @@ unit.persecond = за секунду unit.perminute = за хвилину unit.timesspeed = x швидкість unit.percent = % -unit.shieldhealth = shield health +unit.shieldhealth = міцність щита unit.items = предм. unit.thousands = тис unit.millions = млн @@ -788,14 +784,14 @@ keybind.diagonal_placement.name = Діагональне розміщення keybind.pick.name = Вибрати блок keybind.break_block.name = Зламати блок keybind.deselect.name = Скасувати -keybind.pickupCargo.name = Pickup Cargo -keybind.dropCargo.name = Drop Cargo -keybind.command.name = Command +keybind.pickupCargo.name = Взяти вантаж +keybind.dropCargo.name = Скинути вантаж +keybind.command.name = Взяти командування над одиницями keybind.shoot.name = Постріл keybind.zoom.name = Наблизити keybind.menu.name = Меню keybind.pause.name = Пауза -keybind.pause_building.name = Призупинити/Продовжити будування +keybind.pause_building.name = Призупинити/продовжити будування keybind.minimap.name = Мінімапа keybind.chat.name = Чат keybind.player_list.name = Список гравців @@ -822,6 +818,7 @@ mode.custom = Користувацькі правила rules.infiniteresources = Нескінченні ресурси rules.reactorexplosions = Вибухи реактора +rules.schematic = Використання схем дозволено rules.wavetimer = Таймер для хвиль rules.waves = Хвилі rules.attack = Режим атаки @@ -912,11 +909,11 @@ unit.horizon.name = Горизонт unit.zenith.name = Зеніт unit.antumbra.name = Тіньовик unit.eclipse.name = Затьмарник -unit.mono.name = Єдинак -unit.poly.name = Багацько +unit.mono.name = Моно +unit.poly.name = Полі unit.mega.name = Мега -unit.quad.name = Quad -unit.oct.name = Oct +unit.quad.name = Квал +unit.oct.name = Окт unit.risso.name = Грампус unit.minke.name = Смугач малий unit.bryde.name = Смугач Брайда @@ -927,8 +924,8 @@ unit.beta.name = Бета unit.gamma.name = Гамма unit.scepter.name = Верховна влада unit.reign.name = Верховний Порядок -unit.vela.name = Vela -unit.corvus.name = Corvus +unit.vela.name = Пульсар Вітрил +unit.corvus.name = Ворон block.resupply-point.name = Пункт постачання block.parallax.name = Паралакс @@ -989,7 +986,7 @@ block.dune-wall.name = Дюнова стіна block.pine.name = Сосна block.dirt.name = Ґрунт block.dirt-wall.name = Ґрунтова стіна -block.mud.name = Mud +block.mud.name = Багно block.white-tree-dead.name = Мертве біле дерево block.white-tree.name = Біле дерево block.spore-cluster.name = Скупчення спор @@ -1130,7 +1127,7 @@ block.payload-conveyor.name = Вантажний конвеєр block.payload-router.name = Розвантажувальний маршрутизатор block.disassembler.name = Розбирач block.silicon-crucible.name = Кремнієвий тигель -block.overdrive-dome.name = Overdrive Dome +block.overdrive-dome.name = Величний Прискорювач block.switch.name = Перемикач block.micro-processor.name = Мікропроцесор @@ -1139,12 +1136,13 @@ block.hyper-processor.name = Гіперпроцесор block.logic-display.name = Логічний дисплей block.large-logic-display.name = Великий логічний дисплей block.memory-cell.name = Комірка пам’яті +block.memory-bank.name = Блок пам’яті team.blue.name = Синя team.crux.name = Червона team.sharded.name = Помаранчева team.orange.name = Помаранчева -team.derelict.name = Залишена +team.derelict.name = Знедолена team.green.name = Зелена team.purple.name = Фіолетова @@ -1302,4 +1300,4 @@ block.cyclone.description = Велика протиповітряна та пр block.spectre.description = Масивна двоствольна гармата. Стріляє великими бронебійними кулями в повітряні та наземні цілі. block.meltdown.description = Масивна лазерна гармата. Заряджає і стріляє лазерним променем у найближчих противників. Для роботи потрібен теплоносій. block.repair-point.description = Безперервно ремонтує найближчу пошкоджену бойову одиницю. -block.segment.description = Пошкоджує та руйнує вхідні снаряди. Окрім лазерних. +block.segment.description = Пошкоджує та руйнує вхідні снаряди. Окрім лазерних. \ No newline at end of file diff --git a/core/assets/bundles/bundle_zh_CN.properties b/core/assets/bundles/bundle_zh_CN.properties index 506a29aa99..5744d3d0fd 100644 --- a/core/assets/bundles/bundle_zh_CN.properties +++ b/core/assets/bundles/bundle_zh_CN.properties @@ -1,4 +1,4 @@ -credits.text = 作者[royal]Anuken[] - [sky]anukendev@gmail.com[] +credits.text = 作者[royal]Anuken[] - [sky]anukendev@gmail.com[] 译者[orange]老滑稽[] - [cyan]QQ:1290419934[] credits = 致谢 contributors = 翻译者和贡献者 discord = 加入 Mindustry 的 Discord! @@ -20,8 +20,8 @@ gameover = 游戏结束 gameover.pvp = [accent] {0}[]队获胜! highscore = [accent]新纪录! copied = 已复制。 -indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[]. -indev.notready = This part of the game isn't ready yet +indev.popup = [accent]v6[]仍在[accent]测试版[].\n[lightgray]这意味着:[]\n[scarlet]- 战役不完善[]\n- 内容不完整\n - 大多[scarlet]单位AI[]运行不佳\n- 单位系统不完整\n- 一切内容都可能发生变动或调整。\n\n向[accent]主群(QQ681962751)[]提交错误报告。 +indev.notready = 还没做好看NM load.sound = 音乐加载中 load.map = 地图加载中 @@ -99,15 +99,15 @@ committingchanges = 正在提交更改 done = 已完成 feature.unsupported = 您的设备不支持此功能。 -mods.alphainfo = 请注意,测试版本(alpha)中的模组[scarlet]很容易存在缺陷[]。\n在 Mindustry 的 GitHub 或 Discord 上报告你发现的问题。 -mods.alpha = [accent](Alpha) +mods.alphainfo = 请注意,测试版本中的模组[scarlet]很容易存在缺陷[]。\n在 Mindustry 的 GitHub 或 Discord 上报告你发现的问题。 +mods.alpha = [accent](测试) mods = 模组 mods.none = [lightgray]没有找到模组! mods.guide = 模组制作教程 mods.report = 报告 Bug mods.openfolder = 打开模组文件夹 mods.reload = 重载 -mods.reloadexit = The game will now exit, to reload mods. +mods.reloadexit = 游戏将退出以重载模组。 mod.display = [gray]模组:[orange] {0} mod.enabled = [lightgray]已启用 mod.disabled = [scarlet]已禁用 @@ -115,7 +115,7 @@ mod.disable = 禁用 mod.content = 内容: mod.delete.error = 无法删除模组。可能文件被占用。 mod.requiresversion = [scarlet]所需的游戏版本:[accent]{0} -mod.outdated = [scarlet]Not compatible with V6 (no minGameVersion: 105) +mod.outdated = [scarlet]模组不兼容6.0(缺失 minGameVersion: 105) mod.missingdependencies = [scarlet]缺少前置模组:{0} mod.erroredcontent = [scarlet]内容错误 mod.errors = 读取内容时发生错误. @@ -127,7 +127,7 @@ mod.reloadrequired = [scarlet]需要重启 mod.import = 导入模组 mod.import.file = 导入文件 mod.import.github = 从 GitHub 导入模组 -mod.jarwarn = [scarlet]JAR mods are inherently unsafe.[]\nMake sure you're importing this mod from a trustworthy source! +mod.jarwarn = [scarlet]JAR模组存在危险性。[]\n请确保此模组来源安全可靠! mod.item.remove = 这个物品是[accent] '{0}'[]模组的一部分. 删除物品需要先卸载此模组. mod.remove.confirm = 此模组将被删除。 mod.author = [lightgray]作者:[] {0} @@ -139,8 +139,8 @@ mod.scripts.disable = 你的设备不支持含有脚本的模组。必须禁用 about.button = 关于 name = 名字: noname = 先取一个[accent]玩家名[]。 -planetmap = Planet Map -launchcore = Launch Core +planetmap = 行星地图 +launchcore = 发射核心 filename = 文件名: unlocked = 解锁了新内容! completed = [accent]己研究 @@ -148,14 +148,14 @@ techtree = 科技树 research.list = [lightgray]研究: research = 研究 researched = [lightgray]{0}己研究。 -research.progress = {0}% complete +research.progress = {0}% 完成度 players = {0} 位玩家在线 players.single = {0} 位玩家在线 players.search = search players.notfound = [gray]没有找到玩家。 server.closing = [accent]服务器关闭… server.kicked.kick = 你被踢出了服务器。 -server.kicked.whitelist = 你并没有受邀请在此服务器上游玩。(不在白名单中) +server.kicked.whitelist = 你不在服务器白名单中。 server.kicked.serverClose = 服务器已关闭。 server.kicked.vote = 你被投票踢出了服务器。 server.kicked.clientOutdated = 客户端过旧,请更新你的游戏。 @@ -278,7 +278,7 @@ quit.confirm.tutorial = 确定要跳过教程?\n您可以通过[accent]设置- loading = [accent]加载中… reloading = [accent]重载模组中… saving = [accent]保存中… -respawn = [accent][[{0}][] to respawn in core +respawn = [accent][[{0}][]来重生 cancelbuilding = [accent][[{0}][]来清除规划 selectschematic = [accent][[{0}][]来选择复制 pausebuilding = [accent][[{0}][]来暂停建造 @@ -335,9 +335,9 @@ waves.never = < 无限 > waves.every = 每 waves.waves = 波 waves.perspawn = 每次生成 -waves.shields = shields/wave +waves.shields = 护盾/波次 waves.to = 至 -waves.guardian = Guardian +waves.guardian = 首领 waves.preview = 预览 waves.edit = 编辑… waves.copy = 复制到剪贴板 @@ -346,9 +346,9 @@ waves.invalid = 剪贴板中的波次信息无效。 waves.copied = 波次信息已复制。 waves.none = 没有定义敌人。\n请注意,这将自动替换为默认的敌人列表。 -wavemode.counts = counts -wavemode.totals = totals -wavemode.health = health +wavemode.counts = 数目 +wavemode.totals = 总和 +wavemode.health = 生命值 editor.default = [lightgray]<默认> details = 详情… @@ -415,8 +415,8 @@ toolmode.drawteams.description = 绘制团队而不是方块。 filters.empty = [lightgray]没有过滤条件!用下方的按钮添加。 filter.distort = 扭曲程度 filter.noise = 波动程度 -filter.enemyspawn = Enemy Spawn Select -filter.corespawn = Core Select +filter.enemyspawn = 敌人生成点选择 +filter.corespawn = 核心降落点选择 filter.median = 平均数 filter.oremedian = 矿石平均数 filter.blend = 混合程度 @@ -469,12 +469,12 @@ locked = 已锁定 complete = [lightgray]完成: requirement.wave = {1}中的第{0}波次 requirement.core = 在{0}中摧毁敌方核心 -requirement.research = Research {0} -requirement.capture = Capture {0} +requirement.research = 研究 {0} +requirement.capture = 占领 {0} resume = 暂停:\n[lightgray]{0} bestwave = [lightgray]最高波次:{0} launch = < 发射 > -launch.text = Launch +launch.text = 发射 launch.title = 发射成功 launch.next = [lightgray]下个发射窗口在第{0}波 launch.unable2 = [scarlet]无法发射[] @@ -482,11 +482,11 @@ launch.confirm = 您将装载并发射核心中的所有资源。\n此地图将 launch.skip.confirm = 如果现在跳过,在下一个发射窗口到来前,您都无法发射。 uncover = 解锁 configure = 设定装运的数量 -loadout = Loadout -resources = Resources +loadout = 装运 +resources = 资源 bannedblocks = 禁用建筑 addall = 添加所有 -launch.destination = Destination: {0} +launch.destination = 目的地: {0} configure.invalid = 数量必须是0到{0}之间的数字。 zone.unlocked = [lightgray]{0} 已解锁。 zone.requirement.complete = 完成{0}。\n已达成解锁{1}的要求。 @@ -508,43 +508,43 @@ error.io = 网络 I/O 错误。 error.any = 未知网络错误。 error.bloom = 未能初始化特效。\n您的设备可能不支持。 -weather.rain.name = Rain -weather.snow.name = Snow -weather.sandstorm.name = Sandstorm -weather.sporestorm.name = Sporestorm +weather.rain.name = 降雨 +weather.snow.name = 降雪 +weather.sandstorm.name = 沙尘暴 +weather.sporestorm.name = 孢子雾 -sectors.unexplored = [lightgray]Unexplored -sectors.resources = Resources: -sectors.production = Production: -sectors.stored = Stored: -sectors.resume = Resume -sectors.launch = Launch -sectors.select = Select -sectors.nonelaunch = [lightgray]none (sun) +sectors.unexplored = [lightgray]未探索 +sectors.resources = 资源: +sectors.production = 产出: +sectors.stored = 贮存: +sectors.resume = 继续 +sectors.launch = 发射 +sectors.select = 选择 +sectors.nonelaunch = [lightgray]无 (太阳) -sector.groundZero.name = Ground Zero -sector.craters.name = The Craters -sector.frozenForest.name = Frozen Forest -sector.ruinousShores.name = Ruinous Shores -sector.stainedMountains.name = Stained Mountains -sector.desolateRift.name = Desolate Rift -sector.nuclearComplex.name = Nuclear Production Complex -sector.overgrowth.name = Overgrowth -sector.tarFields.name = Tar Fields -sector.saltFlats.name = Salt Flats -sector.fungalPass.name = Fungal Pass +sector.groundZero.name = 零号地区 +sector.craters.name = 陨石带 +sector.frozenForest.name = 冰冻森林 +sector.ruinousShores.name = 遗迹海岸 +sector.stainedMountains.name = 绵延群山 +sector.desolateRift.name = 荒芜裂谷 +sector.nuclearComplex.name = 核裂阵 +sector.overgrowth.name = 增生区 +sector.tarFields.name = 油田 +sector.saltFlats.name = 盐碱荒滩 +sector.crags.name = 悬崖 -sector.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on. -sector.frozenForest.description = Even here, closer to mountains, the spores have spread. The frigid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders. -sector.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing. -sector.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills. -sector.ruinousShores.description = Past the wastes, is the shoreline. Once, this location housed a coastal defense array. Not much of it remains. Only the most basic defense structures have remained unscathed, everything else reduced to scrap.\nContinue the expansion outwards. Rediscover the technology. -sector.stainedMountains.description = Further inland lie the mountains, yet untainted by spores.\nExtract the abundant titanium in this area. Learn how to use it.\n\nThe enemy presence is greater here. Do not give them time to send their strongest units. -sector.overgrowth.description = This area is overgrown, closer to the source of the spores.\nThe enemy has established an outpost here. Build Titan units. Destroy it. Reclaim that which was lost. -sector.tarFields.description = The outskirts of an oil production zone, between the mountains and desert. One of the few areas with usable tar reserves.\nAlthough abandoned, this area has some dangerous enemy forces nearby. Do not underestimate them.\n\n[lightgray]Research oil processing technology if possible. -sector.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks. -sector.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers. -sector.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores. +sector.groundZero.description = 踏上旅程的最佳位置。这儿的敌人威胁很小,但资源也少。\n收集尽可能多的铅和铜。\n出发吧! +sector.frozenForest.description = 即使是靠近山脉的这里,孢子也已经扩散。他们不能长期停留在寒冷的温度中。\n\n开始运用电力。建造火力发电机并学会使用修理者。 +sector.saltFlats.description = 在沙漠的郊区有盐滩。在这个地方几乎找不到资源。\n\n敌人在这里建立了一个资源存储区。摧毁他们的核心。不要留下任何东西。 +sector.craters.description = 水在这个火山口积聚,这是旧战争的遗迹。夺下该区域。收集沙子来冶炼玻璃。用水泵抽水来加速炮塔和钻头。 +sector.ruinousShores.description = 穿过荒地,就是海岸线。这个地方曾经建造了一个海岸防御线。但现在所剩无几,只有最基本的防御结构仍然毫发无损,其他一切都被摧毁了。\n继续向外扩展。继续研究科技。 +sector.stainedMountains.description = 在更远的内陆地区是山脉,但这里没有被孢子污染。\n这一地区分布着丰富的钛,学习如何使用它。\n\n这里的敌人势力更大,不要给他们时间派出最强的部队。 +sector.overgrowth.description = 这个地区靠近孢子的来源,因此生长过度。\n敌人在这里建立了一个前哨站。建造尖刀单位来摧毁它并找回丢失的东西。 +sector.tarFields.description = 产油区边缘,位于山脉和沙漠之间。它少数几个有石油储量的地区之一。\n尽管被废弃,这附近仍有一些危险的敌方单位。不要低估他们。\n\n[lightgray]如果可能,研究石油加工技术。 +sector.desolateRift.description = 非常危险的区域。这儿的资源丰富但空间很小。敌人十分危险。尽快离开,不要被敌人的攻击间隔太长所愚弄。 +sector.nuclearComplex.description = 以前生产和加工钍的设施已变成废墟。\n[lightgray]研究钍及其多种用途。\n\n敌人在这里大量存在,不断消灭入侵者。 +sector.fungalPass.description = 介于高山和低矮孢子丛生的土地之间的过渡地带。这里有一个小型的敌方侦察基地。\n侦察它。\n使用尖刀和爬行者单位来摧毁两个核心。 settings.language = 语言 settings.data = 游戏数据 @@ -558,65 +558,65 @@ settings.graphics = 图像 settings.cleardata = 清除游戏数据… settings.clear.confirm = 您确定要清除此数据?\n此操作无法撤销! settings.clearall.confirm = [scarlet]警告![]\n这将清除所有数据,包括存档、地图、解锁和按键绑定。\n按「是」后,游戏将删除所有数据并自动退出。 -settings.clearsaves.confirm = Are you sure you want to clear all your saves? -settings.clearsaves = Clear Saves +settings.clearsaves.confirm = 您确定要清除存档? +settings.clearsaves = 清除存档 paused = [accent]< 暂停 > clear = 清除 banned = [scarlet]已禁止 -unplaceable.sectorcaptured = [scarlet]Requires captured sector +unplaceable.sectorcaptured = [scarlet]需要占领区块 yes = 是 no = 否 info.title = [accent]详情 error.title = [crimson]发生了一个错误 error.crashtitle = 发生了一个错误 unit.nobuild = [scarlet]单位未能建造 -blocks.input = 输入 -blocks.output = 输出 -blocks.booster = 增强物品/液体 -blocks.tiles = 所需地型 -blocks.affinities = 相关 +stat.input = 输入 +stat.output = 输出 +stat.booster = 增强物品/液体 +stat.tiles = 所需地型 +stat.affinities = 相关 block.unknown = [lightgray]??? -blocks.powercapacity = 能量容量 -blocks.powershot = 能量/发射 -blocks.damage = 伤害 -blocks.targetsair = 攻击空中单位 -blocks.targetsground = 攻击地面单位 -blocks.itemsmoved = 移动速度 -blocks.launchtime = 发射间隔时间 -blocks.shootrange = 范围 -blocks.size = 尺寸 -blocks.displaysize = Display Size -blocks.liquidcapacity = 液体容量 -blocks.powerrange = 能量范围 -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = 最多连接 -blocks.poweruse = 使用能量 -blocks.powerdamage = 功率/损伤 -blocks.itemcapacity = 物品容量 -blocks.basepowergeneration = 基础能源输出 -blocks.productiontime = 生产时间 -blocks.repairtime = 建筑完全修复时间 -blocks.speedincrease = 提速 -blocks.range = 范围 -blocks.drilltier = 可钻探矿物 -blocks.drillspeed = 基础钻探速度 -blocks.boosteffect = 增强效果 -blocks.maxunits = 最大单位数量 -blocks.health = 生命值 -blocks.buildtime = 建造时间 -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = 建造花费 -blocks.inaccuracy = 误差 -blocks.shots = 发射数 -blocks.reload = 每秒发射数 -blocks.ammo = 弹药 -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = 能量容量 +stat.powershot = 能量/发射 +stat.damage = 伤害 +stat.targetsair = 攻击空中单位 +stat.targetsground = 攻击地面单位 +stat.itemsmoved = 移动速度 +stat.launchtime = 发射间隔时间 +stat.shootrange = 范围 +stat.size = 尺寸 +stat.displaysize = 显示尺寸 +stat.liquidcapacity = 液体容量 +stat.powerrange = 能量范围 +stat.linkrange = 连接范围 +stat.instructions = 指令数量 +stat.powerconnections = 最多连接 +stat.poweruse = 使用能量 +stat.powerdamage = 功率/损伤 +stat.itemcapacity = 物品容量 +stat.basepowergeneration = 基础能源输出 +stat.productiontime = 生产时间 +stat.repairtime = 建筑完全修复时间 +stat.speedincrease = 提速 +stat.range = 范围 +stat.drilltier = 可钻探矿物 +stat.drillspeed = 基础钻探速度 +stat.boosteffect = 增强效果 +stat.maxunits = 最大单位数量 +stat.health = 生命值 +stat.buildtime = 建造时间 +stat.maxconsecutive = 最大连续 +stat.buildcost = 建造花费 +stat.inaccuracy = 误差 +stat.shots = 发射数 +stat.reload = 每秒发射数 +stat.ammo = 弹药 +stat.shieldhealth = 盾容 +stat.cooldowntime = 冷却时间 bar.drilltierreq = 需要更好的钻头 -bar.noresources = Missing Resources -bar.corereq = Core Base Required +bar.noresources = 缺失资源 +bar.corereq = 缺失核心基座 bar.drillspeed = 挖掘速度:{0}/秒 bar.pumpspeed = 泵压速度:{0}/秒 bar.efficiency = 效率:{0}% @@ -627,7 +627,7 @@ bar.poweroutput = 能量输出:{0} bar.items = 物品:{0} bar.capacity = 容量:{0} bar.unitcap = {0} {1}/{2} -bar.limitreached = [scarlet] {0} / {1}[white] {2}\n[lightgray][[unit disabled] +bar.limitreached = [scarlet] {0} / {1}[white] {2}\n[lightgray][[单位上限] bar.liquid = 液体 bar.heat = 热量 bar.power = 电力 @@ -639,7 +639,7 @@ bullet.damage = [stat]{0}[lightgray] 伤害 bullet.splashdamage = [stat]{0}[lightgray] 范围伤害 ~[stat] {1}[lightgray] 格 bullet.incendiary = [stat] 燃烧 bullet.homing = [stat] 追踪 -bullet.shock = [stat] 击晕 +bullet.shock = [stat] 电击 bullet.frag = [stat] 分裂 bullet.knockback = [stat]{0}[lightgray] 击退 bullet.freezing = [stat] 冰冻 @@ -655,16 +655,16 @@ unit.liquidunits = 液体 unit.powerunits = 能量 unit.degrees = 度 unit.seconds = 秒 -unit.minutes = mins +unit.minutes = 分 unit.persecond = /秒 -unit.perminute = /min +unit.perminute = /分 unit.timesspeed = 倍 速度 unit.percent = % -unit.shieldhealth = shield health +unit.shieldhealth = 盾容 unit.items = 物品 -unit.thousands = k -unit.millions = mil -unit.billions = b +unit.thousands = K +unit.millions = M +unit.billions = B category.general = 普通 category.power = 能量 category.liquids = 液体 @@ -720,7 +720,7 @@ setting.minimap.name = 显示小地图 setting.coreitems.name = 显示核心 (开发中) setting.position.name = 显示玩家坐标 setting.musicvol.name = 音乐音量 -setting.atmosphere.name = Show Planet Atmosphere +setting.atmosphere.name = 显示行星大气层 setting.ambientvol.name = 环境音量 setting.mutemusic.name = 无音乐 setting.sfxvol.name = 音效音量 @@ -743,14 +743,14 @@ keybinds.mobile = [scarlet]这里的大多数按键绑定在移动设备上都 category.general.name = 常规 category.view.name = 视图 category.multiplayer.name = 多人 -category.blocks.name = Block Select +category.blocks.name = 选择方块 command.attack = 攻击 command.rally = 集合 command.retreat = 撤退 -command.idle = Idle +command.idle = 闲置 placement.blockselectkeys = \n[lightgray]按键:[{0}, keybind.respawn.name = 重生 -keybind.control.name = Control Unit +keybind.control.name = 控制单位 keybind.clear_building.name = 清除建筑 keybind.press = 请按一个键… keybind.press.axis = 请按一个轴或键… @@ -760,8 +760,8 @@ keybind.toggle_block_status.name = 显隐方块状态 keybind.move_x.name = 水平移动 keybind.move_y.name = 竖直移动 keybind.mouse_move.name = 跟随鼠标 -keybind.pan.name = Pan View -keybind.boost.name = 推送 +keybind.pan.name = 平移视图 +keybind.boost.name = 推进 keybind.schematic_select.name = 选择区域 keybind.schematic_menu.name = 蓝图目录 keybind.schematic_flip_x.name = 水平翻转 @@ -788,9 +788,9 @@ keybind.diagonal_placement.name = 斜线建造 keybind.pick.name = 选择建筑 keybind.break_block.name = 破坏建筑 keybind.deselect.name = 取消选择 -keybind.pickupCargo.name = Pickup Cargo -keybind.dropCargo.name = Drop Cargo -keybind.command.name = Command +keybind.pickupCargo.name = 拾取货物 +keybind.dropCargo.name = 释放货物 +keybind.command.name = 指挥 keybind.shoot.name = 射击 keybind.zoom.name = 缩放 keybind.menu.name = 菜单 @@ -825,10 +825,10 @@ rules.reactorexplosions = 反应堆爆炸 rules.wavetimer = 波次计时器 rules.waves = 波次 rules.attack = 攻击模式 -rules.buildai = AI Building +rules.buildai = AI建造 rules.enemyCheat = 敌人(红队)无限资源 rules.blockhealthmultiplier = 建筑生命倍数 -rules.blockdamagemultiplier = Block Damage Multiplier +rules.blockdamagemultiplier = 建筑伤害倍数 rules.unitbuildspeedmultiplier = 单位生产速度倍数 rules.unithealthmultiplier = 单位生命倍数 rules.unitdamagemultiplier = 单位伤害倍数 @@ -839,20 +839,20 @@ rules.buildspeedmultiplier = 建设时间倍数 rules.deconstructrefundmultiplier = 拆除返还倍数 rules.waitForWaveToEnd = 等待敌人时间 rules.dropzoneradius = 敌人出生点禁区大小:[lightgray](格) -rules.unitammo = Units Require Ammo +rules.unitammo = 单位消耗子弹 rules.title.waves = 波次 rules.title.resourcesbuilding = 资源和建造 rules.title.enemy = 敌人 rules.title.unit = 单位 rules.title.experimental = 实验性 -rules.title.environment = Environment +rules.title.environment = 环境性 rules.lighting = 光照 rules.fire = Fire -rules.explosions = Block/Unit Explosion Damage +rules.explosions = 建筑/单位爆炸伤害 rules.ambientlight = 环境光 -rules.weather = Weather -rules.weather.frequency = Frequency: -rules.weather.duration = Duration: +rules.weather = 气候 +rules.weather.frequency = 频率: +rules.weather.duration = 时长: content.item.name = 物品 content.liquid.name = 液体 @@ -897,61 +897,61 @@ liquid.viscosity = [lightgray]粘度:{0} liquid.temperature = [lightgray]温度:{0} unit.dagger.name = 尖刀 -unit.mace.name = Mace +unit.mace.name = 牙狼 unit.fortress.name = 堡垒 -unit.nova.name = Nova -unit.pulsar.name = Pulsar -unit.quasar.name = Quasar -unit.crawler.name = 爬行者 -unit.atrax.name = Atrax -unit.spiroct.name = Spiroct -unit.arkyid.name = Arkyid -unit.toxopid.name = Toxopid -unit.flare.name = Flare -unit.horizon.name = Horizon -unit.zenith.name = Zenith -unit.antumbra.name = Antumbra -unit.eclipse.name = Eclipse -unit.mono.name = Mono -unit.poly.name = Poly -unit.mega.name = Mega -unit.quad.name = Quad -unit.oct.name = Oct -unit.risso.name = Risso -unit.minke.name = Minke -unit.bryde.name = Bryde -unit.sei.name = Sei -unit.omura.name = Omura -unit.alpha.name = Alpha -unit.beta.name = Beta -unit.gamma.name = Gamma -unit.scepter.name = Scepter -unit.reign.name = Reign -unit.vela.name = Vela -unit.corvus.name = Corvus +unit.nova.name = 新星 +unit.pulsar.name = 脉冲星 +unit.quasar.name = 超星 +unit.crawler.name = 爬虫 +unit.atrax.name = 火蛛 +unit.spiroct.name = 天蝎 +unit.arkyid.name = 血蛭 +unit.toxopid.name = 毒蟒 +unit.flare.name = 星耀 +unit.horizon.name = 天垠 +unit.zenith.name = 苍穹 +unit.antumbra.name = 半影 +unit.eclipse.name = 日蚀 +unit.mono.name = 独影 +unit.poly.name = 聚幻 +unit.mega.name = 巨像 +unit.quad.name = 雷霆 +unit.oct.name = 要塞 +unit.risso.name = 梭鱼 +unit.minke.name = 刺鲸 +unit.bryde.name = 虎鲨 +unit.sei.name = 湖妖 +unit.omura.name = 海神 +unit.alpha.name = 阿尔法 +unit.beta.name = 贝塔 +unit.gamma.name = 伽玛 +unit.scepter.name = 权杖 +unit.reign.name = 君王 +unit.vela.name = 灾星 +unit.corvus.name = 死星 -block.resupply-point.name = Resupply Point -block.parallax.name = Parallax +block.resupply-point.name = 补给点 +block.parallax.name = 阻滞光束 block.cliff.name = 悬崖 block.sand-boulder.name = 沙砂巨石 block.grass.name = 草地 block.slag.name = 矿渣 block.salt.name = 盐碱地 -block.salt-wall.name = Salt Wall +block.salt-wall.name = 盐墙 block.pebbles.name = 鹅卵石 block.tendrils.name = 卷须 -block.sand-wall.name = Sand Wall +block.sand-wall.name = 沙墙 block.spore-pine.name = 孢子树 -block.spore-wall.name = Spore Wall -block.boulder.name = Boulder -block.snow-boulder.name = Snow Boulder +block.spore-wall.name = 孢子墙 +block.boulder.name = 巨石 +block.snow-boulder.name = 雪石 block.snow-pine.name = 雪树 block.shale.name = 页岩地 block.shale-boulder.name = 页岩巨石 block.moss.name = 苔藓地 block.shrubs.name = 灌木丛 block.spore-moss.name = 孢子苔藓地 -block.shale-wall.name = Shale Wall +block.shale-wall.name = 页岩墙 block.scrap-wall.name = 废墙 block.scrap-wall-large.name = 大型废墙 block.scrap-wall-huge.name = 巨型废墙 @@ -979,17 +979,17 @@ block.craters.name = 陨石坑 block.sand-water.name = 沙 水 block.darksand-water.name = 暗沙 水 block.char.name = 焦土 -block.dacite.name = Dacite -block.dacite-wall.name = Dacite Wall +block.dacite.name = 英安岩 +block.dacite-wall.name = 英安岩墙 block.ice-snow.name = 冰雪地 -block.stone-wall.name = Stone Wall -block.ice-wall.name = Ice Wall -block.snow-wall.name = Snow Wall -block.dune-wall.name = Dune Wall +block.stone-wall.name = 石墙 +block.ice-wall.name = 冰墙 +block.snow-wall.name = 雪墙 +block.dune-wall.name = 沙丘岩 block.pine.name = 松树 -block.dirt.name = Dirt -block.dirt-wall.name = Dirt Wall -block.mud.name = Mud +block.dirt.name = 泥土 +block.dirt-wall.name = 泥土墙 +block.mud.name = 泥巴 block.white-tree-dead.name = 枯萎的白树 block.white-tree.name = 白树 block.spore-cluster.name = 孢子簇 @@ -1005,7 +1005,7 @@ block.dark-panel-4.name = 暗面板4 block.dark-panel-5.name = 暗面板5 block.dark-panel-6.name = 暗面板6 block.dark-metal.name = 暗金属 -block.basalt.name = Basalt +block.basalt.name = 玄武岩 block.hotrock.name = 热石头 block.magmarock.name = 岩浆石头 block.copper-wall.name = 铜墙 @@ -1081,8 +1081,8 @@ block.ripple.name = 浪涌 block.phase-conveyor.name = 相织物传送带桥 block.bridge-conveyor.name = 传送带桥 block.plastanium-compressor.name = 塑钢压缩机 -block.pyratite-mixer.name = 硫混合器 -block.blast-mixer.name = 爆炸混合器 +block.pyratite-mixer.name = 硫化物混合器 +block.blast-mixer.name = 爆炸物混合器 block.solar-panel.name = 太阳能板 block.solar-panel-large.name = 大型太阳能板 block.oil-extractor.name = 石油钻井 @@ -1101,12 +1101,12 @@ block.blast-drill.name = 爆破钻头 block.thermal-pump.name = 热能泵 block.thermal-generator.name = 热能发电机 block.alloy-smelter.name = 合金冶炼厂 -block.mender.name = 修理者 +block.mender.name = 修复器 block.mend-projector.name = 修理投影器 block.surge-wall.name = 波动墙 block.surge-wall-large.name = 大型波动墙 -block.cyclone.name = 气旋炮 -block.fuse.name = 雷光炮 +block.cyclone.name = 气旋 +block.fuse.name = 雷光 block.shock-mine.name = 脉冲地雷 block.overdrive-projector.name = 超速投影器 block.force-projector.name = 力墙投影器 @@ -1117,28 +1117,28 @@ block.meltdown.name = 熔毁 block.container.name = 容器 block.launch-pad.name = 发射台 block.launch-pad-large.name = 大型发射台 -block.segment.name = 分割机 -block.command-center.name = Command Center -block.ground-factory.name = 地面工厂 -block.air-factory.name = Air Factory -block.naval-factory.name = Naval Factory -block.additive-reconstructor.name = Additive Reconstructor -block.multiplicative-reconstructor.name = Multiplicative Reconstructor -block.exponential-reconstructor.name = Exponential Reconstructor -block.tetrative-reconstructor.name = Tetrative Reconstructor -block.payload-conveyor.name = Mass Conveyor -block.payload-router.name = Payload Router -block.disassembler.name = Disassembler -block.silicon-crucible.name = Silicon Crucible -block.overdrive-dome.name = Overdrive Dome +block.segment.name = 裂解光束 +block.command-center.name = 指挥中心 +block.ground-factory.name = 陆战单位工厂 +block.air-factory.name = 空战单位工厂 +block.naval-factory.name = 海战单位工厂 +block.additive-reconstructor.name = 数增级单位重构工厂 +block.multiplicative-reconstructor.name = 倍增级单位重构工厂 +block.exponential-reconstructor.name = 幂乘级单位重构工厂 +block.tetrative-reconstructor.name = 无量级单位重构工厂 +block.payload-conveyor.name = 载荷传送带 +block.payload-router.name = 载荷路由器 +block.disassembler.name = 分离机 +block.silicon-crucible.name = 热能坩埚 +block.overdrive-dome.name = 超速场投射器 -block.switch.name = Switch -block.micro-processor.name = Micro Processor -block.logic-processor.name = Logic Processor -block.hyper-processor.name = Hyper Processor -block.logic-display.name = Logic Display -block.large-logic-display.name = Large Logic Display -block.memory-cell.name = Memory Cell +block.switch.name = 开关 +block.micro-processor.name = 微型处理器 +block.logic-processor.name = 逻辑处理器 +block.hyper-processor.name = 超频处理器 +block.logic-display.name = 逻辑显示屏 +block.large-logic-display.name = 大型逻辑显示屏 +block.memory-cell.name = 存储单元 team.blue.name = 蓝 team.crux.name = 红 @@ -1299,7 +1299,7 @@ block.salvo.description = 双管炮的升级版。中型,快速射出一串子 block.fuse.description = 大型近程炮塔,发射三道刺穿敌人的短程光束。 block.ripple.description = 大型远程炮台,非常强力,向远处的敌人投射一簇弹药。 block.cyclone.description = 大型炮塔,对空对地,发射在敌人周围引爆的爆炸物。 -block.spectre.description = 超大型炮塔,对空对地,一次射出两颗强大的穿甲弹药。 +block.spectre.description = 超大型炮塔,对空对地,一次射出两颗强大的破甲弹。 block.meltdown.description = 超大型激光炮塔,充能之后持续发射光束,需要冷却剂。 -block.repair-point.description = 持续治疗其附近伤势最重的单位。 -block.segment.description = 对行进中的导弹进行破坏和摧毁, 除激光以外. +block.repair-point.description = 持续治疗其附近受损最严重的单位。 +block.segment.description = 摧毁袭来的除激光以外的子弹或导弹. \ No newline at end of file diff --git a/core/assets/bundles/bundle_zh_TW.properties b/core/assets/bundles/bundle_zh_TW.properties index 85efa9a527..e495f4b768 100644 --- a/core/assets/bundles/bundle_zh_TW.properties +++ b/core/assets/bundles/bundle_zh_TW.properties @@ -570,49 +570,49 @@ info.title = 資訊 error.title = [crimson]發生錯誤 error.crashtitle = 發生錯誤 unit.nobuild = [scarlet]單位不能建造 -blocks.input = 輸入 -blocks.output = 輸出 -blocks.booster = 強化 -blocks.tiles = 需求方塊 -blocks.affinities = 親和方塊 +stat.input = 輸入 +stat.output = 輸出 +stat.booster = 強化 +stat.tiles = 需求方塊 +stat.affinities = 親和方塊 block.unknown = [lightgray]??? -blocks.powercapacity = 蓄電量 -blocks.powershot = 能量/射擊 -blocks.damage = 傷害 -blocks.targetsair = 攻擊空中目標 -blocks.targetsground = 攻擊地面目標 -blocks.itemsmoved = 移動速度 -blocks.launchtime = 發射間隔 -blocks.shootrange = 範圍 -blocks.size = 尺寸 -blocks.displaysize = Display Size -blocks.liquidcapacity = 液體容量 -blocks.powerrange = 輸出範圍 -blocks.linkrange = Link Range -blocks.instructions = Instructions -blocks.powerconnections = 最大連接數 -blocks.poweruse = 能量使用 -blocks.powerdamage = 能量/傷害 -blocks.itemcapacity = 物品容量 -blocks.basepowergeneration = 基礎能量生產 -blocks.productiontime = 生產時間 -blocks.repairtime = 方塊完全修復時間 -blocks.speedincrease = 速度提升 -blocks.range = 範圍 -blocks.drilltier = 可鑽取礦物 -blocks.drillspeed = 基本鑽取速度 -blocks.boosteffect = 提升效應 -blocks.maxunits = 最大活躍單位 -blocks.health = 耐久度 -blocks.buildtime = 建設時間 -blocks.maxconsecutive = Max Consecutive -blocks.buildcost = 建造成本 -blocks.inaccuracy = 誤差 -blocks.shots = 射擊數 -blocks.reload = 射擊次數/秒 -blocks.ammo = 彈藥 -blocks.shieldhealth = Shield Health -blocks.cooldowntime = Cooldown Time +stat.powercapacity = 蓄電量 +stat.powershot = 能量/射擊 +stat.damage = 傷害 +stat.targetsair = 攻擊空中目標 +stat.targetsground = 攻擊地面目標 +stat.itemsmoved = 移動速度 +stat.launchtime = 發射間隔 +stat.shootrange = 範圍 +stat.size = 尺寸 +stat.displaysize = Display Size +stat.liquidcapacity = 液體容量 +stat.powerrange = 輸出範圍 +stat.linkrange = Link Range +stat.instructions = Instructions +stat.powerconnections = 最大連接數 +stat.poweruse = 能量使用 +stat.powerdamage = 能量/傷害 +stat.itemcapacity = 物品容量 +stat.basepowergeneration = 基礎能量生產 +stat.productiontime = 生產時間 +stat.repairtime = 方塊完全修復時間 +stat.speedincrease = 速度提升 +stat.range = 範圍 +stat.drilltier = 可鑽取礦物 +stat.drillspeed = 基本鑽取速度 +stat.boosteffect = 提升效應 +stat.maxunits = 最大活躍單位 +stat.health = 耐久度 +stat.buildtime = 建設時間 +stat.maxconsecutive = Max Consecutive +stat.buildcost = 建造成本 +stat.inaccuracy = 誤差 +stat.shots = 射擊數 +stat.reload = 射擊次數/秒 +stat.ammo = 彈藥 +stat.shieldhealth = Shield Health +stat.cooldowntime = Cooldown Time bar.drilltierreq = 需要更好的鑽頭 bar.noresources = Missing Resources @@ -1302,4 +1302,4 @@ block.cyclone.description = 一種對空和對地的大型砲塔。向附近單 block.spectre.description = 一種雙炮管的巨型砲塔。向空中及地面敵人發射大型的穿甲彈。 block.meltdown.description = 一種巨型激光砲塔。充能並發射持續性的激光光束。需要冷卻液以運作。 block.repair-point.description = 持續治療附近最近的受損單位。 -block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. +block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted. \ No newline at end of file diff --git a/core/assets/contributors b/core/assets/contributors index 69de5a3d8e..9f1cf8c9f4 100644 --- a/core/assets/contributors +++ b/core/assets/contributors @@ -95,3 +95,4 @@ ThePlayerA YellOw139 PetrGasparik LeoDog896 +Summet diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index b07514ea1b..417ed98b34 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -313,3 +313,4 @@ 63423=memory-bank|block-memory-bank-medium 63422=foreshadow|block-foreshadow-medium 63421=tsunami|block-tsunami-medium +63420=space|block-space-medium diff --git a/core/assets/maps/archipelago.msav b/core/assets/maps/archipelago.msav new file mode 100644 index 0000000000..24764ccf20 Binary files /dev/null and b/core/assets/maps/archipelago.msav differ diff --git a/core/assets/maps/caldera.msav b/core/assets/maps/caldera.msav index 4ed0889f5e..57bb5c382f 100644 Binary files a/core/assets/maps/caldera.msav and b/core/assets/maps/caldera.msav differ diff --git a/core/assets/maps/craters.msav b/core/assets/maps/craters.msav index b879701ae6..04c1aa73d3 100644 Binary files a/core/assets/maps/craters.msav and b/core/assets/maps/craters.msav differ diff --git a/core/assets/maps/fork.msav b/core/assets/maps/fork.msav index 0a6a82d226..2fd62bd91b 100644 Binary files a/core/assets/maps/fork.msav and b/core/assets/maps/fork.msav differ diff --git a/core/assets/maps/fortress.msav b/core/assets/maps/fortress.msav index c5f58e0380..db60a0490d 100644 Binary files a/core/assets/maps/fortress.msav and b/core/assets/maps/fortress.msav differ diff --git a/core/assets/maps/frozenForest.msav b/core/assets/maps/frozenForest.msav index a2a1f52354..0eb9f1fe56 100644 Binary files a/core/assets/maps/frozenForest.msav and b/core/assets/maps/frozenForest.msav differ diff --git a/core/assets/maps/fungalPass.msav b/core/assets/maps/fungalPass.msav index c154c2e4db..1e3a26f520 100644 Binary files a/core/assets/maps/fungalPass.msav and b/core/assets/maps/fungalPass.msav differ diff --git a/core/assets/maps/glacier.msav b/core/assets/maps/glacier.msav index 1494079697..83a4f07437 100644 Binary files a/core/assets/maps/glacier.msav and b/core/assets/maps/glacier.msav differ diff --git a/core/assets/maps/islands.msav b/core/assets/maps/islands.msav index 48e13f8b6f..90159d57e0 100644 Binary files a/core/assets/maps/islands.msav and b/core/assets/maps/islands.msav differ diff --git a/core/assets/maps/labyrinth.msav b/core/assets/maps/labyrinth.msav index 7501a592ad..d63ca28bf9 100644 Binary files a/core/assets/maps/labyrinth.msav and b/core/assets/maps/labyrinth.msav differ diff --git a/core/assets/maps/maze.msav b/core/assets/maps/maze.msav index ea34efa876..25386f23c4 100644 Binary files a/core/assets/maps/maze.msav and b/core/assets/maps/maze.msav differ diff --git a/core/assets/maps/moltenLake.msav b/core/assets/maps/moltenLake.msav new file mode 100644 index 0000000000..a409307c6f Binary files /dev/null and b/core/assets/maps/moltenLake.msav differ diff --git a/core/assets/maps/mudFlats.msav b/core/assets/maps/mudFlats.msav new file mode 100644 index 0000000000..1ba2e25ceb Binary files /dev/null and b/core/assets/maps/mudFlats.msav differ diff --git a/core/assets/maps/ruinousShores.msav b/core/assets/maps/ruinousShores.msav index a0ef267a99..41e957c0ff 100644 Binary files a/core/assets/maps/ruinousShores.msav and b/core/assets/maps/ruinousShores.msav differ diff --git a/core/assets/maps/saltFlats.msav b/core/assets/maps/saltFlats.msav index 9a70ba342a..556b33700f 100644 Binary files a/core/assets/maps/saltFlats.msav and b/core/assets/maps/saltFlats.msav differ diff --git a/core/assets/maps/shattered.msav b/core/assets/maps/shattered.msav index cad5016e9d..549e42cab7 100644 Binary files a/core/assets/maps/shattered.msav and b/core/assets/maps/shattered.msav differ diff --git a/core/assets/maps/tarFields.msav b/core/assets/maps/tarFields.msav index 06eaed164d..bf8b306f95 100644 Binary files a/core/assets/maps/tarFields.msav and b/core/assets/maps/tarFields.msav differ diff --git a/core/assets/maps/tendrils.msav b/core/assets/maps/tendrils.msav index 178c11a03e..825437d6c5 100644 Binary files a/core/assets/maps/tendrils.msav and b/core/assets/maps/tendrils.msav differ diff --git a/core/assets/maps/triad.msav b/core/assets/maps/triad.msav index a693b02cba..fd25effa9c 100644 Binary files a/core/assets/maps/triad.msav and b/core/assets/maps/triad.msav differ diff --git a/core/assets/maps/veins.msav b/core/assets/maps/veins.msav index 6ad97e728a..744dbaf99d 100644 Binary files a/core/assets/maps/veins.msav and b/core/assets/maps/veins.msav differ diff --git a/core/assets/maps/wasteland.msav b/core/assets/maps/wasteland.msav index f7bb73595e..b00e76fd12 100644 Binary files a/core/assets/maps/wasteland.msav and b/core/assets/maps/wasteland.msav differ diff --git a/core/assets/scripts/base.js b/core/assets/scripts/base.js index c6d7be846b..ace7d878ee 100755 --- a/core/assets/scripts/base.js +++ b/core/assets/scripts/base.js @@ -9,8 +9,8 @@ const readBytes = path => Vars.mods.getScripts().readBytes(path) const loadMusic = path => Vars.mods.getScripts().loadMusic(path) const loadSound = path => Vars.mods.getScripts().loadSound(path) -var scriptName = "base.js" -var modName = "none" +let scriptName = "base.js" +let modName = "none" const print = text => log(modName + "/" + scriptName, text); diff --git a/core/assets/shaders/default.frag b/core/assets/shaders/default.frag new file mode 100644 index 0000000000..93be3cffc9 --- /dev/null +++ b/core/assets/shaders/default.frag @@ -0,0 +1,9 @@ +varying lowp vec4 v_color; +varying lowp vec4 v_mix_color; +varying vec2 v_texCoords; +uniform sampler2D u_texture; + +void main(){ + vec4 c = texture2D(u_texture, v_texCoords); + gl_FragColor = v_color * mix(c, vec4(v_mix_color.rgb, c.a), v_mix_color.a); +} \ No newline at end of file diff --git a/core/assets/shaders/planet.vert b/core/assets/shaders/planet.vert index f500af0ecf..4723e2bfff 100755 --- a/core/assets/shaders/planet.vert +++ b/core/assets/shaders/planet.vert @@ -10,7 +10,7 @@ uniform vec3 u_ambientColor; varying vec4 v_col; -const vec3 diffuse = vec3(0); +const vec3 diffuse = vec3(0.01); const float shinefalloff = 4.0; const float shinelen = 0.2; diff --git a/core/assets/shaders/space.frag b/core/assets/shaders/space.frag new file mode 100755 index 0000000000..4b95cf7438 --- /dev/null +++ b/core/assets/shaders/space.frag @@ -0,0 +1,23 @@ +#define HIGHP +#define NSCALE 2700.0 +#define CAMSCALE (NSCALE*5.0) + +uniform sampler2D u_texture; +uniform sampler2D u_stars; + +uniform vec2 u_campos; +uniform vec2 u_ccampos; +uniform vec2 u_resolution; +uniform float u_time; + +varying vec2 v_texCoords; + +void main(){ + vec2 c = v_texCoords.xy; + vec2 coords = vec2(c.x * u_resolution.x, c.y * u_resolution.y); + + vec4 color = texture2D(u_texture, c); + color.rgb = texture2D(u_stars, coords/NSCALE + vec2(-0.1, -0.1) + u_ccampos / CAMSCALE).rgb; + + gl_FragColor = color; +} \ No newline at end of file diff --git a/core/assets/sprites/block_colors.png b/core/assets/sprites/block_colors.png index ccbd6ed7e2..c297dccdf7 100644 Binary files a/core/assets/sprites/block_colors.png and b/core/assets/sprites/block_colors.png differ diff --git a/core/assets/sprites/fallback/sprites.atlas b/core/assets/sprites/fallback/sprites.atlas index 13e8478d73..fd8aece5ae 100644 --- a/core/assets/sprites/fallback/sprites.atlas +++ b/core/assets/sprites/fallback/sprites.atlas @@ -7862,1456 +7862,3318 @@ filter: nearest,nearest repeat: none basalt-edge rotate: false - xy: 1, 395 + xy: 1, 399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 basalt1 rotate: false - xy: 1561, 459 + xy: 2005, 463 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 basalt2 rotate: false - xy: 1595, 459 + xy: 1299, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 basalt3 rotate: false - xy: 1629, 459 + xy: 1333, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char1 rotate: false - xy: 1663, 459 + xy: 1367, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char2 rotate: false - xy: 1697, 459 + xy: 1401, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char3 rotate: false - xy: 1731, 459 + xy: 1435, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cliff rotate: false - xy: 1765, 459 + xy: 1469, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +cliff0 + rotate: false + xy: 589, 137 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask1 + rotate: false + xy: 589, 137 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask129 + rotate: false + xy: 589, 137 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask131 + rotate: false + xy: 589, 137 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask3 + rotate: false + xy: 589, 137 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff1 + rotate: false + xy: 687, 235 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask130 + rotate: false + xy: 687, 235 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask2 + rotate: false + xy: 687, 235 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff2 + rotate: false + xy: 785, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask12 + rotate: false + xy: 785, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask132 + rotate: false + xy: 785, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask134 + rotate: false + xy: 785, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask14 + rotate: false + xy: 785, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask140 + rotate: false + xy: 785, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask142 + rotate: false + xy: 785, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask4 + rotate: false + xy: 785, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask6 + rotate: false + xy: 785, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff3 + rotate: false + xy: 883, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff4 + rotate: false + xy: 589, 71 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff5 + rotate: false + xy: 949, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff6 + rotate: false + xy: 1015, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff7 + rotate: false + xy: 1081, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask0 + rotate: false + xy: 1147, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask128 + rotate: false + xy: 1147, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask10 + rotate: false + xy: 1411, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask138 + rotate: false + xy: 1411, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask112 + rotate: false + xy: 1709, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask120 + rotate: false + xy: 1709, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask113 + rotate: false + xy: 1775, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask115 + rotate: false + xy: 1775, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask121 + rotate: false + xy: 1775, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask123 + rotate: false + xy: 1775, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask114 + rotate: false + xy: 1841, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask122 + rotate: false + xy: 1841, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask116 + rotate: false + xy: 1907, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask118 + rotate: false + xy: 1907, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask117 + rotate: false + xy: 787, 169 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask119 + rotate: false + xy: 787, 169 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask124 + rotate: false + xy: 787, 103 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask126 + rotate: false + xy: 787, 103 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask125 + rotate: false + xy: 787, 37 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask127 + rotate: false + xy: 787, 37 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask16 + rotate: false + xy: 1477, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask144 + rotate: false + xy: 1477, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask152 + rotate: false + xy: 1477, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask176 + rotate: false + xy: 1477, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask184 + rotate: false + xy: 1477, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask24 + rotate: false + xy: 1477, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask48 + rotate: false + xy: 1477, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask56 + rotate: false + xy: 1477, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask17 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask145 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask147 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask153 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask155 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask177 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask179 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask185 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask187 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask19 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask25 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask27 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask49 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask51 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask57 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask59 + rotate: false + xy: 1543, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask18 + rotate: false + xy: 1609, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask146 + rotate: false + xy: 1609, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask154 + rotate: false + xy: 1609, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask178 + rotate: false + xy: 1609, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask186 + rotate: false + xy: 1609, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask26 + rotate: false + xy: 1609, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask50 + rotate: false + xy: 1609, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask58 + rotate: false + xy: 1609, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask192 + rotate: false + xy: 885, 267 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask224 + rotate: false + xy: 885, 267 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask193 + rotate: false + xy: 853, 201 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask195 + rotate: false + xy: 853, 201 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask225 + rotate: false + xy: 853, 201 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask227 + rotate: false + xy: 853, 201 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask194 + rotate: false + xy: 853, 135 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask226 + rotate: false + xy: 853, 135 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask196 + rotate: false + xy: 853, 69 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask198 + rotate: false + xy: 853, 69 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask204 + rotate: false + xy: 853, 69 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask206 + rotate: false + xy: 853, 69 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask228 + rotate: false + xy: 853, 69 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask230 + rotate: false + xy: 853, 69 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask236 + rotate: false + xy: 853, 69 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask238 + rotate: false + xy: 853, 69 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask197 + rotate: false + xy: 951, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask199 + rotate: false + xy: 951, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask205 + rotate: false + xy: 951, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask207 + rotate: false + xy: 951, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask229 + rotate: false + xy: 951, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask231 + rotate: false + xy: 951, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask237 + rotate: false + xy: 951, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask239 + rotate: false + xy: 951, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask20 + rotate: false + xy: 1675, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask148 + rotate: false + xy: 1675, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask150 + rotate: false + xy: 1675, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask180 + rotate: false + xy: 1675, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask182 + rotate: false + xy: 1675, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask22 + rotate: false + xy: 1675, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask52 + rotate: false + xy: 1675, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask54 + rotate: false + xy: 1675, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask200 + rotate: false + xy: 1017, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask232 + rotate: false + xy: 1017, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask201 + rotate: false + xy: 1083, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask203 + rotate: false + xy: 1083, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask233 + rotate: false + xy: 1083, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask235 + rotate: false + xy: 1083, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask202 + rotate: false + xy: 1149, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask234 + rotate: false + xy: 1149, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask208 + rotate: false + xy: 1215, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask216 + rotate: false + xy: 1215, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask209 + rotate: false + xy: 1281, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask211 + rotate: false + xy: 1281, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask217 + rotate: false + xy: 1281, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask219 + rotate: false + xy: 1281, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask21 + rotate: false + xy: 1741, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask149 + rotate: false + xy: 1741, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask151 + rotate: false + xy: 1741, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask181 + rotate: false + xy: 1741, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask183 + rotate: false + xy: 1741, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask23 + rotate: false + xy: 1741, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask53 + rotate: false + xy: 1741, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask55 + rotate: false + xy: 1741, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask210 + rotate: false + xy: 1347, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask218 + rotate: false + xy: 1347, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask212 + rotate: false + xy: 1413, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask214 + rotate: false + xy: 1413, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask213 + rotate: false + xy: 1479, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask215 + rotate: false + xy: 1479, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask220 + rotate: false + xy: 1545, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask222 + rotate: false + xy: 1545, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask221 + rotate: false + xy: 1611, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask223 + rotate: false + xy: 1611, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask240 + rotate: false + xy: 1677, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask248 + rotate: false + xy: 1677, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask241 + rotate: false + xy: 1743, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask243 + rotate: false + xy: 1743, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask249 + rotate: false + xy: 1743, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask251 + rotate: false + xy: 1743, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask242 + rotate: false + xy: 1809, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask250 + rotate: false + xy: 1809, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask244 + rotate: false + xy: 1875, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask246 + rotate: false + xy: 1875, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask245 + rotate: false + xy: 1973, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask247 + rotate: false + xy: 1973, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask252 + rotate: false + xy: 1941, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask254 + rotate: false + xy: 1941, 299 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask253 + rotate: false + xy: 919, 201 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask255 + rotate: false + xy: 919, 201 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask28 + rotate: false + xy: 1807, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask156 + rotate: false + xy: 1807, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask158 + rotate: false + xy: 1807, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask188 + rotate: false + xy: 1807, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask190 + rotate: false + xy: 1807, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask30 + rotate: false + xy: 1807, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask60 + rotate: false + xy: 1807, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask62 + rotate: false + xy: 1807, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask29 + rotate: false + xy: 1873, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask157 + rotate: false + xy: 1873, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask159 + rotate: false + xy: 1873, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask189 + rotate: false + xy: 1873, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask191 + rotate: false + xy: 1873, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask31 + rotate: false + xy: 1873, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask61 + rotate: false + xy: 1873, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask63 + rotate: false + xy: 1873, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask32 + rotate: false + xy: 1939, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask160 + rotate: false + xy: 1939, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask33 + rotate: false + xy: 589, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask161 + rotate: false + xy: 589, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask163 + rotate: false + xy: 589, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask35 + rotate: false + xy: 589, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask34 + rotate: false + xy: 655, 137 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask162 + rotate: false + xy: 655, 137 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask36 + rotate: false + xy: 655, 71 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask164 + rotate: false + xy: 655, 71 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask166 + rotate: false + xy: 655, 71 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask172 + rotate: false + xy: 655, 71 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask174 + rotate: false + xy: 655, 71 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask38 + rotate: false + xy: 655, 71 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask44 + rotate: false + xy: 655, 71 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask46 + rotate: false + xy: 655, 71 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask37 + rotate: false + xy: 655, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask165 + rotate: false + xy: 655, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask167 + rotate: false + xy: 655, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask173 + rotate: false + xy: 655, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask175 + rotate: false + xy: 655, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask39 + rotate: false + xy: 655, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask45 + rotate: false + xy: 655, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask47 + rotate: false + xy: 655, 5 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask40 + rotate: false + xy: 753, 235 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask168 + rotate: false + xy: 753, 235 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask41 + rotate: false + xy: 721, 169 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask169 + rotate: false + xy: 721, 169 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask171 + rotate: false + xy: 721, 169 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask43 + rotate: false + xy: 721, 169 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask42 + rotate: false + xy: 721, 103 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask170 + rotate: false + xy: 721, 103 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask5 + rotate: false + xy: 1213, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask13 + rotate: false + xy: 1213, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask133 + rotate: false + xy: 1213, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask135 + rotate: false + xy: 1213, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask141 + rotate: false + xy: 1213, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask143 + rotate: false + xy: 1213, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask15 + rotate: false + xy: 1213, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask7 + rotate: false + xy: 1213, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask64 + rotate: false + xy: 721, 37 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask96 + rotate: false + xy: 721, 37 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask65 + rotate: false + xy: 851, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask67 + rotate: false + xy: 851, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask97 + rotate: false + xy: 851, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask99 + rotate: false + xy: 851, 333 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask66 + rotate: false + xy: 819, 267 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask98 + rotate: false + xy: 819, 267 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask68 + rotate: false + xy: 917, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask100 + rotate: false + xy: 917, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask102 + rotate: false + xy: 917, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask108 + rotate: false + xy: 917, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask110 + rotate: false + xy: 917, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask70 + rotate: false + xy: 917, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask76 + rotate: false + xy: 917, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask78 + rotate: false + xy: 917, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask69 + rotate: false + xy: 983, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask101 + rotate: false + xy: 983, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask103 + rotate: false + xy: 983, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask109 + rotate: false + xy: 983, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask111 + rotate: false + xy: 983, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask71 + rotate: false + xy: 983, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask77 + rotate: false + xy: 983, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask79 + rotate: false + xy: 983, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask72 + rotate: false + xy: 1049, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask104 + rotate: false + xy: 1049, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask73 + rotate: false + xy: 1115, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask105 + rotate: false + xy: 1115, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask107 + rotate: false + xy: 1115, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask75 + rotate: false + xy: 1115, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask74 + rotate: false + xy: 1181, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask106 + rotate: false + xy: 1181, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask8 + rotate: false + xy: 1279, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask136 + rotate: false + xy: 1279, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask80 + rotate: false + xy: 1247, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask88 + rotate: false + xy: 1247, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask81 + rotate: false + xy: 1313, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask83 + rotate: false + xy: 1313, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask89 + rotate: false + xy: 1313, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask91 + rotate: false + xy: 1313, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask82 + rotate: false + xy: 1379, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask90 + rotate: false + xy: 1379, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask84 + rotate: false + xy: 1445, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask86 + rotate: false + xy: 1445, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask85 + rotate: false + xy: 1511, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask87 + rotate: false + xy: 1511, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask9 + rotate: false + xy: 1345, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask11 + rotate: false + xy: 1345, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask137 + rotate: false + xy: 1345, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask139 + rotate: false + xy: 1345, 431 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask92 + rotate: false + xy: 1577, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask94 + rotate: false + xy: 1577, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask93 + rotate: false + xy: 1643, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask95 + rotate: false + xy: 1643, 365 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 coal1 rotate: false - xy: 1799, 459 + xy: 1503, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 coal2 rotate: false - xy: 1833, 459 + xy: 1537, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 coal3 rotate: false - xy: 1867, 459 + xy: 1571, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper1 rotate: false - xy: 1901, 459 + xy: 1605, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper2 rotate: false - xy: 1935, 459 + xy: 1639, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper3 rotate: false - xy: 1969, 459 + xy: 1673, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters1 rotate: false - xy: 2003, 459 + xy: 1707, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters2 rotate: false - xy: 491, 1 + xy: 1741, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters3 rotate: false - xy: 557, 67 + xy: 1775, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters4 rotate: false - xy: 655, 165 + xy: 1809, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters5 rotate: false - xy: 753, 263 + xy: 1843, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters6 rotate: false - xy: 851, 361 + xy: 1877, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite-edge rotate: false - xy: 1, 297 + xy: 1, 301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dacite-wall-large rotate: false - xy: 491, 35 + xy: 919, 135 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dacite-wall1 rotate: false - xy: 851, 327 + xy: 755, 3 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite-wall2 rotate: false - xy: 1411, 409 + xy: 789, 3 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite1 rotate: false - xy: 525, 1 + xy: 1911, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite2 rotate: false - xy: 655, 131 + xy: 1945, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite3 rotate: false - xy: 753, 229 + xy: 721, 3 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-metal-large rotate: false - xy: 589, 133 + xy: 919, 69 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dark-metal1 rotate: false - xy: 1445, 409 + xy: 853, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-metal2 rotate: false - xy: 1479, 409 + xy: 887, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-1 rotate: false - xy: 1513, 409 + xy: 921, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-1-edge rotate: false - xy: 99, 395 + xy: 99, 399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-2 rotate: false - xy: 1561, 425 + xy: 2007, 331 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-2-edge rotate: false - xy: 1, 199 + xy: 1, 203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-3 rotate: false - xy: 1595, 425 + xy: 985, 67 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-3-edge rotate: false - xy: 99, 297 + xy: 99, 301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-4 rotate: false - xy: 1629, 425 + xy: 1019, 67 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-4-edge rotate: false - xy: 197, 395 + xy: 197, 399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-5 rotate: false - xy: 1663, 425 + xy: 1053, 67 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-5-edge rotate: false - xy: 1, 101 + xy: 1, 105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-6 rotate: false - xy: 1697, 425 + xy: 1087, 67 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-6-edge rotate: false - xy: 99, 199 + xy: 99, 203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 darksand-edge rotate: false - xy: 197, 297 + xy: 197, 301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 darksand-tainted-water rotate: false - xy: 1833, 425 + xy: 1233, 199 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water-edge rotate: false - xy: 295, 395 + xy: 295, 399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 darksand-tainted-water1 rotate: false - xy: 1867, 425 + xy: 1233, 165 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water2 rotate: false - xy: 1901, 425 + xy: 1233, 131 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water3 rotate: false - xy: 1935, 425 + xy: 1299, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water rotate: false - xy: 1969, 425 + xy: 1333, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water-edge rotate: false - xy: 1, 3 + xy: 1, 7 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 darksand-water1 rotate: false - xy: 2003, 425 + xy: 1367, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water2 rotate: false - xy: 591, 99 + xy: 1401, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water3 rotate: false - xy: 591, 65 + xy: 1435, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand1 rotate: false - xy: 1731, 425 + xy: 1121, 67 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand2 rotate: false - xy: 1765, 425 + xy: 1183, 99 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand3 rotate: false - xy: 1799, 425 + xy: 2007, 297 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 deepwater rotate: false - xy: 625, 97 + xy: 1469, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 deepwater-edge rotate: false - xy: 99, 101 + xy: 99, 105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dirt-edge rotate: false - xy: 197, 199 + xy: 197, 203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dirt-wall-large rotate: false - xy: 687, 231 + xy: 985, 233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dirt-wall1 rotate: false - xy: 787, 295 + xy: 1605, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dirt-wall2 rotate: false - xy: 787, 261 + xy: 1639, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dirt1 rotate: false - xy: 625, 63 + xy: 1503, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dirt2 rotate: false - xy: 659, 97 + xy: 1537, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dirt3 rotate: false - xy: 659, 63 + xy: 1571, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dune-wall-large rotate: false - xy: 785, 329 + xy: 985, 167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dune-wall1 rotate: false - xy: 787, 227 + xy: 1673, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dune-wall2 rotate: false - xy: 821, 293 + xy: 1707, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 edge rotate: false - xy: 821, 259 + xy: 1741, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 edge-stencil rotate: false - xy: 295, 297 + xy: 295, 301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 edgier rotate: false - xy: 821, 225 + xy: 1775, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass-edge rotate: false - xy: 393, 395 + xy: 393, 399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 grass1 rotate: false - xy: 855, 293 + xy: 1809, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass2 rotate: false - xy: 855, 259 + xy: 1843, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass3 rotate: false - xy: 855, 225 + xy: 1877, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock1 rotate: false - xy: 1547, 391 + xy: 1911, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock2 rotate: false - xy: 1581, 391 + xy: 1945, 231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock3 rotate: false - xy: 1615, 391 + xy: 1217, 97 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-edge rotate: false - xy: 99, 3 + xy: 99, 7 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ice-snow-edge rotate: false - xy: 197, 101 + xy: 197, 105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ice-snow1 rotate: false - xy: 1751, 391 + xy: 2013, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-snow2 rotate: false - xy: 1785, 391 + xy: 2013, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-snow3 rotate: false - xy: 1819, 391 + xy: 1155, 65 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-wall-large rotate: false - xy: 883, 427 + xy: 1051, 233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 ice-wall1 rotate: false - xy: 1853, 391 + xy: 1189, 63 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-wall2 rotate: false - xy: 1887, 391 + xy: 1223, 63 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice1 rotate: false - xy: 1649, 391 + xy: 1251, 97 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice2 rotate: false - xy: 1683, 391 + xy: 1979, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice3 rotate: false - xy: 1717, 391 + xy: 1979, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 lead1 rotate: false - xy: 1921, 391 + xy: 1257, 63 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 lead2 rotate: false - xy: 1955, 391 + xy: 823, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 lead3 rotate: false - xy: 1989, 391 + xy: 857, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock1 rotate: false - xy: 689, 197 + xy: 891, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock2 rotate: false - xy: 689, 163 + xy: 925, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock3 rotate: false - xy: 723, 195 + xy: 1267, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor rotate: false - xy: 723, 161 + xy: 1267, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-2 rotate: false - xy: 757, 193 + xy: 1301, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-2-edge rotate: false - xy: 295, 199 + xy: 295, 203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 metal-floor-3 rotate: false - xy: 757, 159 + xy: 1301, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-3-edge rotate: false - xy: 393, 297 + xy: 393, 301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 metal-floor-5 rotate: false - xy: 791, 191 + xy: 1335, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-5-edge rotate: false - xy: 491, 395 + xy: 491, 399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 metal-floor-damaged-edge rotate: false - xy: 197, 3 + xy: 197, 7 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 metal-floor-damaged1 rotate: false - xy: 825, 191 + xy: 1335, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-damaged2 rotate: false - xy: 791, 157 + xy: 1369, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-damaged3 rotate: false - xy: 825, 157 + xy: 1369, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-edge rotate: false - xy: 295, 101 + xy: 295, 105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 moss-edge rotate: false - xy: 393, 199 + xy: 393, 203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 moss1 rotate: false - xy: 859, 191 + xy: 1403, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 moss2 rotate: false - xy: 859, 157 + xy: 1403, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 moss3 rotate: false - xy: 885, 393 + xy: 1437, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mud-edge rotate: false - xy: 491, 297 + xy: 491, 301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mud1 rotate: false - xy: 885, 359 + xy: 1437, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mud2 rotate: false - xy: 919, 393 + xy: 1471, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mud3 rotate: false - xy: 953, 393 + xy: 1471, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-coal1 rotate: false - xy: 919, 359 + xy: 1505, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-coal2 rotate: false - xy: 987, 393 + xy: 1505, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-coal3 rotate: false - xy: 953, 359 + xy: 1539, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-copper1 rotate: false - xy: 1021, 393 + xy: 1539, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-copper2 rotate: false - xy: 987, 359 + xy: 1573, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-copper3 rotate: false - xy: 1055, 393 + xy: 1573, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-lead1 rotate: false - xy: 1021, 359 + xy: 1607, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-lead2 rotate: false - xy: 1089, 393 + xy: 1607, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-lead3 rotate: false - xy: 1055, 359 + xy: 1641, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-scrap1 rotate: false - xy: 1123, 393 + xy: 1641, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-scrap2 rotate: false - xy: 1089, 359 + xy: 1675, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-scrap3 rotate: false - xy: 1157, 393 + xy: 1675, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-thorium1 rotate: false - xy: 1123, 359 + xy: 1709, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-thorium2 rotate: false - xy: 1191, 393 + xy: 1709, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-thorium3 rotate: false - xy: 1157, 359 + xy: 1743, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-titanium1 rotate: false - xy: 1225, 393 + xy: 1743, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-titanium2 rotate: false - xy: 1191, 359 + xy: 1777, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-titanium3 rotate: false - xy: 1259, 393 + xy: 1777, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pebbles1 rotate: false - xy: 1225, 359 + xy: 1811, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pebbles2 rotate: false - xy: 1293, 393 + xy: 1811, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pebbles3 rotate: false - xy: 1259, 359 + xy: 1845, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pine rotate: false - xy: 1411, 443 + xy: 1183, 183 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 salt rotate: false - xy: 1327, 393 + xy: 1845, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salt-edge rotate: false - xy: 589, 395 + xy: 589, 399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 salt-wall-large rotate: false - xy: 949, 427 + xy: 985, 101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 salt-wall1 rotate: false - xy: 1293, 359 + xy: 1879, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salt-wall2 rotate: false - xy: 1361, 393 + xy: 1879, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-edge rotate: false - xy: 295, 3 + xy: 295, 7 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 sand-wall-large rotate: false - xy: 1015, 427 + xy: 1051, 167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sand-wall1 rotate: false - xy: 1429, 375 + xy: 1319, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-wall2 rotate: false - xy: 1463, 375 + xy: 1353, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water rotate: false - xy: 1497, 375 + xy: 1387, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water-edge rotate: false - xy: 393, 101 + xy: 393, 105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 sand-water1 rotate: false - xy: 1395, 341 + xy: 1421, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water2 rotate: false - xy: 1429, 341 + xy: 1455, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water3 rotate: false - xy: 1463, 341 + xy: 1489, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand1 rotate: false - xy: 1327, 359 + xy: 1913, 197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand2 rotate: false - xy: 1361, 359 + xy: 1913, 163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand3 rotate: false - xy: 1395, 375 + xy: 1285, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap1 rotate: false - xy: 1497, 341 + xy: 1523, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap2 rotate: false - xy: 1531, 357 + xy: 1557, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap3 rotate: false - xy: 1565, 357 + xy: 1591, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-edge rotate: false - xy: 491, 199 + xy: 491, 203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 shale-wall-large rotate: false - xy: 1081, 427 + xy: 1117, 233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shale-wall1 rotate: false - xy: 1701, 357 + xy: 1727, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-wall2 rotate: false - xy: 1735, 357 + xy: 1761, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale1 rotate: false - xy: 1599, 357 + xy: 1625, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale2 rotate: false - xy: 1633, 357 + xy: 1659, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale3 rotate: false - xy: 1667, 357 + xy: 1693, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs-large rotate: false - xy: 1147, 427 + xy: 1051, 101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shrubs1 rotate: false - xy: 1769, 357 + xy: 1795, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs2 rotate: false - xy: 1803, 357 + xy: 1829, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 slag rotate: false - xy: 1837, 357 + xy: 1863, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 slag-edge rotate: false - xy: 589, 297 + xy: 589, 301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 snow-edge rotate: false - xy: 687, 395 + xy: 687, 399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 snow-pine rotate: false - xy: 1461, 443 + xy: 1249, 249 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snow-wall-large rotate: false - xy: 1213, 427 + xy: 1117, 167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 snow-wall1 rotate: false - xy: 1973, 357 + xy: 1325, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow-wall2 rotate: false - xy: 1531, 323 + xy: 1359, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow1 rotate: false - xy: 1871, 357 + xy: 1897, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow2 rotate: false - xy: 1905, 357 + xy: 1931, 129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow3 rotate: false - xy: 1939, 357 + xy: 1291, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +space + rotate: false + xy: 1393, 95 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +space-edge + rotate: false + xy: 393, 7 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 spawn rotate: false - xy: 1565, 323 + xy: 1427, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss-edge rotate: false - xy: 393, 3 + xy: 491, 105 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 spore-moss1 rotate: false - xy: 1599, 323 + xy: 1461, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss2 rotate: false - xy: 1633, 323 + xy: 1495, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss3 rotate: false - xy: 1667, 323 + xy: 1529, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-pine rotate: false - xy: 1511, 443 + xy: 1183, 133 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-wall-large rotate: false - xy: 1279, 427 + xy: 1183, 233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-wall1 rotate: false - xy: 1701, 323 + xy: 1563, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-wall2 rotate: false - xy: 1735, 323 + xy: 1597, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone-edge rotate: false - xy: 491, 101 + xy: 589, 203 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 stone-wall-large rotate: false - xy: 1345, 427 + xy: 1117, 101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 stone-wall1 rotate: false - xy: 1871, 323 + xy: 1733, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone-wall2 rotate: false - xy: 1905, 323 + xy: 1767, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone1 rotate: false - xy: 1769, 323 + xy: 1631, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone2 rotate: false - xy: 1803, 323 + xy: 1665, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone3 rotate: false - xy: 1837, 323 + xy: 1699, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tainted-water rotate: false - xy: 1939, 323 + xy: 1801, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tainted-water-edge rotate: false - xy: 589, 199 + xy: 687, 301 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 tar rotate: false - xy: 1973, 323 + xy: 1835, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tar-edge rotate: false - xy: 687, 297 + xy: 785, 399 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 tendrils1 rotate: false - xy: 2007, 357 + xy: 1869, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tendrils2 rotate: false - xy: 2007, 323 + xy: 1903, 95 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tendrils3 rotate: false - xy: 889, 325 + xy: 1291, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium1 rotate: false - xy: 923, 325 + xy: 1325, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium2 rotate: false - xy: 889, 291 + xy: 1359, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium3 rotate: false - xy: 957, 325 + xy: 1393, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium1 rotate: false - xy: 889, 257 + xy: 1427, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium2 rotate: false - xy: 923, 291 + xy: 1461, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium3 rotate: false - xy: 991, 325 + xy: 1495, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water rotate: false - xy: 923, 257 + xy: 1529, 61 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water-edge rotate: false - xy: 785, 395 + xy: 491, 7 size: 96, 96 orig: 96, 96 offset: 0, 0 @@ -10505,128 +12367,142 @@ editor-snow3 orig: 32, 32 offset: 0, 0 index: -1 -editor-spawn +editor-space rotate: false xy: 559, 269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +space-icon-editor + rotate: false + xy: 559, 269 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +editor-spawn + rotate: false + xy: 593, 303 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 editor-spore-moss1 - rotate: false - xy: 593, 303 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -spore-moss-icon-editor - rotate: false - xy: 593, 303 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -editor-spore-moss2 rotate: false xy: 593, 269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -editor-spore-moss3 +spore-moss-icon-editor + rotate: false + xy: 593, 269 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +editor-spore-moss2 rotate: false xy: 627, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +editor-spore-moss3 + rotate: false + xy: 627, 367 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 editor-stone1 - rotate: false - xy: 627, 367 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -stone-icon-editor - rotate: false - xy: 627, 367 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -editor-stone2 rotate: false xy: 661, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -editor-stone3 +stone-icon-editor + rotate: false + xy: 661, 401 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +editor-stone2 rotate: false xy: 627, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -editor-tainted-water +editor-stone3 rotate: false xy: 661, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +editor-tainted-water + rotate: false + xy: 695, 401 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 tainted-water-icon-editor rotate: false - xy: 661, 367 + xy: 695, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tar rotate: false - xy: 695, 401 + xy: 627, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tar-icon-editor rotate: false - xy: 695, 401 + xy: 627, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils1 rotate: false - xy: 627, 299 + xy: 661, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils2 rotate: false - xy: 661, 333 + xy: 695, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils3 rotate: false - xy: 695, 367 + xy: 729, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-water rotate: false - xy: 729, 401 + xy: 661, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water-icon-editor rotate: false - xy: 729, 401 + xy: 661, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10675,7 +12551,7 @@ ground-factory-icon-editor index: -1 hail-icon-editor rotate: false - xy: 661, 299 + xy: 695, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10689,14 +12565,14 @@ hyper-processor-icon-editor index: -1 ice-wall-icon-editor rotate: false - xy: 695, 333 + xy: 729, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 illuminator-icon-editor rotate: false - xy: 729, 367 + xy: 763, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10710,35 +12586,35 @@ impact-reactor-icon-editor index: -1 incinerator-icon-editor rotate: false - xy: 763, 401 + xy: 695, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 inverted-sorter-icon-editor rotate: false - xy: 695, 299 + xy: 729, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source-icon-editor rotate: false - xy: 729, 333 + xy: 763, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void-icon-editor rotate: false - xy: 763, 367 + xy: 797, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 junction-icon-editor rotate: false - xy: 797, 401 + xy: 729, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10787,21 +12663,21 @@ launch-pad-large-icon-editor index: -1 liquid-junction-icon-editor rotate: false - xy: 729, 299 + xy: 763, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-icon-editor rotate: false - xy: 763, 333 + xy: 797, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-source-icon-editor rotate: false - xy: 797, 367 + xy: 831, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10815,7 +12691,7 @@ liquid-tank-icon-editor index: -1 liquid-void-icon-editor rotate: false - xy: 831, 401 + xy: 763, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10850,7 +12726,7 @@ mechanical-drill-icon-editor index: -1 mechanical-pump-icon-editor rotate: false - xy: 763, 299 + xy: 797, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10864,7 +12740,7 @@ meltdown-icon-editor index: -1 melter-icon-editor rotate: false - xy: 797, 333 + xy: 831, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10878,7 +12754,7 @@ memory-bank-icon-editor index: -1 memory-cell-icon-editor rotate: false - xy: 831, 367 + xy: 865, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10892,21 +12768,21 @@ mend-projector-icon-editor index: -1 mender-icon-editor rotate: false - xy: 865, 401 + xy: 797, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 message-icon-editor rotate: false - xy: 797, 299 + xy: 831, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 micro-processor-icon-editor rotate: false - xy: 831, 333 + xy: 865, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10955,7 +12831,7 @@ overdrive-projector-icon-editor index: -1 overflow-gate-icon-editor rotate: false - xy: 865, 367 + xy: 831, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10983,28 +12859,28 @@ payload-router-icon-editor index: -1 pebbles-icon-editor rotate: false - xy: 831, 299 + xy: 865, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-icon-editor rotate: false - xy: 865, 333 + xy: 865, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-icon-editor rotate: false - xy: 865, 299 + xy: 627, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-icon-editor rotate: false - xy: 627, 265 + xy: 661, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11039,14 +12915,14 @@ plastanium-compressor-icon-editor index: -1 plastanium-conveyor-icon-editor rotate: false - xy: 661, 265 + xy: 695, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-wall-icon-editor rotate: false - xy: 695, 265 + xy: 729, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11060,7 +12936,7 @@ plastanium-wall-large-icon-editor index: -1 plated-conduit-icon-editor rotate: false - xy: 729, 265 + xy: 763, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11074,7 +12950,7 @@ pneumatic-drill-icon-editor index: -1 power-node-icon-editor rotate: false - xy: 763, 265 + xy: 797, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11088,28 +12964,28 @@ power-node-large-icon-editor index: -1 power-source-icon-editor rotate: false - xy: 797, 265 + xy: 831, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void-icon-editor rotate: false - xy: 831, 265 + xy: 865, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-icon-editor rotate: false - xy: 865, 265 + xy: 899, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-icon-editor rotate: false - xy: 899, 401 + xy: 899, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11123,7 +12999,7 @@ pyratite-mixer-icon-editor index: -1 repair-point-icon-editor rotate: false - xy: 899, 367 + xy: 899, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11151,7 +13027,7 @@ rotary-pump-icon-editor index: -1 router-icon-editor rotate: false - xy: 899, 333 + xy: 899, 299 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11165,7 +13041,7 @@ rtg-generator-icon-editor index: -1 salt-wall-icon-editor rotate: false - xy: 899, 299 + xy: 899, 265 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11179,21 +13055,21 @@ salvo-icon-editor index: -1 sand-boulder-icon-editor rotate: false - xy: 899, 265 + xy: 459, 235 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-wall-icon-editor rotate: false - xy: 459, 235 + xy: 459, 201 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water-icon-editor rotate: false - xy: 459, 201 + xy: 493, 235 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11207,7 +13083,7 @@ scatter-icon-editor index: -1 scorch-icon-editor rotate: false - xy: 493, 235 + xy: 459, 167 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11228,7 +13104,7 @@ scrap-wall-huge-icon-editor index: -1 scrap-wall-icon-editor rotate: false - xy: 459, 167 + xy: 493, 201 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11256,28 +13132,28 @@ separator-icon-editor index: -1 shale-boulder-icon-editor rotate: false - xy: 493, 201 + xy: 527, 235 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-wall-icon-editor rotate: false - xy: 527, 235 + xy: 493, 167 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shock-mine-icon-editor rotate: false - xy: 493, 167 + xy: 527, 201 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs-icon-editor rotate: false - xy: 527, 201 + xy: 561, 235 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11305,7 +13181,7 @@ snow-boulder-icon-editor index: -1 snow-icon-editor rotate: false - xy: 561, 235 + xy: 527, 167 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11319,14 +13195,14 @@ snow-pine-icon-editor index: -1 snow-wall-icon-editor rotate: false - xy: 527, 167 + xy: 561, 201 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-icon-editor rotate: false - xy: 561, 201 + xy: 561, 167 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11340,14 +13216,14 @@ solar-panel-large-icon-editor index: -1 sorter-icon-editor rotate: false - xy: 561, 167 + xy: 463, 133 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spawn-icon-editor rotate: false - xy: 463, 133 + xy: 463, 99 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11382,7 +13258,7 @@ spore-press-icon-editor index: -1 spore-wall-icon-editor rotate: false - xy: 463, 99 + xy: 497, 133 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11396,7 +13272,7 @@ steam-generator-icon-editor index: -1 stone-wall-icon-editor rotate: false - xy: 497, 133 + xy: 497, 99 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11410,7 +13286,7 @@ surge-tower-icon-editor index: -1 surge-wall-icon-editor rotate: false - xy: 497, 99 + xy: 531, 133 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11431,14 +13307,14 @@ swarmer-icon-editor index: -1 switch-icon-editor rotate: false - xy: 531, 133 + xy: 531, 99 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tendrils-icon-editor rotate: false - xy: 531, 99 + xy: 565, 133 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11473,7 +13349,7 @@ thorium-reactor-icon-editor index: -1 thorium-wall-icon-editor rotate: false - xy: 565, 133 + xy: 565, 99 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11494,14 +13370,14 @@ thruster-icon-editor index: -1 titanium-conveyor-icon-editor rotate: false - xy: 565, 99 + xy: 469, 65 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-icon-editor rotate: false - xy: 469, 65 + xy: 469, 31 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11522,14 +13398,14 @@ tsunami-icon-editor index: -1 underflow-gate-icon-editor rotate: false - xy: 469, 31 + xy: 503, 65 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unloader-icon-editor rotate: false - xy: 503, 65 + xy: 503, 31 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11584,7 +13460,7 @@ alpha-bg index: -1 bar rotate: false - xy: 1048, 560 + xy: 950, 175 size: 27, 36 split: 9, 9, 9, 9 orig: 27, 36 @@ -11592,7 +13468,7 @@ bar index: -1 bar-top rotate: false - xy: 1455, 483 + xy: 950, 213 size: 27, 36 split: 9, 10, 9, 10 orig: 27, 36 @@ -11607,21 +13483,21 @@ block-additive-reconstructor-large index: -1 block-additive-reconstructor-medium rotate: false - xy: 1627, 618 + xy: 1571, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-additive-reconstructor-small rotate: false - xy: 1013, 359 + xy: 2023, 789 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-additive-reconstructor-tiny rotate: false - xy: 327, 1 + xy: 1549, 553 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11642,21 +13518,21 @@ block-air-factory-large index: -1 block-air-factory-medium rotate: false - xy: 1665, 647 + xy: 1605, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-air-factory-small rotate: false - xy: 2023, 881 + xy: 1489, 399 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-air-factory-tiny rotate: false - xy: 881, 1 + xy: 1009, 47 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11670,28 +13546,28 @@ block-air-factory-xlarge index: -1 block-alloy-smelter-large rotate: false - xy: 651, 274 + xy: 651, 283 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-alloy-smelter-medium rotate: false - xy: 1699, 647 + xy: 1639, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-alloy-smelter-small rotate: false - xy: 2023, 855 + xy: 950, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-alloy-smelter-tiny rotate: false - xy: 899, 1 + xy: 301, 1 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11705,28 +13581,28 @@ block-alloy-smelter-xlarge index: -1 block-arc-large rotate: false - xy: 551, 141 + xy: 596, 191 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-arc-medium rotate: false - xy: 2014, 907 + xy: 1825, 689 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-arc-small rotate: false - xy: 2023, 829 + xy: 979, 204 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-arc-tiny rotate: false - xy: 917, 1 + xy: 319, 1 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11740,28 +13616,28 @@ block-arc-xlarge index: -1 block-armored-conveyor-large rotate: false - xy: 451, 74 + xy: 646, 241 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-armored-conveyor-medium rotate: false - xy: 1909, 689 + xy: 881, 571 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-armored-conveyor-small rotate: false - xy: 2023, 803 + xy: 979, 178 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-armored-conveyor-tiny rotate: false - xy: 935, 1 + xy: 337, 1 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11775,28 +13651,28 @@ block-armored-conveyor-xlarge index: -1 block-basalt-large rotate: false - xy: 646, 232 + xy: 701, 324 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-basalt-medium rotate: false - xy: 1989, 857 + xy: 915, 571 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-basalt-small rotate: false - xy: 781, 690 + xy: 979, 152 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-basalt-tiny rotate: false - xy: 953, 1 + xy: 1403, 333 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11810,35 +13686,35 @@ block-basalt-xlarge index: -1 block-battery-large rotate: false - xy: 401, 34 + xy: 501, 74 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-battery-large-large rotate: false - xy: 443, 32 + xy: 693, 282 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-battery-large-medium rotate: false - xy: 1661, 613 + xy: 877, 537 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-battery-large-small rotate: false - xy: 1251, 427 + xy: 1455, 367 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-battery-large-tiny rotate: false - xy: 971, 1 + xy: 331, 598 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11852,21 +13728,21 @@ block-battery-large-xlarge index: -1 block-battery-medium rotate: false - xy: 1695, 613 + xy: 911, 537 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-battery-small rotate: false - xy: 1420, 461 + xy: 1421, 346 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-battery-tiny rotate: false - xy: 989, 1 + xy: 309, 672 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11880,28 +13756,28 @@ block-battery-xlarge index: -1 block-blast-drill-large rotate: false - xy: 501, 100 + xy: 688, 240 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-blast-drill-medium rotate: false - xy: 351, 6 + xy: 877, 503 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-blast-drill-small rotate: false - xy: 1277, 427 + xy: 485, 6 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-blast-drill-tiny rotate: false - xy: 1007, 1 + xy: 331, 580 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11915,28 +13791,28 @@ block-blast-drill-xlarge index: -1 block-blast-mixer-large rotate: false - xy: 543, 99 + xy: 451, 35 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-blast-mixer-medium rotate: false - xy: 881, 563 + xy: 911, 503 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-blast-mixer-small rotate: false - xy: 1303, 427 + xy: 1013, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-blast-mixer-tiny rotate: false - xy: 1025, 1 + xy: 1681, 345 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11950,28 +13826,28 @@ block-blast-mixer-xlarge index: -1 block-block-forge-large rotate: false - xy: 593, 133 + xy: 493, 32 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-block-forge-medium rotate: false - xy: 915, 563 + xy: 877, 469 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-block-forge-small rotate: false - xy: 1329, 427 + xy: 1039, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-block-forge-tiny rotate: false - xy: 1043, 1 + xy: 355, 6 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11985,28 +13861,28 @@ block-block-forge-xlarge index: -1 block-block-loader-large rotate: false - xy: 585, 91 + xy: 401, 8 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-block-loader-medium rotate: false - xy: 877, 529 + xy: 911, 469 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-block-loader-small rotate: false - xy: 1484, 489 + xy: 1065, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-block-loader-tiny rotate: false - xy: 1061, 1 + xy: 373, 6 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12020,28 +13896,28 @@ block-block-loader-xlarge index: -1 block-block-unloader-large rotate: false - xy: 493, 58 + xy: 551, 91 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-block-unloader-medium rotate: false - xy: 877, 495 + xy: 877, 435 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-block-unloader-small rotate: false - xy: 1510, 489 + xy: 1091, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-block-unloader-tiny rotate: false - xy: 1079, 1 + xy: 1421, 328 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12055,28 +13931,28 @@ block-block-unloader-xlarge index: -1 block-boulder-large rotate: false - xy: 535, 57 + xy: 751, 536 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-boulder-medium rotate: false - xy: 911, 529 + xy: 911, 435 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-boulder-small rotate: false - xy: 1355, 433 + xy: 1117, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-boulder-tiny rotate: false - xy: 1097, 1 + xy: 1403, 315 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12090,28 +13966,28 @@ block-boulder-xlarge index: -1 block-bridge-conduit-large rotate: false - xy: 577, 49 + xy: 751, 494 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-bridge-conduit-medium rotate: false - xy: 877, 461 + xy: 877, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-bridge-conduit-small rotate: false - xy: 1115, 393 + xy: 1143, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-bridge-conduit-tiny rotate: false - xy: 331, 598 + xy: 1421, 310 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12125,28 +14001,28 @@ block-bridge-conduit-xlarge index: -1 block-bridge-conveyor-large rotate: false - xy: 485, 16 + xy: 793, 536 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-bridge-conveyor-medium rotate: false - xy: 911, 495 + xy: 911, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-bridge-conveyor-small rotate: false - xy: 1081, 375 + xy: 1169, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-bridge-conveyor-tiny rotate: false - xy: 1096, 193 + xy: 1371, 307 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12160,28 +14036,28 @@ block-bridge-conveyor-xlarge index: -1 block-char-large rotate: false - xy: 527, 15 + xy: 751, 452 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-char-medium rotate: false - xy: 877, 427 + xy: 1673, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-char-small rotate: false - xy: 1076, 349 + xy: 1195, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-char-tiny rotate: false - xy: 464, 14 + xy: 1373, 289 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12195,28 +14071,28 @@ block-char-xlarge index: -1 block-cliff-large rotate: false - xy: 569, 7 + xy: 793, 494 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cliff-medium rotate: false - xy: 911, 461 + xy: 1707, 649 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cliff-small rotate: false - xy: 1446, 457 + xy: 1221, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cliff-tiny rotate: false - xy: 309, 672 + xy: 1373, 271 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12230,28 +14106,28 @@ block-cliff-xlarge index: -1 block-coal-centrifuge-large rotate: false - xy: 751, 536 + xy: 835, 536 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-coal-centrifuge-medium rotate: false - xy: 877, 393 + xy: 1741, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-coal-centrifuge-small rotate: false - xy: 1472, 457 + xy: 1007, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-coal-centrifuge-tiny rotate: false - xy: 1534, 221 + xy: 1373, 253 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12265,28 +14141,28 @@ block-coal-centrifuge-xlarge index: -1 block-combustion-generator-large rotate: false - xy: 751, 494 + xy: 751, 410 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-combustion-generator-medium rotate: false - xy: 911, 427 + xy: 1909, 731 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-combustion-generator-small rotate: false - xy: 1498, 463 + xy: 1033, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-combustion-generator-tiny rotate: false - xy: 1552, 221 + xy: 1373, 235 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12300,28 +14176,28 @@ block-combustion-generator-xlarge index: -1 block-command-center-large rotate: false - xy: 793, 536 + xy: 793, 452 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-command-center-medium rotate: false - xy: 911, 393 + xy: 1867, 709 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-command-center-small rotate: false - xy: 1524, 463 + xy: 1059, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-command-center-tiny rotate: false - xy: 331, 580 + xy: 1439, 323 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12335,28 +14211,28 @@ block-command-center-xlarge index: -1 block-conduit-large rotate: false - xy: 751, 452 + xy: 835, 494 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-conduit-medium rotate: false - xy: 877, 359 + xy: 1499, 597 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-conduit-small rotate: false - xy: 1107, 367 + xy: 1085, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-conduit-tiny rotate: false - xy: 1510, 195 + xy: 1457, 323 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12370,28 +14246,28 @@ block-conduit-xlarge index: -1 block-container-large rotate: false - xy: 793, 494 + xy: 751, 368 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-container-medium rotate: false - xy: 911, 359 + xy: 1951, 749 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-container-small rotate: false - xy: 1102, 341 + xy: 1111, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-container-tiny rotate: false - xy: 1563, 495 + xy: 1475, 323 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12405,28 +14281,28 @@ block-container-xlarge index: -1 block-conveyor-large rotate: false - xy: 835, 536 + xy: 793, 410 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-conveyor-medium rotate: false - xy: 872, 325 + xy: 1007, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-conveyor-small rotate: false - xy: 1102, 315 + xy: 1137, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-conveyor-tiny rotate: false - xy: 1570, 216 + xy: 1493, 323 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12440,35 +14316,35 @@ block-conveyor-xlarge index: -1 block-copper-wall-large rotate: false - xy: 751, 410 + xy: 835, 452 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-copper-wall-large-large rotate: false - xy: 793, 452 + xy: 793, 368 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-copper-wall-large-medium rotate: false - xy: 906, 325 + xy: 1041, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-copper-wall-large-small rotate: false - xy: 1102, 289 + xy: 1163, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-copper-wall-large-tiny rotate: false - xy: 1534, 203 + xy: 1439, 305 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12482,21 +14358,21 @@ block-copper-wall-large-xlarge index: -1 block-copper-wall-medium rotate: false - xy: 869, 291 + xy: 1075, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-copper-wall-small rotate: false - xy: 1102, 263 + xy: 1189, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-copper-wall-tiny rotate: false - xy: 1552, 203 + xy: 1457, 305 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12510,28 +14386,28 @@ block-copper-wall-xlarge index: -1 block-core-foundation-large rotate: false - xy: 835, 494 + xy: 835, 410 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-core-foundation-medium rotate: false - xy: 903, 291 + xy: 1109, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-core-foundation-small rotate: false - xy: 1096, 237 + xy: 1215, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-core-foundation-tiny rotate: false - xy: 1570, 198 + xy: 1475, 305 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12545,28 +14421,28 @@ block-core-foundation-xlarge index: -1 block-core-nucleus-large rotate: false - xy: 793, 410 + xy: 835, 368 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-core-nucleus-medium rotate: false - xy: 1133, 589 + xy: 1143, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-core-nucleus-small rotate: false - xy: 1096, 211 + xy: 1009, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-core-nucleus-tiny rotate: false - xy: 1588, 216 + xy: 1493, 305 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12580,28 +14456,28 @@ block-core-nucleus-xlarge index: -1 block-core-shard-large rotate: false - xy: 835, 452 + xy: 646, 199 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-core-shard-medium rotate: false - xy: 1167, 589 + xy: 1177, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-core-shard-small rotate: false - xy: 1141, 393 + xy: 1009, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-core-shard-tiny rotate: false - xy: 1588, 198 + xy: 2029, 661 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12615,28 +14491,28 @@ block-core-shard-xlarge index: -1 block-craters-large rotate: false - xy: 835, 410 + xy: 688, 198 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-craters-medium rotate: false - xy: 1201, 589 + xy: 1211, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-craters-small rotate: false - xy: 1133, 367 + xy: 1035, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-craters-tiny rotate: false - xy: 1510, 177 + xy: 1365, 47 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12650,28 +14526,28 @@ block-craters-xlarge index: -1 block-cryofluid-mixer-large rotate: false - xy: 751, 368 + xy: 543, 49 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cryofluid-mixer-medium rotate: false - xy: 1235, 589 + xy: 1245, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cryofluid-mixer-small rotate: false - xy: 1128, 341 + xy: 1035, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cryofluid-mixer-tiny rotate: false - xy: 1528, 185 + xy: 1365, 29 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12685,28 +14561,28 @@ block-cryofluid-mixer-xlarge index: -1 block-cultivator-large rotate: false - xy: 793, 368 + xy: 535, 7 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cultivator-medium rotate: false - xy: 1269, 589 + xy: 1279, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cultivator-small rotate: false - xy: 1128, 315 + xy: 1061, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cultivator-tiny rotate: false - xy: 1546, 185 + xy: 1365, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12720,28 +14596,28 @@ block-cultivator-xlarge index: -1 block-cyclone-large rotate: false - xy: 835, 368 + xy: 596, 149 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cyclone-medium rotate: false - xy: 1303, 589 + xy: 1313, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cyclone-small rotate: false - xy: 1128, 289 + xy: 1061, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cyclone-tiny rotate: false - xy: 1528, 167 + xy: 2030, 883 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12755,28 +14631,28 @@ block-cyclone-xlarge index: -1 block-dacite-boulder-large rotate: false - xy: 746, 326 + xy: 638, 157 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dacite-boulder-medium rotate: false - xy: 1337, 589 + xy: 1347, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dacite-boulder-small rotate: false - xy: 1128, 263 + xy: 1087, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dacite-boulder-tiny rotate: false - xy: 1546, 167 + xy: 2030, 865 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12790,56 +14666,56 @@ block-dacite-boulder-xlarge index: -1 block-dacite-large rotate: false - xy: 788, 326 + xy: 680, 156 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dacite-medium rotate: false - xy: 1371, 589 + xy: 1381, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dacite-small rotate: false - xy: 1122, 237 + xy: 1087, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dacite-tiny rotate: false - xy: 1564, 180 + xy: 1373, 217 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-dacite-wall-large rotate: false - xy: 830, 326 + xy: 594, 107 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dacite-wall-medium rotate: false - xy: 1405, 589 + xy: 1415, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dacite-wall-small rotate: false - xy: 1122, 211 + xy: 1113, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dacite-wall-tiny rotate: false - xy: 1582, 180 + xy: 1697, 397 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12860,28 +14736,28 @@ block-dacite-xlarge index: -1 block-dark-metal-large rotate: false - xy: 701, 284 + xy: 593, 65 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-metal-medium rotate: false - xy: 1439, 589 + xy: 949, 571 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-metal-small rotate: false - xy: 1167, 395 + xy: 1113, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-metal-tiny rotate: false - xy: 1564, 162 + xy: 1697, 379 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12895,28 +14771,28 @@ block-dark-metal-xlarge index: -1 block-dark-panel-1-large rotate: false - xy: 743, 284 + xy: 638, 115 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-1-medium rotate: false - xy: 1473, 589 + xy: 945, 537 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-1-small rotate: false - xy: 1193, 398 + xy: 1139, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-1-tiny rotate: false - xy: 1582, 162 + xy: 1347, 209 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12930,28 +14806,28 @@ block-dark-panel-1-xlarge index: -1 block-dark-panel-2-large rotate: false - xy: 785, 284 + xy: 680, 114 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-2-medium rotate: false - xy: 1507, 589 + xy: 945, 503 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-2-small rotate: false - xy: 1219, 399 + xy: 1139, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-2-tiny rotate: false - xy: 1600, 180 + xy: 1343, 191 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12965,28 +14841,28 @@ block-dark-panel-2-xlarge index: -1 block-dark-panel-3-large rotate: false - xy: 827, 284 + xy: 743, 324 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-3-medium rotate: false - xy: 1541, 589 + xy: 945, 469 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-3-small rotate: false - xy: 1159, 367 + xy: 1165, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-3-tiny rotate: false - xy: 1600, 162 + xy: 1343, 173 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13000,28 +14876,28 @@ block-dark-panel-3-xlarge index: -1 block-dark-panel-4-large rotate: false - xy: 635, 133 + xy: 735, 282 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-4-medium rotate: false - xy: 1575, 589 + xy: 945, 435 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-4-small rotate: false - xy: 1154, 341 + xy: 1165, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-4-tiny rotate: false - xy: 1330, 205 + xy: 1343, 155 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13035,28 +14911,28 @@ block-dark-panel-4-xlarge index: -1 block-dark-panel-5-large rotate: false - xy: 627, 91 + xy: 730, 240 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-5-medium rotate: false - xy: 1943, 681 + xy: 945, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-5-small rotate: false - xy: 1154, 315 + xy: 1191, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-5-tiny rotate: false - xy: 1348, 205 + xy: 1343, 137 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13070,28 +14946,28 @@ block-dark-panel-5-xlarge index: -1 block-dark-panel-6-large rotate: false - xy: 619, 49 + xy: 730, 198 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-6-medium rotate: false - xy: 949, 563 + xy: 1901, 697 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-6-small rotate: false - xy: 1154, 289 + xy: 1191, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-6-tiny rotate: false - xy: 1408, 210 + xy: 1343, 119 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13105,49 +14981,49 @@ block-dark-panel-6-xlarge index: -1 block-darksand-large rotate: false - xy: 611, 7 + xy: 722, 156 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-darksand-medium rotate: false - xy: 945, 529 + xy: 1859, 675 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-small rotate: false - xy: 1154, 263 + xy: 1217, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-darksand-tainted-water-large rotate: false - xy: 669, 91 + xy: 722, 114 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-darksand-tainted-water-medium rotate: false - xy: 945, 495 + xy: 1893, 663 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-tainted-water-small rotate: false - xy: 1148, 237 + xy: 1217, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-darksand-tainted-water-tiny rotate: false - xy: 1426, 205 + xy: 1655, 324 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13161,35 +15037,35 @@ block-darksand-tainted-water-xlarge index: -1 block-darksand-tiny rotate: false - xy: 1536, 495 + xy: 1652, 306 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-darksand-water-large rotate: false - xy: 661, 49 + xy: 785, 326 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-darksand-water-medium rotate: false - xy: 945, 461 + xy: 1943, 715 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-water-small rotate: false - xy: 1148, 211 + xy: 1009, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-darksand-water-tiny rotate: false - xy: 1550, 477 + xy: 1673, 324 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13210,28 +15086,28 @@ block-darksand-xlarge index: -1 block-deepwater-large rotate: false - xy: 653, 7 + xy: 827, 326 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-deepwater-medium rotate: false - xy: 945, 427 + xy: 1935, 681 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-deepwater-small rotate: false - xy: 1581, 524 + xy: 1035, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-deepwater-tiny rotate: false - xy: 1568, 477 + xy: 1670, 306 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13245,28 +15121,28 @@ block-deepwater-xlarge index: -1 block-differential-generator-large rotate: false - xy: 703, 49 + xy: 577, 7 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-differential-generator-medium rotate: false - xy: 945, 393 + xy: 1927, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-differential-generator-small rotate: false - xy: 1607, 524 + xy: 1061, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-differential-generator-tiny rotate: false - xy: 1586, 480 + xy: 1691, 327 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13280,28 +15156,28 @@ block-differential-generator-xlarge index: -1 block-diode-large rotate: false - xy: 695, 7 + xy: 777, 282 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-diode-medium rotate: false - xy: 945, 359 + xy: 1741, 624 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-diode-small rotate: false - xy: 1633, 519 + xy: 1087, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-diode-tiny rotate: false - xy: 1604, 480 + xy: 1511, 319 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13315,56 +15191,56 @@ block-diode-xlarge index: -1 block-dirt-large rotate: false - xy: 737, 7 + xy: 772, 240 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dirt-medium rotate: false - xy: 940, 325 + xy: 1707, 615 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dirt-small rotate: false - xy: 1659, 519 + xy: 1113, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dirt-tiny rotate: false - xy: 1563, 459 + xy: 1529, 319 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-dirt-wall-large rotate: false - xy: 646, 190 + xy: 772, 198 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dirt-wall-medium rotate: false - xy: 937, 291 + xy: 1741, 590 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dirt-wall-small rotate: false - xy: 1685, 519 + xy: 1139, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dirt-wall-tiny rotate: false - xy: 1563, 441 + xy: 1547, 319 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13385,28 +15261,28 @@ block-dirt-xlarge index: -1 block-disassembler-large rotate: false - xy: 821, 933 + xy: 764, 156 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-disassembler-medium rotate: false - xy: 1609, 584 + xy: 1993, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-disassembler-small rotate: false - xy: 1711, 519 + xy: 1165, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-disassembler-tiny rotate: false - xy: 1563, 423 + xy: 1511, 301 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13420,28 +15296,28 @@ block-disassembler-xlarge index: -1 block-distributor-large rotate: false - xy: 863, 933 + xy: 764, 114 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-distributor-medium rotate: false - xy: 1643, 579 + xy: 1989, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-distributor-small rotate: false - xy: 1737, 519 + xy: 1191, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-distributor-tiny rotate: false - xy: 1563, 405 + xy: 1529, 301 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13455,35 +15331,35 @@ block-distributor-xlarge index: -1 block-door-large rotate: false - xy: 905, 933 + xy: 819, 284 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-door-large-large rotate: false - xy: 947, 933 + xy: 869, 326 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-door-large-medium rotate: false - xy: 1677, 579 + xy: 1985, 747 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-door-large-small rotate: false - xy: 1763, 519 + xy: 1217, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-door-large-tiny rotate: false - xy: 1563, 387 + xy: 1547, 301 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13497,21 +15373,21 @@ block-door-large-xlarge index: -1 block-door-medium rotate: false - xy: 1711, 579 + xy: 1977, 713 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-door-small rotate: false - xy: 1789, 519 + xy: 1005, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-door-tiny rotate: false - xy: 1581, 459 + xy: 1565, 307 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13525,28 +15401,28 @@ block-door-xlarge index: -1 block-dune-wall-large rotate: false - xy: 989, 933 + xy: 861, 284 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dune-wall-medium rotate: false - xy: 1729, 613 + xy: 1969, 679 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dune-wall-small rotate: false - xy: 1815, 519 + xy: 1005, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dune-wall-tiny rotate: false - xy: 1581, 441 + xy: 1583, 307 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13560,28 +15436,28 @@ block-dune-wall-xlarge index: -1 block-duo-large rotate: false - xy: 1031, 933 + xy: 806, 156 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-duo-medium rotate: false - xy: 1733, 647 + xy: 1961, 645 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-duo-small rotate: false - xy: 1841, 519 + xy: 1031, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-duo-tiny rotate: false - xy: 1581, 423 + xy: 1601, 298 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13595,28 +15471,28 @@ block-duo-xlarge index: -1 block-exponential-reconstructor-large rotate: false - xy: 1073, 933 + xy: 806, 114 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-exponential-reconstructor-medium rotate: false - xy: 1745, 579 + xy: 1775, 658 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-exponential-reconstructor-small rotate: false - xy: 1867, 519 + xy: 1031, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-exponential-reconstructor-tiny rotate: false - xy: 1581, 405 + xy: 1565, 289 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13630,28 +15506,28 @@ block-exponential-reconstructor-xlarge index: -1 block-force-projector-large rotate: false - xy: 1115, 933 + xy: 903, 284 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-force-projector-medium rotate: false - xy: 1763, 613 + xy: 1775, 624 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-force-projector-small rotate: false - xy: 1893, 519 + xy: 1057, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-force-projector-tiny rotate: false - xy: 1581, 387 + xy: 1583, 289 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13665,28 +15541,28 @@ block-force-projector-xlarge index: -1 block-foreshadow-large rotate: false - xy: 1157, 933 + xy: 821, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-foreshadow-medium rotate: false - xy: 1767, 647 + xy: 1775, 590 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-foreshadow-small rotate: false - xy: 1919, 519 + xy: 1057, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-foreshadow-tiny rotate: false - xy: 1575, 369 + xy: 1601, 280 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13700,28 +15576,28 @@ block-foreshadow-xlarge index: -1 block-fuse-large rotate: false - xy: 1199, 933 + xy: 863, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-fuse-medium rotate: false - xy: 1779, 579 + xy: 1809, 655 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-fuse-small rotate: false - xy: 1945, 519 + xy: 1083, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-fuse-tiny rotate: false - xy: 1575, 351 + xy: 1619, 293 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13735,28 +15611,28 @@ block-fuse-xlarge index: -1 block-graphite-press-large rotate: false - xy: 1241, 933 + xy: 905, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-graphite-press-medium rotate: false - xy: 1797, 613 + xy: 1809, 621 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-graphite-press-small rotate: false - xy: 1971, 519 + xy: 1083, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-graphite-press-tiny rotate: false - xy: 1575, 333 + xy: 1619, 275 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13770,28 +15646,28 @@ block-graphite-press-xlarge index: -1 block-grass-large rotate: false - xy: 1283, 933 + xy: 947, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-grass-medium rotate: false - xy: 1801, 647 + xy: 1809, 587 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-grass-small rotate: false - xy: 1997, 519 + xy: 1109, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-grass-tiny rotate: false - xy: 1575, 315 + xy: 1361, 191 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13805,28 +15681,28 @@ block-grass-xlarge index: -1 block-ground-factory-large rotate: false - xy: 1325, 933 + xy: 989, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ground-factory-medium rotate: false - xy: 1813, 579 + xy: 1843, 641 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ground-factory-small rotate: false - xy: 2023, 519 + xy: 1109, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ground-factory-tiny rotate: false - xy: 1599, 462 + xy: 1361, 173 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13840,28 +15716,28 @@ block-ground-factory-xlarge index: -1 block-hail-large rotate: false - xy: 1367, 933 + xy: 1031, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-hail-medium rotate: false - xy: 1831, 613 + xy: 1843, 607 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hail-small rotate: false - xy: 1581, 498 + xy: 1135, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-hail-tiny rotate: false - xy: 1599, 444 + xy: 1361, 155 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13875,28 +15751,28 @@ block-hail-xlarge index: -1 block-hotrock-large rotate: false - xy: 1409, 933 + xy: 1073, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-hotrock-medium rotate: false - xy: 1835, 647 + xy: 1843, 573 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hotrock-small rotate: false - xy: 1607, 498 + xy: 1135, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-hotrock-tiny rotate: false - xy: 1599, 426 + xy: 1361, 137 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13910,28 +15786,28 @@ block-hotrock-xlarge index: -1 block-hyper-processor-large rotate: false - xy: 1451, 933 + xy: 1115, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-hyper-processor-medium rotate: false - xy: 1847, 579 + xy: 1877, 629 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hyper-processor-small rotate: false - xy: 1633, 493 + xy: 1161, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-hyper-processor-tiny rotate: false - xy: 1599, 408 + xy: 1361, 119 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13945,49 +15821,49 @@ block-hyper-processor-xlarge index: -1 block-ice-large rotate: false - xy: 1493, 933 + xy: 1157, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ice-medium rotate: false - xy: 1865, 613 + xy: 1877, 595 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-small rotate: false - xy: 1659, 493 + xy: 1161, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ice-snow-large rotate: false - xy: 1535, 933 + xy: 1199, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ice-snow-medium rotate: false - xy: 1869, 647 + xy: 1877, 561 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-snow-small rotate: false - xy: 1685, 493 + xy: 1187, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ice-snow-tiny rotate: false - xy: 1599, 390 + xy: 1366, 101 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14001,35 +15877,35 @@ block-ice-snow-xlarge index: -1 block-ice-tiny rotate: false - xy: 1593, 369 + xy: 1379, 199 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-ice-wall-large rotate: false - xy: 1577, 933 + xy: 1241, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ice-wall-medium rotate: false - xy: 1903, 655 + xy: 1911, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-wall-small rotate: false - xy: 1711, 493 + xy: 1187, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ice-wall-tiny rotate: false - xy: 1593, 351 + xy: 1379, 181 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14050,28 +15926,28 @@ block-ice-xlarge index: -1 block-illuminator-large rotate: false - xy: 1619, 933 + xy: 1283, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-illuminator-medium rotate: false - xy: 1937, 647 + xy: 1911, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-illuminator-small rotate: false - xy: 1737, 493 + xy: 1213, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-illuminator-tiny rotate: false - xy: 1593, 333 + xy: 1379, 163 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14085,28 +15961,28 @@ block-illuminator-xlarge index: -1 block-impact-reactor-large rotate: false - xy: 1661, 933 + xy: 1325, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-impact-reactor-medium rotate: false - xy: 1881, 579 + xy: 1945, 611 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-impact-reactor-small rotate: false - xy: 1763, 493 + xy: 1213, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-impact-reactor-tiny rotate: false - xy: 1593, 315 + xy: 1379, 145 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14120,28 +15996,28 @@ block-impact-reactor-xlarge index: -1 block-incinerator-large rotate: false - xy: 1703, 933 + xy: 1367, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-incinerator-medium rotate: false - xy: 1899, 613 + xy: 1945, 577 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-incinerator-small rotate: false - xy: 1789, 493 + xy: 1005, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-incinerator-tiny rotate: false - xy: 1596, 297 + xy: 1379, 127 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14155,28 +16031,28 @@ block-incinerator-xlarge index: -1 block-inverted-sorter-large rotate: false - xy: 1745, 933 + xy: 1409, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-inverted-sorter-medium rotate: false - xy: 1933, 613 + xy: 1911, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-inverted-sorter-small rotate: false - xy: 1815, 493 + xy: 1031, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-inverted-sorter-tiny rotate: false - xy: 1596, 279 + xy: 1384, 109 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14190,28 +16066,28 @@ block-inverted-sorter-xlarge index: -1 block-item-source-large rotate: false - xy: 1787, 933 + xy: 1451, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-item-source-medium rotate: false - xy: 1915, 579 + xy: 1945, 543 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-item-source-small rotate: false - xy: 1841, 493 + xy: 1057, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-item-source-tiny rotate: false - xy: 1596, 261 + xy: 1384, 91 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14225,28 +16101,28 @@ block-item-source-xlarge index: -1 block-item-void-large rotate: false - xy: 1829, 933 + xy: 1493, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-item-void-medium rotate: false - xy: 1949, 579 + xy: 1979, 611 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-item-void-small rotate: false - xy: 1867, 493 + xy: 1083, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-item-void-tiny rotate: false - xy: 1596, 243 + xy: 1373, 73 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14260,28 +16136,28 @@ block-item-void-xlarge index: -1 block-junction-large rotate: false - xy: 1871, 933 + xy: 1535, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-junction-medium rotate: false - xy: 1967, 613 + xy: 1979, 577 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-junction-small rotate: false - xy: 1893, 493 + xy: 1109, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-junction-tiny rotate: false - xy: 1617, 462 + xy: 1391, 73 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14295,28 +16171,28 @@ block-junction-xlarge index: -1 block-kiln-large rotate: false - xy: 1913, 933 + xy: 1577, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-kiln-medium rotate: false - xy: 1971, 647 + xy: 1979, 543 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-kiln-small rotate: false - xy: 1919, 493 + xy: 1135, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-kiln-tiny rotate: false - xy: 1617, 444 + xy: 1383, 55 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14330,28 +16206,28 @@ block-kiln-xlarge index: -1 block-lancer-large rotate: false - xy: 1955, 933 + xy: 1619, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-lancer-medium rotate: false - xy: 1977, 681 + xy: 1995, 645 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-lancer-small rotate: false - xy: 1945, 493 + xy: 1161, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-lancer-tiny rotate: false - xy: 1617, 426 + xy: 1383, 37 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14365,28 +16241,28 @@ block-lancer-xlarge index: -1 block-large-logic-display-large rotate: false - xy: 845, 891 + xy: 1661, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-large-logic-display-medium rotate: false - xy: 1983, 579 + xy: 2003, 679 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-large-logic-display-small rotate: false - xy: 1971, 493 + xy: 1187, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-large-logic-display-tiny rotate: false - xy: 1617, 408 + xy: 1383, 19 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14400,28 +16276,28 @@ block-large-logic-display-xlarge index: -1 block-laser-drill-large rotate: false - xy: 887, 891 + xy: 1703, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-laser-drill-medium rotate: false - xy: 2001, 613 + xy: 2011, 713 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-laser-drill-small rotate: false - xy: 1997, 493 + xy: 1213, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-laser-drill-tiny rotate: false - xy: 1617, 390 + xy: 1383, 1 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14435,35 +16311,35 @@ block-laser-drill-xlarge index: -1 block-launch-pad-large rotate: false - xy: 929, 891 + xy: 1745, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-launch-pad-large-large rotate: false - xy: 971, 891 + xy: 1787, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-launch-pad-large-medium rotate: false - xy: 2005, 647 + xy: 2013, 611 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-launch-pad-large-small rotate: false - xy: 2023, 493 + xy: 979, 126 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-launch-pad-large-tiny rotate: false - xy: 1611, 372 + xy: 1401, 55 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14477,21 +16353,21 @@ block-launch-pad-large-xlarge index: -1 block-launch-pad-medium rotate: false - xy: 1989, 823 + xy: 2013, 577 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-launch-pad-small rotate: false - xy: 1355, 407 + xy: 976, 100 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-launch-pad-tiny rotate: false - xy: 1611, 354 + xy: 1401, 37 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14505,28 +16381,28 @@ block-launch-pad-xlarge index: -1 block-liquid-junction-large rotate: false - xy: 1013, 891 + xy: 1829, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-junction-medium rotate: false - xy: 1988, 789 + xy: 2013, 543 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-junction-small rotate: false - xy: 1381, 433 + xy: 1005, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-junction-tiny rotate: false - xy: 1611, 336 + xy: 1401, 19 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14540,28 +16416,28 @@ block-liquid-junction-xlarge index: -1 block-liquid-router-large rotate: false - xy: 1055, 891 + xy: 1871, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-router-medium rotate: false - xy: 1987, 755 + xy: 1536, 605 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-router-small rotate: false - xy: 1381, 407 + xy: 1031, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-router-tiny rotate: false - xy: 1611, 318 + xy: 1401, 1 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14575,28 +16451,28 @@ block-liquid-router-xlarge index: -1 block-liquid-source-large rotate: false - xy: 1097, 891 + xy: 1913, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-source-medium rotate: false - xy: 1986, 721 + xy: 1571, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-source-small rotate: false - xy: 1407, 434 + xy: 1057, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-source-tiny rotate: false - xy: 1614, 300 + xy: 1703, 561 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14610,28 +16486,28 @@ block-liquid-source-xlarge index: -1 block-liquid-tank-large rotate: false - xy: 1139, 891 + xy: 1955, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-tank-medium rotate: false - xy: 869, 257 + xy: 1605, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-tank-small rotate: false - xy: 1407, 408 + xy: 1083, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-tank-tiny rotate: false - xy: 1614, 282 + xy: 1721, 563 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14645,28 +16521,28 @@ block-liquid-tank-xlarge index: -1 block-liquid-void-large rotate: false - xy: 1181, 891 + xy: 845, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-void-medium rotate: false - xy: 903, 257 + xy: 1639, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-void-small rotate: false - xy: 1433, 431 + xy: 1109, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-void-tiny rotate: false - xy: 1614, 264 + xy: 1688, 306 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14680,28 +16556,28 @@ block-liquid-void-xlarge index: -1 block-logic-display-large rotate: false - xy: 1223, 891 + xy: 887, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-logic-display-medium rotate: false - xy: 937, 257 + xy: 1673, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-logic-display-small rotate: false - xy: 1459, 431 + xy: 1135, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-logic-display-tiny rotate: false - xy: 1614, 246 + xy: 1637, 288 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14715,28 +16591,28 @@ block-logic-display-xlarge index: -1 block-logic-processor-large rotate: false - xy: 1265, 891 + xy: 929, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-logic-processor-medium rotate: false - xy: 1091, 571 + xy: 1707, 581 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-logic-processor-small rotate: false - xy: 1433, 405 + xy: 1161, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-logic-processor-tiny rotate: false - xy: 1629, 372 + xy: 1655, 288 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14750,28 +16626,28 @@ block-logic-processor-xlarge index: -1 block-magmarock-large rotate: false - xy: 1307, 891 + xy: 971, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-magmarock-medium rotate: false - xy: 1125, 555 + xy: 1741, 556 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-magmarock-small rotate: false - xy: 1459, 405 + xy: 1187, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-magmarock-tiny rotate: false - xy: 1629, 354 + xy: 1673, 288 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14785,28 +16661,28 @@ block-magmarock-xlarge index: -1 block-mass-driver-large rotate: false - xy: 1349, 891 + xy: 1013, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mass-driver-medium rotate: false - xy: 1159, 555 + xy: 1775, 556 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mass-driver-small rotate: false - xy: 1485, 431 + xy: 1213, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mass-driver-tiny rotate: false - xy: 1629, 336 + xy: 1691, 288 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14820,28 +16696,28 @@ block-mass-driver-xlarge index: -1 block-mechanical-drill-large rotate: false - xy: 1391, 891 + xy: 1055, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mechanical-drill-medium rotate: false - xy: 1193, 555 + xy: 1809, 553 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mechanical-drill-small rotate: false - xy: 1485, 405 + xy: 1002, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mechanical-drill-tiny rotate: false - xy: 1629, 318 + xy: 1637, 270 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14855,28 +16731,28 @@ block-mechanical-drill-xlarge index: -1 block-mechanical-pump-large rotate: false - xy: 1433, 891 + xy: 1097, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mechanical-pump-medium rotate: false - xy: 1227, 555 + xy: 1843, 539 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mechanical-pump-small rotate: false - xy: 1511, 437 + xy: 1028, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mechanical-pump-tiny rotate: false - xy: 1632, 300 + xy: 1655, 270 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14890,28 +16766,28 @@ block-mechanical-pump-xlarge index: -1 block-meltdown-large rotate: false - xy: 1475, 891 + xy: 1139, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-meltdown-medium rotate: false - xy: 1261, 555 + xy: 1877, 527 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-meltdown-small rotate: false - xy: 1511, 411 + xy: 1054, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-meltdown-tiny rotate: false - xy: 1632, 282 + xy: 1673, 270 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14925,28 +16801,28 @@ block-meltdown-xlarge index: -1 block-melter-large rotate: false - xy: 1517, 891 + xy: 1181, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-melter-medium rotate: false - xy: 1295, 555 + xy: 1911, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-melter-small rotate: false - xy: 1537, 437 + xy: 1080, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-melter-tiny rotate: false - xy: 1632, 264 + xy: 1691, 270 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14960,28 +16836,28 @@ block-melter-xlarge index: -1 block-memory-bank-large rotate: false - xy: 1559, 891 + xy: 1223, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-memory-bank-medium rotate: false - xy: 1329, 555 + xy: 1945, 509 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-memory-bank-small rotate: false - xy: 1537, 411 + xy: 1106, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-memory-bank-tiny rotate: false - xy: 1632, 246 + xy: 1721, 545 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14995,28 +16871,28 @@ block-memory-bank-xlarge index: -1 block-memory-cell-large rotate: false - xy: 1601, 891 + xy: 1265, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-memory-cell-medium rotate: false - xy: 1363, 555 + xy: 1979, 509 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-memory-cell-small rotate: false - xy: 1185, 369 + xy: 1132, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-memory-cell-tiny rotate: false - xy: 1635, 475 + xy: 1739, 538 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15030,28 +16906,28 @@ block-memory-cell-xlarge index: -1 block-mend-projector-large rotate: false - xy: 1643, 891 + xy: 1307, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mend-projector-medium rotate: false - xy: 1397, 555 + xy: 2013, 509 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mend-projector-small rotate: false - xy: 1174, 237 + xy: 1158, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mend-projector-tiny rotate: false - xy: 1635, 457 + xy: 1757, 538 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15065,28 +16941,28 @@ block-mend-projector-xlarge index: -1 block-mender-large rotate: false - xy: 1685, 891 + xy: 1349, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mender-medium rotate: false - xy: 1431, 555 + xy: 1449, 576 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mender-small rotate: false - xy: 1174, 211 + xy: 1184, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mender-tiny rotate: false - xy: 1653, 475 + xy: 1775, 538 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15100,28 +16976,28 @@ block-mender-xlarge index: -1 block-message-large rotate: false - xy: 1727, 891 + xy: 1391, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-message-medium rotate: false - xy: 1465, 555 + xy: 1570, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-message-small rotate: false - xy: 1245, 399 + xy: 1210, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-message-tiny rotate: false - xy: 1635, 439 + xy: 1705, 527 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15135,28 +17011,28 @@ block-message-xlarge index: -1 block-metal-floor-2-large rotate: false - xy: 1769, 891 + xy: 1433, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-2-medium rotate: false - xy: 1499, 555 + xy: 1604, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-2-small rotate: false - xy: 1271, 401 + xy: 1009, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-2-tiny rotate: false - xy: 1653, 457 + xy: 1705, 509 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15170,28 +17046,28 @@ block-metal-floor-2-xlarge index: -1 block-metal-floor-3-large rotate: false - xy: 1811, 891 + xy: 1475, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-3-medium rotate: false - xy: 1533, 555 + xy: 1638, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-3-small rotate: false - xy: 1297, 401 + xy: 1035, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-3-tiny rotate: false - xy: 1671, 475 + xy: 1704, 491 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15205,28 +17081,28 @@ block-metal-floor-3-xlarge index: -1 block-metal-floor-5-large rotate: false - xy: 1853, 891 + xy: 1517, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-5-medium rotate: false - xy: 1567, 555 + xy: 1672, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-5-small rotate: false - xy: 1323, 401 + xy: 1061, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-5-tiny rotate: false - xy: 1635, 421 + xy: 1704, 473 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15240,28 +17116,28 @@ block-metal-floor-5-xlarge index: -1 block-metal-floor-damaged-large rotate: false - xy: 1895, 891 + xy: 1559, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-damaged-medium rotate: false - xy: 1601, 550 + xy: 636, 81 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-damaged-small rotate: false - xy: 1511, 385 + xy: 1087, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-damaged-tiny rotate: false - xy: 1653, 439 + xy: 1704, 455 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15275,28 +17151,28 @@ block-metal-floor-damaged-xlarge index: -1 block-metal-floor-large rotate: false - xy: 1937, 891 + xy: 1601, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-medium rotate: false - xy: 1635, 545 + xy: 670, 80 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-small rotate: false - xy: 1537, 385 + xy: 1113, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-tiny rotate: false - xy: 1671, 457 + xy: 1704, 437 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15310,28 +17186,28 @@ block-metal-floor-xlarge index: -1 block-micro-processor-large rotate: false - xy: 859, 849 + xy: 1643, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-micro-processor-medium rotate: false - xy: 1669, 545 + xy: 704, 80 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-micro-processor-small rotate: false - xy: 1180, 341 + xy: 1139, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-micro-processor-tiny rotate: false - xy: 1689, 475 + xy: 1704, 419 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15345,28 +17221,28 @@ block-micro-processor-xlarge index: -1 block-moss-large rotate: false - xy: 859, 807 + xy: 1685, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-moss-medium rotate: false - xy: 1703, 545 + xy: 738, 80 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-moss-small rotate: false - xy: 1180, 315 + xy: 1165, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-moss-tiny rotate: false - xy: 1635, 403 + xy: 1715, 401 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15380,28 +17256,28 @@ block-moss-xlarge index: -1 block-mud-large rotate: false - xy: 901, 849 + xy: 1727, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mud-medium rotate: false - xy: 1737, 545 + xy: 772, 80 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mud-small rotate: false - xy: 1180, 289 + xy: 1191, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mud-tiny rotate: false - xy: 1653, 421 + xy: 1715, 383 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15415,28 +17291,28 @@ block-mud-xlarge index: -1 block-multi-press-large rotate: false - xy: 859, 765 + xy: 1769, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-multi-press-medium rotate: false - xy: 1771, 545 + xy: 806, 80 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-multi-press-small rotate: false - xy: 1180, 263 + xy: 1217, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-multi-press-tiny rotate: false - xy: 1671, 439 + xy: 1715, 365 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15450,28 +17326,28 @@ block-multi-press-xlarge index: -1 block-multiplicative-reconstructor-large rotate: false - xy: 901, 807 + xy: 1811, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-multiplicative-reconstructor-medium rotate: false - xy: 1805, 545 + xy: 635, 47 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-multiplicative-reconstructor-small rotate: false - xy: 1200, 237 + xy: 1447, 341 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-multiplicative-reconstructor-tiny rotate: false - xy: 1689, 457 + xy: 1723, 520 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15485,28 +17361,28 @@ block-multiplicative-reconstructor-xlarge index: -1 block-naval-factory-large rotate: false - xy: 943, 849 + xy: 1853, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-naval-factory-medium rotate: false - xy: 1839, 545 + xy: 669, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-naval-factory-small rotate: false - xy: 1200, 211 + xy: 1236, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-naval-factory-tiny rotate: false - xy: 1707, 475 + xy: 1741, 520 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15520,28 +17396,28 @@ block-naval-factory-xlarge index: -1 block-oil-extractor-large rotate: false - xy: 859, 723 + xy: 1895, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-oil-extractor-medium rotate: false - xy: 1873, 545 + xy: 703, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-oil-extractor-small rotate: false - xy: 1211, 372 + xy: 1243, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-oil-extractor-tiny rotate: false - xy: 1653, 403 + xy: 1759, 520 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15555,28 +17431,28 @@ block-oil-extractor-xlarge index: -1 block-ore-coal-large rotate: false - xy: 901, 765 + xy: 1937, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-coal-medium rotate: false - xy: 1907, 545 + xy: 737, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-coal-small rotate: false - xy: 1237, 373 + xy: 1523, 545 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-coal-tiny rotate: false - xy: 1671, 421 + xy: 1777, 520 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15590,28 +17466,28 @@ block-ore-coal-xlarge index: -1 block-ore-copper-large rotate: false - xy: 943, 807 + xy: 859, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-copper-medium rotate: false - xy: 1941, 545 + xy: 771, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-copper-small rotate: false - xy: 1263, 373 + xy: 1523, 519 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-copper-tiny rotate: false - xy: 1689, 439 + xy: 1723, 502 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15625,28 +17501,28 @@ block-ore-copper-xlarge index: -1 block-ore-lead-large rotate: false - xy: 985, 849 + xy: 859, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-lead-medium rotate: false - xy: 1975, 545 + xy: 805, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-lead-small rotate: false - xy: 1289, 375 + xy: 1522, 493 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-lead-tiny rotate: false - xy: 1707, 457 + xy: 1741, 502 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15660,28 +17536,28 @@ block-ore-lead-xlarge index: -1 block-ore-scrap-large rotate: false - xy: 859, 681 + xy: 901, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-scrap-medium rotate: false - xy: 2009, 545 + xy: 619, 13 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-scrap-small rotate: false - xy: 1315, 375 + xy: 1522, 467 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-scrap-tiny rotate: false - xy: 1725, 475 + xy: 1759, 502 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15695,28 +17571,28 @@ block-ore-scrap-xlarge index: -1 block-ore-thorium-large rotate: false - xy: 901, 723 + xy: 859, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-thorium-medium rotate: false - xy: 974, 325 + xy: 653, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-thorium-small rotate: false - xy: 1341, 375 + xy: 1522, 441 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-thorium-tiny rotate: false - xy: 1671, 403 + xy: 1777, 502 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15730,28 +17606,28 @@ block-ore-thorium-xlarge index: -1 block-ore-titanium-large rotate: false - xy: 943, 765 + xy: 943, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-titanium-medium rotate: false - xy: 971, 291 + xy: 687, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-titanium-small rotate: false - xy: 1367, 381 + xy: 1522, 415 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-titanium-tiny rotate: false - xy: 1689, 421 + xy: 1722, 484 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15765,28 +17641,28 @@ block-ore-titanium-xlarge index: -1 block-overdrive-dome-large rotate: false - xy: 985, 807 + xy: 901, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-overdrive-dome-medium rotate: false - xy: 971, 257 + xy: 721, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-overdrive-dome-small rotate: false - xy: 1393, 381 + xy: 1515, 389 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-overdrive-dome-tiny rotate: false - xy: 1707, 439 + xy: 1722, 466 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15800,28 +17676,28 @@ block-overdrive-dome-xlarge index: -1 block-overdrive-projector-large rotate: false - xy: 1027, 849 + xy: 859, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-overdrive-projector-medium rotate: false - xy: 688, 240 + xy: 755, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-overdrive-projector-small rotate: false - xy: 1419, 379 + xy: 1489, 373 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-overdrive-projector-tiny rotate: false - xy: 1725, 457 + xy: 1740, 484 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15835,28 +17711,28 @@ block-overdrive-projector-xlarge index: -1 block-overflow-gate-large rotate: false - xy: 901, 681 + xy: 985, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-overflow-gate-medium rotate: false - xy: 688, 206 + xy: 789, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-overflow-gate-small rotate: false - xy: 1445, 379 + xy: 1515, 363 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-overflow-gate-tiny rotate: false - xy: 1743, 475 + xy: 1722, 448 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15870,28 +17746,28 @@ block-overflow-gate-xlarge index: -1 block-parallax-large rotate: false - xy: 943, 723 + xy: 943, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-parallax-medium rotate: false - xy: 722, 250 + xy: 823, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-parallax-small rotate: false - xy: 1471, 379 + xy: 1241, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-parallax-tiny rotate: false - xy: 1689, 403 + xy: 1740, 466 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15905,28 +17781,28 @@ block-parallax-xlarge index: -1 block-payload-conveyor-large rotate: false - xy: 985, 765 + xy: 901, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-payload-conveyor-medium rotate: false - xy: 756, 250 + xy: 839, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-payload-conveyor-small rotate: false - xy: 1367, 355 + xy: 1247, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-payload-conveyor-tiny rotate: false - xy: 1707, 421 + xy: 1758, 484 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15940,28 +17816,28 @@ block-payload-conveyor-xlarge index: -1 block-payload-router-large rotate: false - xy: 1027, 807 + xy: 859, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-payload-router-medium rotate: false - xy: 722, 216 + xy: 840, 80 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-payload-router-small rotate: false - xy: 1393, 355 + xy: 1243, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-payload-router-tiny rotate: false - xy: 1725, 439 + xy: 1722, 430 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15975,28 +17851,28 @@ block-payload-router-xlarge index: -1 block-pebbles-large rotate: false - xy: 1069, 849 + xy: 1027, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pebbles-medium rotate: false - xy: 790, 250 + xy: 857, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pebbles-small rotate: false - xy: 1419, 353 + xy: 1243, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pebbles-tiny rotate: false - xy: 1743, 457 + xy: 1740, 448 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16010,28 +17886,28 @@ block-pebbles-xlarge index: -1 block-phase-conduit-large rotate: false - xy: 943, 681 + xy: 985, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-conduit-medium rotate: false - xy: 756, 216 + xy: 873, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-conduit-small rotate: false - xy: 1445, 353 + xy: 1243, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-conduit-tiny rotate: false - xy: 1761, 475 + xy: 1758, 466 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16045,28 +17921,28 @@ block-phase-conduit-xlarge index: -1 block-phase-conveyor-large rotate: false - xy: 985, 723 + xy: 943, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-conveyor-medium rotate: false - xy: 824, 250 + xy: 891, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-conveyor-small rotate: false - xy: 1471, 353 + xy: 1239, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-conveyor-tiny rotate: false - xy: 1707, 403 + xy: 1776, 484 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16080,35 +17956,35 @@ block-phase-conveyor-xlarge index: -1 block-phase-wall-large rotate: false - xy: 1027, 765 + xy: 901, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-wall-large-large rotate: false - xy: 1069, 807 + xy: 1069, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-wall-large-medium rotate: false - xy: 790, 216 + xy: 814, 248 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-wall-large-small rotate: false - xy: 1497, 359 + xy: 1239, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-wall-large-tiny rotate: false - xy: 1725, 421 + xy: 1740, 430 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16122,21 +17998,21 @@ block-phase-wall-large-xlarge index: -1 block-phase-wall-medium rotate: false - xy: 824, 216 + xy: 814, 214 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-wall-small rotate: false - xy: 1523, 359 + xy: 1239, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-wall-tiny rotate: false - xy: 1743, 439 + xy: 1758, 448 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16150,28 +18026,28 @@ block-phase-wall-xlarge index: -1 block-phase-weaver-large rotate: false - xy: 1111, 849 + xy: 1027, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-weaver-medium rotate: false - xy: 858, 223 + xy: 848, 250 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-weaver-small rotate: false - xy: 1549, 359 + xy: 1239, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-weaver-tiny rotate: false - xy: 1761, 457 + xy: 1776, 466 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16185,28 +18061,28 @@ block-phase-weaver-xlarge index: -1 block-pine-large rotate: false - xy: 985, 681 + xy: 985, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pine-medium rotate: false - xy: 892, 223 + xy: 848, 216 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pine-small rotate: false - xy: 1497, 333 + xy: 1273, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pine-tiny rotate: false - xy: 1779, 475 + xy: 1758, 430 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16220,28 +18096,28 @@ block-pine-xlarge index: -1 block-plastanium-compressor-large rotate: false - xy: 1027, 723 + xy: 943, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-compressor-medium rotate: false - xy: 926, 223 + xy: 882, 250 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-compressor-small rotate: false - xy: 1523, 333 + xy: 1267, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-compressor-tiny rotate: false - xy: 1725, 403 + xy: 1776, 448 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16255,28 +18131,28 @@ block-plastanium-compressor-xlarge index: -1 block-plastanium-conveyor-large rotate: false - xy: 1069, 765 + xy: 901, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-conveyor-medium rotate: false - xy: 960, 223 + xy: 882, 216 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-conveyor-small rotate: false - xy: 1549, 333 + xy: 1269, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-conveyor-tiny rotate: false - xy: 1743, 421 + xy: 1776, 430 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16290,35 +18166,35 @@ block-plastanium-conveyor-xlarge index: -1 block-plastanium-wall-large rotate: false - xy: 1111, 807 + xy: 1111, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-wall-large-large rotate: false - xy: 1153, 849 + xy: 1069, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-wall-large-medium rotate: false - xy: 688, 172 + xy: 916, 250 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-wall-large-small rotate: false - xy: 1119, 185 + xy: 1269, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-wall-large-tiny rotate: false - xy: 1761, 439 + xy: 1733, 412 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16332,21 +18208,21 @@ block-plastanium-wall-large-xlarge index: -1 block-plastanium-wall-medium rotate: false - xy: 722, 182 + xy: 916, 216 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-wall-small rotate: false - xy: 1119, 159 + xy: 1269, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-wall-tiny rotate: false - xy: 1779, 457 + xy: 1733, 394 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16360,28 +18236,28 @@ block-plastanium-wall-xlarge index: -1 block-plated-conduit-large rotate: false - xy: 1027, 681 + xy: 1027, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plated-conduit-medium rotate: false - xy: 756, 182 + xy: 848, 182 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plated-conduit-small rotate: false - xy: 1145, 185 + xy: 1265, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plated-conduit-tiny rotate: false - xy: 1797, 475 + xy: 1751, 412 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16395,28 +18271,28 @@ block-plated-conduit-xlarge index: -1 block-pneumatic-drill-large rotate: false - xy: 1069, 723 + xy: 985, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pneumatic-drill-medium rotate: false - xy: 790, 182 + xy: 848, 148 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pneumatic-drill-small rotate: false - xy: 1119, 133 + xy: 1265, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pneumatic-drill-tiny rotate: false - xy: 1743, 403 + xy: 1733, 376 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16430,35 +18306,35 @@ block-pneumatic-drill-xlarge index: -1 block-power-node-large rotate: false - xy: 1111, 765 + xy: 943, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-node-large-large rotate: false - xy: 1153, 807 + xy: 1153, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-node-large-medium rotate: false - xy: 824, 182 + xy: 848, 114 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-node-large-small rotate: false - xy: 1145, 159 + xy: 1265, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-node-large-tiny rotate: false - xy: 1761, 421 + xy: 1751, 394 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16472,21 +18348,21 @@ block-power-node-large-xlarge index: -1 block-power-node-medium rotate: false - xy: 858, 189 + xy: 874, 80 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-node-small rotate: false - xy: 1171, 185 + xy: 1265, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-node-tiny rotate: false - xy: 1779, 439 + xy: 1769, 412 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16500,28 +18376,28 @@ block-power-node-xlarge index: -1 block-power-source-large rotate: false - xy: 1195, 849 + xy: 1111, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-source-medium rotate: false - xy: 892, 189 + xy: 882, 182 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-source-small rotate: false - xy: 1119, 107 + xy: 1262, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-source-tiny rotate: false - xy: 1797, 457 + xy: 1751, 376 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16535,28 +18411,28 @@ block-power-source-xlarge index: -1 block-power-void-large rotate: false - xy: 1069, 681 + xy: 1069, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-void-medium rotate: false - xy: 926, 189 + xy: 916, 182 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-void-small rotate: false - xy: 1145, 133 + xy: 1299, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-void-tiny rotate: false - xy: 1815, 475 + xy: 1769, 394 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16570,28 +18446,28 @@ block-power-void-xlarge index: -1 block-pulse-conduit-large rotate: false - xy: 1111, 723 + xy: 1027, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pulse-conduit-medium rotate: false - xy: 960, 189 + xy: 882, 148 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pulse-conduit-small rotate: false - xy: 1171, 159 + xy: 1293, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pulse-conduit-tiny rotate: false - xy: 1761, 403 + xy: 1769, 376 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16605,28 +18481,28 @@ block-pulse-conduit-xlarge index: -1 block-pulverizer-large rotate: false - xy: 1153, 765 + xy: 985, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pulverizer-medium rotate: false - xy: 677, 138 + xy: 882, 114 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pulverizer-small rotate: false - xy: 1197, 185 + xy: 1295, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pulverizer-tiny rotate: false - xy: 1779, 421 + xy: 1733, 358 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16640,28 +18516,28 @@ block-pulverizer-xlarge index: -1 block-pyratite-mixer-large rotate: false - xy: 1195, 807 + xy: 1195, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pyratite-mixer-medium rotate: false - xy: 994, 223 + xy: 916, 148 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pyratite-mixer-small rotate: false - xy: 1119, 81 + xy: 1295, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pyratite-mixer-tiny rotate: false - xy: 1797, 439 + xy: 1751, 358 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16675,28 +18551,28 @@ block-pyratite-mixer-xlarge index: -1 block-repair-point-large rotate: false - xy: 1237, 849 + xy: 1153, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-repair-point-medium rotate: false - xy: 994, 189 + xy: 916, 114 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-repair-point-small rotate: false - xy: 1145, 107 + xy: 1295, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-repair-point-tiny rotate: false - xy: 1815, 457 + xy: 1769, 358 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16710,28 +18586,28 @@ block-repair-point-xlarge index: -1 block-resupply-point-large rotate: false - xy: 1111, 681 + xy: 1111, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-resupply-point-medium rotate: false - xy: 711, 138 + xy: 908, 80 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-resupply-point-small rotate: false - xy: 1171, 133 + xy: 1291, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-resupply-point-tiny rotate: false - xy: 1833, 475 + xy: 1787, 412 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16745,28 +18621,28 @@ block-resupply-point-xlarge index: -1 block-ripple-large rotate: false - xy: 1153, 723 + xy: 1069, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ripple-medium rotate: false - xy: 711, 104 + xy: 907, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ripple-small rotate: false - xy: 1197, 159 + xy: 1291, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ripple-tiny rotate: false - xy: 1779, 403 + xy: 1787, 394 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16780,28 +18656,28 @@ block-ripple-xlarge index: -1 block-rotary-pump-large rotate: false - xy: 1195, 765 + xy: 1027, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-rotary-pump-medium rotate: false - xy: 745, 148 + xy: 925, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rotary-pump-small rotate: false - xy: 1119, 55 + xy: 1291, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-rotary-pump-tiny rotate: false - xy: 1797, 421 + xy: 1787, 376 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16815,28 +18691,28 @@ block-rotary-pump-xlarge index: -1 block-router-large rotate: false - xy: 1237, 807 + xy: 1237, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-router-medium rotate: false - xy: 779, 148 + xy: 941, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-router-small rotate: false - xy: 1145, 81 + xy: 1291, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-router-tiny rotate: false - xy: 1815, 439 + xy: 1787, 358 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16850,28 +18726,28 @@ block-router-xlarge index: -1 block-rtg-generator-large rotate: false - xy: 1279, 849 + xy: 1195, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-rtg-generator-medium rotate: false - xy: 745, 114 + xy: 942, 80 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rtg-generator-small rotate: false - xy: 1171, 107 + xy: 1288, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-rtg-generator-tiny rotate: false - xy: 1833, 457 + xy: 1794, 484 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16885,56 +18761,56 @@ block-rtg-generator-xlarge index: -1 block-salt-large rotate: false - xy: 1153, 681 + xy: 1153, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-salt-medium rotate: false - xy: 779, 114 + xy: 959, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salt-small rotate: false - xy: 1197, 133 + xy: 1269, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-salt-tiny rotate: false - xy: 1851, 475 + xy: 1794, 466 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-salt-wall-large rotate: false - xy: 1195, 723 + xy: 1111, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-salt-wall-medium rotate: false - xy: 813, 148 + xy: 975, 46 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salt-wall-small rotate: false - xy: 1119, 29 + xy: 1325, 331 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-salt-wall-tiny rotate: false - xy: 1797, 403 + xy: 1794, 448 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16955,28 +18831,28 @@ block-salt-xlarge index: -1 block-salvo-large rotate: false - xy: 1237, 765 + xy: 1069, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-salvo-medium rotate: false - xy: 813, 114 + xy: 993, 12 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salvo-small rotate: false - xy: 1145, 55 + xy: 1351, 331 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-salvo-tiny rotate: false - xy: 1815, 421 + xy: 1794, 430 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16990,28 +18866,28 @@ block-salvo-xlarge index: -1 block-sand-boulder-large rotate: false - xy: 1279, 807 + xy: 1279, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-boulder-medium rotate: false - xy: 745, 80 + xy: 1533, 571 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-boulder-small rotate: false - xy: 1171, 81 + xy: 1295, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-boulder-tiny rotate: false - xy: 1833, 439 + xy: 1805, 412 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17025,56 +18901,56 @@ block-sand-boulder-xlarge index: -1 block-sand-large rotate: false - xy: 1321, 849 + xy: 1237, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-medium rotate: false - xy: 779, 80 + xy: 1483, 563 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-small rotate: false - xy: 1197, 107 + xy: 1377, 325 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-tiny rotate: false - xy: 1851, 457 + xy: 1805, 394 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-sand-wall-large rotate: false - xy: 1195, 681 + xy: 1195, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-wall-medium rotate: false - xy: 813, 80 + xy: 1567, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-wall-small rotate: false - xy: 1145, 29 + xy: 1314, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-wall-tiny rotate: false - xy: 1869, 475 + xy: 1805, 376 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17088,28 +18964,28 @@ block-sand-wall-xlarge index: -1 block-sand-water-large rotate: false - xy: 1237, 723 + xy: 1153, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-water-medium rotate: false - xy: 847, 148 + xy: 1601, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-water-small rotate: false - xy: 1171, 55 + xy: 1321, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-water-tiny rotate: false - xy: 1815, 403 + xy: 1805, 358 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17130,28 +19006,28 @@ block-sand-xlarge index: -1 block-scatter-large rotate: false - xy: 1279, 765 + xy: 1111, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scatter-medium rotate: false - xy: 847, 114 + xy: 1635, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scatter-small rotate: false - xy: 1197, 81 + xy: 1549, 519 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scatter-tiny rotate: false - xy: 1833, 421 + xy: 1391, 287 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17165,28 +19041,28 @@ block-scatter-xlarge index: -1 block-scorch-large rotate: false - xy: 1321, 807 + xy: 1321, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scorch-medium rotate: false - xy: 847, 80 + xy: 1669, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scorch-small rotate: false - xy: 1171, 29 + xy: 1548, 493 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scorch-tiny rotate: false - xy: 1851, 439 + xy: 1391, 269 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17200,28 +19076,28 @@ block-scorch-xlarge index: -1 block-scrap-wall-gigantic-large rotate: false - xy: 1363, 849 + xy: 1279, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-gigantic-medium rotate: false - xy: 881, 155 + xy: 979, 537 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-gigantic-small rotate: false - xy: 1197, 55 + xy: 1575, 519 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-gigantic-tiny rotate: false - xy: 1869, 457 + xy: 1391, 251 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17235,28 +19111,28 @@ block-scrap-wall-gigantic-xlarge index: -1 block-scrap-wall-huge-large rotate: false - xy: 1237, 681 + xy: 1237, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-huge-medium rotate: false - xy: 881, 121 + xy: 979, 503 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-huge-small rotate: false - xy: 1197, 29 + xy: 1548, 467 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-huge-tiny rotate: false - xy: 1887, 475 + xy: 1391, 233 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17270,35 +19146,35 @@ block-scrap-wall-huge-xlarge index: -1 block-scrap-wall-large rotate: false - xy: 1279, 723 + xy: 1195, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-large-large rotate: false - xy: 1321, 765 + xy: 1153, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-large-medium rotate: false - xy: 915, 155 + xy: 979, 469 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-large-small rotate: false - xy: 1119, 3 + xy: 1574, 493 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-large-tiny rotate: false - xy: 1833, 403 + xy: 1409, 292 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17312,21 +19188,21 @@ block-scrap-wall-large-xlarge index: -1 block-scrap-wall-medium rotate: false - xy: 881, 87 + xy: 979, 435 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-small rotate: false - xy: 1145, 3 + xy: 1601, 519 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-tiny rotate: false - xy: 1851, 421 + xy: 1409, 274 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17340,28 +19216,28 @@ block-scrap-wall-xlarge index: -1 block-segment-large rotate: false - xy: 1363, 807 + xy: 1363, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-segment-medium rotate: false - xy: 915, 121 + xy: 979, 401 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-segment-small rotate: false - xy: 1171, 3 + xy: 1548, 441 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-segment-tiny rotate: false - xy: 1869, 439 + xy: 1409, 256 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17375,28 +19251,28 @@ block-segment-xlarge index: -1 block-separator-large rotate: false - xy: 1405, 849 + xy: 1321, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-separator-medium rotate: false - xy: 949, 155 + xy: 1013, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-separator-small rotate: false - xy: 1197, 3 + xy: 1574, 467 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-separator-tiny rotate: false - xy: 1887, 457 + xy: 1409, 238 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17410,28 +19286,28 @@ block-separator-xlarge index: -1 block-shale-boulder-large rotate: false - xy: 1279, 681 + xy: 1279, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shale-boulder-medium rotate: false - xy: 915, 87 + xy: 1047, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-boulder-small rotate: false - xy: 1206, 343 + xy: 1600, 493 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shale-boulder-tiny rotate: false - xy: 1905, 475 + xy: 1427, 287 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17445,56 +19321,56 @@ block-shale-boulder-xlarge index: -1 block-shale-large rotate: false - xy: 1321, 723 + xy: 1237, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shale-medium rotate: false - xy: 949, 121 + xy: 1013, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-small rotate: false - xy: 1206, 317 + xy: 1627, 519 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shale-tiny rotate: false - xy: 1851, 403 + xy: 1445, 287 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-shale-wall-large rotate: false - xy: 1363, 765 + xy: 1195, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shale-wall-medium rotate: false - xy: 983, 155 + xy: 1081, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-wall-small rotate: false - xy: 1206, 291 + xy: 1548, 415 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shale-wall-tiny rotate: false - xy: 1869, 421 + xy: 1427, 269 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17515,28 +19391,28 @@ block-shale-xlarge index: -1 block-shock-mine-large rotate: false - xy: 1405, 807 + xy: 1405, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shock-mine-medium rotate: false - xy: 949, 87 + xy: 1013, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shock-mine-small rotate: false - xy: 1206, 265 + xy: 1541, 389 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shock-mine-tiny rotate: false - xy: 1887, 439 + xy: 1463, 287 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17550,28 +19426,28 @@ block-shock-mine-xlarge index: -1 block-shrubs-large rotate: false - xy: 1447, 849 + xy: 1363, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shrubs-medium rotate: false - xy: 983, 121 + xy: 1047, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shrubs-small rotate: false - xy: 1226, 239 + xy: 1574, 441 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shrubs-tiny rotate: false - xy: 1905, 457 + xy: 1427, 251 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17585,28 +19461,28 @@ block-shrubs-xlarge index: -1 block-silicon-crucible-large rotate: false - xy: 1321, 681 + xy: 1321, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-silicon-crucible-medium rotate: false - xy: 983, 87 + xy: 1115, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-silicon-crucible-small rotate: false - xy: 1226, 213 + xy: 1600, 467 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-silicon-crucible-tiny rotate: false - xy: 1923, 475 + xy: 1445, 269 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17620,28 +19496,28 @@ block-silicon-crucible-xlarge index: -1 block-silicon-smelter-large rotate: false - xy: 1363, 723 + xy: 1279, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-silicon-smelter-medium rotate: false - xy: 1017, 155 + xy: 1013, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-silicon-smelter-small rotate: false - xy: 1223, 185 + xy: 1626, 493 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-silicon-smelter-tiny rotate: false - xy: 1869, 403 + xy: 1481, 287 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17655,28 +19531,28 @@ block-silicon-smelter-xlarge index: -1 block-slag-large rotate: false - xy: 1405, 765 + xy: 1237, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-slag-medium rotate: false - xy: 1017, 121 + xy: 1047, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-slag-small rotate: false - xy: 1223, 159 + xy: 1653, 519 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-slag-tiny rotate: false - xy: 1887, 421 + xy: 1445, 251 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17690,28 +19566,28 @@ block-slag-xlarge index: -1 block-snow-boulder-large rotate: false - xy: 1447, 807 + xy: 1447, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-boulder-medium rotate: false - xy: 1017, 87 + xy: 1081, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-boulder-small rotate: false - xy: 1223, 133 + xy: 1541, 363 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-boulder-tiny rotate: false - xy: 1905, 439 + xy: 1463, 269 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17725,42 +19601,42 @@ block-snow-boulder-xlarge index: -1 block-snow-large rotate: false - xy: 1489, 849 + xy: 1405, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-medium rotate: false - xy: 881, 53 + xy: 1149, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-pine-large rotate: false - xy: 1363, 681 + xy: 1363, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-pine-medium rotate: false - xy: 915, 53 + xy: 1013, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-pine-small rotate: false - xy: 1223, 107 + xy: 1574, 415 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-pine-tiny rotate: false - xy: 1923, 457 + xy: 1463, 251 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17774,42 +19650,42 @@ block-snow-pine-xlarge index: -1 block-snow-small rotate: false - xy: 1223, 81 + xy: 1567, 389 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-tiny rotate: false - xy: 1941, 475 + xy: 1481, 269 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-snow-wall-large rotate: false - xy: 1405, 723 + xy: 1321, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-wall-medium rotate: false - xy: 949, 53 + xy: 1047, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-wall-small rotate: false - xy: 1223, 55 + xy: 1600, 441 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-wall-tiny rotate: false - xy: 1887, 403 + xy: 1481, 251 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17830,35 +19706,35 @@ block-snow-xlarge index: -1 block-solar-panel-large rotate: false - xy: 1447, 765 + xy: 1279, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-solar-panel-large-large rotate: false - xy: 1489, 807 + xy: 1489, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-solar-panel-large-medium rotate: false - xy: 983, 53 + xy: 1081, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-solar-panel-large-small rotate: false - xy: 1223, 29 + xy: 1626, 467 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-solar-panel-large-tiny rotate: false - xy: 1905, 421 + xy: 1427, 233 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17872,21 +19748,21 @@ block-solar-panel-large-xlarge index: -1 block-solar-panel-medium rotate: false - xy: 1017, 53 + xy: 1115, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-solar-panel-small rotate: false - xy: 1223, 3 + xy: 1652, 493 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-solar-panel-tiny rotate: false - xy: 1923, 439 + xy: 1445, 233 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17900,28 +19776,28 @@ block-solar-panel-xlarge index: -1 block-sorter-large rotate: false - xy: 1531, 849 + xy: 1447, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sorter-medium rotate: false - xy: 979, 529 + xy: 1183, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sorter-small rotate: false - xy: 1289, 349 + xy: 1567, 363 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sorter-tiny rotate: false - xy: 1941, 457 + xy: 1463, 233 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17933,1304 +19809,1339 @@ block-sorter-xlarge orig: 48, 48 offset: 0, 0 index: -1 -block-spawn-large +block-space-large rotate: false - xy: 1405, 681 + xy: 1405, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spawn-medium +block-space-medium rotate: false - xy: 979, 495 + xy: 1047, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spawn-small +block-space-small rotate: false - xy: 1315, 349 + xy: 1600, 415 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spawn-tiny +block-space-tiny rotate: false - xy: 1959, 475 + xy: 1481, 233 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spawn-xlarge +block-space-xlarge rotate: false xy: 451, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spectre-large +block-spawn-large rotate: false - xy: 1447, 723 + xy: 1363, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spectre-medium +block-spawn-medium rotate: false - xy: 979, 461 + xy: 1081, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spectre-small +block-spawn-small rotate: false - xy: 1341, 349 + xy: 1593, 389 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spectre-tiny +block-spawn-tiny rotate: false - xy: 1905, 403 + xy: 1409, 220 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spectre-xlarge +block-spawn-xlarge rotate: false xy: 351, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-cluster-large +block-spectre-large rotate: false - xy: 1489, 765 + xy: 1321, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-cluster-medium +block-spectre-medium rotate: false - xy: 979, 427 + xy: 1115, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-cluster-small +block-spectre-small rotate: false - xy: 1367, 329 + xy: 1626, 441 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-cluster-tiny +block-spectre-tiny rotate: false - xy: 1923, 421 + xy: 1427, 215 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-cluster-xlarge +block-spectre-xlarge rotate: false xy: 401, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-moss-large +block-spore-cluster-large rotate: false - xy: 1531, 807 + xy: 1531, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-moss-medium +block-spore-cluster-medium rotate: false - xy: 979, 393 + xy: 1149, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-moss-small +block-spore-cluster-small rotate: false - xy: 1393, 329 + xy: 1652, 467 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-moss-tiny +block-spore-cluster-tiny rotate: false - xy: 1941, 439 + xy: 1445, 215 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-moss-xlarge +block-spore-cluster-xlarge rotate: false xy: 451, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-pine-large +block-spore-moss-large rotate: false - xy: 1573, 849 + xy: 1489, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-pine-medium +block-spore-moss-medium rotate: false - xy: 979, 359 + xy: 1217, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-pine-small +block-spore-moss-small rotate: false - xy: 1419, 327 + xy: 1593, 363 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-pine-tiny +block-spore-moss-tiny rotate: false - xy: 1959, 457 + xy: 1463, 215 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-pine-xlarge +block-spore-moss-xlarge rotate: false xy: 501, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-press-large +block-spore-pine-large rotate: false - xy: 1447, 681 + xy: 1447, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-press-medium +block-spore-pine-medium rotate: false - xy: 1008, 325 + xy: 1081, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-press-small +block-spore-pine-small rotate: false - xy: 1445, 327 + xy: 1626, 415 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-press-tiny +block-spore-pine-tiny rotate: false - xy: 1977, 475 + xy: 1481, 215 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-press-xlarge +block-spore-pine-xlarge rotate: false xy: 351, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-wall-large +block-spore-press-large rotate: false - xy: 1489, 723 + xy: 1405, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-wall-medium +block-spore-press-medium rotate: false - xy: 1005, 291 + xy: 1115, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-wall-small +block-spore-press-small rotate: false - xy: 1471, 327 + xy: 1619, 389 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-wall-tiny +block-spore-press-tiny rotate: false - xy: 1923, 403 + xy: 1499, 283 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-wall-xlarge +block-spore-press-xlarge rotate: false xy: 401, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-steam-generator-large +block-spore-wall-large rotate: false - xy: 1531, 765 + xy: 1363, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-steam-generator-medium +block-spore-wall-medium rotate: false - xy: 1005, 257 + xy: 1149, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-steam-generator-small +block-spore-wall-small rotate: false - xy: 1497, 307 + xy: 1652, 441 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-steam-generator-tiny +block-spore-wall-tiny rotate: false - xy: 1941, 421 + xy: 1517, 283 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-steam-generator-xlarge +block-spore-wall-xlarge rotate: false xy: 451, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-stone-large +block-steam-generator-large rotate: false - xy: 1573, 807 + xy: 1573, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-stone-medium +block-steam-generator-medium rotate: false - xy: 1028, 223 + xy: 1183, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-stone-small +block-steam-generator-small rotate: false - xy: 1523, 307 + xy: 1619, 363 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-stone-tiny +block-steam-generator-tiny rotate: false - xy: 1959, 439 + xy: 1499, 265 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-stone-wall-large - rotate: false - xy: 1615, 849 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-stone-wall-medium - rotate: false - xy: 1028, 189 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-stone-wall-small - rotate: false - xy: 1549, 307 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-stone-wall-tiny - rotate: false - xy: 1977, 457 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-stone-wall-xlarge +block-steam-generator-xlarge rotate: false xy: 501, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-stone-xlarge +block-stone-large + rotate: false + xy: 1531, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-stone-medium + rotate: false + xy: 1251, 555 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-stone-small + rotate: false + xy: 1652, 415 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-stone-tiny + rotate: false + xy: 1535, 283 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-stone-wall-large + rotate: false + xy: 1489, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-stone-wall-medium + rotate: false + xy: 1115, 419 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-stone-wall-small + rotate: false + xy: 1645, 389 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-stone-wall-tiny + rotate: false + xy: 1499, 247 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-stone-wall-xlarge rotate: false xy: 551, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-surge-tower-large - rotate: false - xy: 1489, 681 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-surge-tower-medium - rotate: false - xy: 1051, 155 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-surge-tower-small - rotate: false - xy: 1232, 346 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-surge-tower-tiny - rotate: false - xy: 1995, 475 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-surge-tower-xlarge +block-stone-xlarge rotate: false xy: 351, 316 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-surge-wall-large +block-surge-tower-large rotate: false - xy: 1531, 723 + xy: 1447, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-surge-wall-large-large +block-surge-tower-medium rotate: false - xy: 1573, 765 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-surge-wall-large-medium - rotate: false - xy: 1051, 121 + xy: 1149, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-surge-wall-large-small +block-surge-tower-small rotate: false - xy: 1232, 320 + xy: 1645, 363 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-surge-wall-large-tiny +block-surge-tower-tiny rotate: false - xy: 1941, 403 + xy: 1517, 265 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-surge-wall-large-xlarge +block-surge-tower-xlarge rotate: false xy: 401, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-surge-wall-medium +block-surge-wall-large rotate: false - xy: 1051, 87 + xy: 1405, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-surge-wall-large-large + rotate: false + xy: 1615, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-surge-wall-large-medium + rotate: false + xy: 1183, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-surge-wall-small +block-surge-wall-large-small rotate: false - xy: 1232, 294 + xy: 1679, 519 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-surge-wall-tiny +block-surge-wall-large-tiny rotate: false - xy: 1959, 421 + xy: 1499, 229 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-surge-wall-xlarge +block-surge-wall-large-xlarge rotate: false xy: 451, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-swarmer-large +block-surge-wall-medium rotate: false - xy: 1615, 807 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-swarmer-medium - rotate: false - xy: 1051, 53 + xy: 1217, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-swarmer-small +block-surge-wall-small rotate: false - xy: 1232, 268 + xy: 1678, 493 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-swarmer-tiny +block-surge-wall-tiny rotate: false - xy: 1977, 439 + xy: 1517, 247 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-swarmer-xlarge +block-surge-wall-xlarge rotate: false xy: 501, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-switch-large +block-swarmer-large rotate: false - xy: 1657, 849 + xy: 1573, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-switch-medium +block-swarmer-medium rotate: false - xy: 2011, 687 + xy: 1285, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-switch-small +block-swarmer-small rotate: false - xy: 1258, 347 + xy: 1678, 467 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-switch-tiny +block-swarmer-tiny rotate: false - xy: 1995, 457 + xy: 1535, 265 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-switch-xlarge +block-swarmer-xlarge rotate: false xy: 551, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tainted-water-large +block-switch-large rotate: false - xy: 1531, 681 + xy: 1531, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-tainted-water-medium +block-switch-medium rotate: false - xy: 779, 46 + xy: 1149, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tainted-water-small +block-switch-small rotate: false - xy: 1258, 321 + xy: 1678, 441 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tainted-water-tiny +block-switch-tiny rotate: false - xy: 2013, 475 + xy: 1517, 229 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tainted-water-xlarge +block-switch-xlarge rotate: false xy: 601, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tar-large +block-tainted-water-large rotate: false - xy: 1573, 723 + xy: 1489, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-tar-medium +block-tainted-water-medium rotate: false - xy: 779, 12 + xy: 1183, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tar-small +block-tainted-water-small rotate: false - xy: 1258, 295 + xy: 1678, 415 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tar-tiny +block-tainted-water-tiny rotate: false - xy: 2031, 475 + xy: 1535, 247 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tar-xlarge +block-tainted-water-xlarge rotate: false xy: 351, 266 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tendrils-large +block-tar-large rotate: false - xy: 1615, 765 + xy: 1447, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-tendrils-medium +block-tar-medium rotate: false - xy: 813, 46 + xy: 1217, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tendrils-small +block-tar-small rotate: false - xy: 1258, 269 + xy: 1671, 389 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tendrils-tiny +block-tar-tiny rotate: false - xy: 1959, 403 + xy: 1535, 229 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tendrils-xlarge +block-tar-xlarge rotate: false xy: 401, 316 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tetrative-reconstructor-large +block-tendrils-large rotate: false - xy: 1657, 807 + xy: 1657, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-tetrative-reconstructor-medium +block-tendrils-medium rotate: false - xy: 847, 46 + xy: 1251, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tetrative-reconstructor-small +block-tendrils-small rotate: false - xy: 1284, 323 + xy: 1671, 363 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tetrative-reconstructor-tiny +block-tendrils-tiny rotate: false - xy: 1977, 421 + xy: 1499, 211 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tetrative-reconstructor-xlarge +block-tendrils-xlarge rotate: false xy: 451, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thermal-generator-large +block-tetrative-reconstructor-large rotate: false - xy: 1699, 849 + xy: 1615, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-thermal-generator-medium +block-tetrative-reconstructor-medium rotate: false - xy: 813, 12 + xy: 1319, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thermal-generator-small +block-tetrative-reconstructor-small rotate: false - xy: 1310, 323 + xy: 1473, 341 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thermal-generator-tiny +block-tetrative-reconstructor-tiny rotate: false - xy: 1995, 439 + xy: 1517, 211 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thermal-generator-xlarge +block-tetrative-reconstructor-xlarge rotate: false xy: 501, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thermal-pump-large +block-thermal-generator-large rotate: false - xy: 1573, 681 + xy: 1573, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-thermal-pump-medium +block-thermal-generator-medium rotate: false - xy: 847, 12 + xy: 1183, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thermal-pump-small +block-thermal-generator-small rotate: false - xy: 1284, 297 + xy: 1319, 299 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thermal-pump-tiny +block-thermal-generator-tiny rotate: false - xy: 2013, 457 + xy: 1535, 211 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thermal-pump-xlarge +block-thermal-generator-xlarge rotate: false xy: 551, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thorium-reactor-large +block-thermal-pump-large rotate: false - xy: 1615, 723 + xy: 1531, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-thorium-reactor-medium +block-thermal-pump-medium rotate: false - xy: 881, 19 + xy: 1217, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thorium-reactor-small +block-thermal-pump-small rotate: false - xy: 1336, 323 + xy: 1321, 273 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thorium-reactor-tiny +block-thermal-pump-tiny rotate: false - xy: 2031, 457 + xy: 1553, 271 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thorium-reactor-xlarge +block-thermal-pump-xlarge rotate: false xy: 601, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thorium-wall-large +block-thorium-reactor-large rotate: false - xy: 1657, 765 + xy: 1489, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-thorium-wall-large-large +block-thorium-reactor-medium rotate: false - xy: 1699, 807 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thorium-wall-large-medium - rotate: false - xy: 915, 19 + xy: 1251, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thorium-wall-large-small +block-thorium-reactor-small rotate: false - xy: 1284, 271 + xy: 1321, 247 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thorium-wall-large-tiny +block-thorium-reactor-tiny rotate: false - xy: 1977, 403 + xy: 1571, 271 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thorium-wall-large-xlarge +block-thorium-reactor-xlarge rotate: false xy: 651, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thorium-wall-medium +block-thorium-wall-large rotate: false - xy: 949, 19 + xy: 1699, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thorium-wall-large-large + rotate: false + xy: 1657, 807 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thorium-wall-large-medium + rotate: false + xy: 1285, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thorium-wall-small +block-thorium-wall-large-small rotate: false - xy: 1310, 297 + xy: 1321, 221 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thorium-wall-tiny +block-thorium-wall-large-tiny rotate: false - xy: 1995, 421 + xy: 1553, 253 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thorium-wall-xlarge +block-thorium-wall-large-xlarge rotate: false xy: 351, 216 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thruster-large +block-thorium-wall-medium rotate: false - xy: 1741, 849 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thruster-medium - rotate: false - xy: 983, 19 + xy: 1353, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thruster-small +block-thorium-wall-small rotate: false - xy: 1310, 271 + xy: 1317, 195 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thruster-tiny +block-thorium-wall-tiny rotate: false - xy: 2013, 439 + xy: 1553, 235 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thruster-xlarge +block-thorium-wall-xlarge rotate: false xy: 401, 266 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-titanium-conveyor-large +block-thruster-large rotate: false - xy: 1615, 681 + xy: 1615, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-titanium-conveyor-medium +block-thruster-medium rotate: false - xy: 1017, 19 + xy: 1217, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-titanium-conveyor-small +block-thruster-small rotate: false - xy: 1336, 297 + xy: 1317, 169 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-titanium-conveyor-tiny +block-thruster-tiny rotate: false - xy: 2031, 439 + xy: 1571, 253 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-titanium-conveyor-xlarge +block-thruster-xlarge rotate: false xy: 451, 316 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-titanium-wall-large +block-titanium-conveyor-large rotate: false - xy: 1657, 723 + xy: 1573, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-titanium-wall-large-large +block-titanium-conveyor-medium rotate: false - xy: 1699, 765 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-titanium-wall-large-medium - rotate: false - xy: 1051, 19 + xy: 1251, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-titanium-wall-large-small +block-titanium-conveyor-small rotate: false - xy: 1336, 271 + xy: 1317, 143 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-titanium-wall-large-tiny +block-titanium-conveyor-tiny rotate: false - xy: 1995, 403 + xy: 1553, 217 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-titanium-wall-large-xlarge +block-titanium-conveyor-xlarge rotate: false xy: 501, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-titanium-wall-medium +block-titanium-wall-large rotate: false - xy: 1039, 291 + xy: 1531, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-titanium-wall-large-large + rotate: false + xy: 1741, 849 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-titanium-wall-large-medium + rotate: false + xy: 1285, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-titanium-wall-small +block-titanium-wall-large-small rotate: false - xy: 1362, 303 + xy: 1317, 117 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-titanium-wall-tiny +block-titanium-wall-large-tiny rotate: false - xy: 2013, 421 + xy: 1571, 235 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-titanium-wall-xlarge +block-titanium-wall-large-xlarge rotate: false xy: 551, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tsunami-large +block-titanium-wall-medium rotate: false - xy: 1741, 807 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-tsunami-medium - rotate: false - xy: 1039, 257 + xy: 1319, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tsunami-small +block-titanium-wall-small rotate: false - xy: 1388, 303 + xy: 1345, 305 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tsunami-tiny +block-titanium-wall-tiny rotate: false - xy: 2031, 421 + xy: 1571, 217 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tsunami-xlarge +block-titanium-wall-xlarge rotate: false xy: 601, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-underflow-gate-large +block-tsunami-large rotate: false - xy: 1783, 849 + xy: 1699, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-underflow-gate-medium +block-tsunami-medium rotate: false - xy: 1062, 223 + xy: 1387, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-underflow-gate-small +block-tsunami-small rotate: false - xy: 1362, 277 + xy: 1347, 279 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-underflow-gate-tiny +block-tsunami-tiny rotate: false - xy: 2013, 403 + xy: 1589, 262 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-underflow-gate-xlarge +block-tsunami-xlarge rotate: false xy: 651, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-unloader-large +block-underflow-gate-large rotate: false - xy: 1657, 681 + xy: 1657, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-unloader-medium +block-underflow-gate-medium rotate: false - xy: 1062, 189 + xy: 1251, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-unloader-small +block-underflow-gate-small rotate: false - xy: 1388, 277 + xy: 1347, 253 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-unloader-tiny +block-underflow-gate-tiny rotate: false - xy: 2031, 403 + xy: 1589, 244 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-unloader-xlarge +block-underflow-gate-xlarge rotate: false xy: 701, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-vault-large +block-unloader-large rotate: false - xy: 1699, 723 + xy: 1615, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-vault-medium +block-unloader-medium rotate: false - xy: 1085, 155 + xy: 1285, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-vault-small +block-unloader-small rotate: false - xy: 1414, 301 + xy: 1347, 227 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-vault-tiny +block-unloader-tiny rotate: false - xy: 1647, 385 + xy: 1589, 226 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-vault-xlarge +block-unloader-xlarge rotate: false xy: 351, 166 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-water-extractor-large +block-vault-large rotate: false - xy: 1741, 765 + xy: 1573, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-water-extractor-medium +block-vault-medium rotate: false - xy: 1085, 121 + xy: 1319, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-water-extractor-small +block-vault-small rotate: false - xy: 1440, 301 + xy: 1340, 91 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-water-extractor-tiny +block-vault-tiny rotate: false - xy: 1647, 367 + xy: 1589, 208 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-water-extractor-xlarge +block-vault-xlarge rotate: false xy: 401, 216 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-water-large +block-water-extractor-large rotate: false - xy: 1783, 807 + xy: 1783, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-water-medium +block-water-extractor-medium rotate: false - xy: 1085, 87 + xy: 1353, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-water-small +block-water-extractor-small rotate: false - xy: 1466, 301 + xy: 1347, 65 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-water-tiny +block-water-extractor-tiny rotate: false - xy: 1665, 385 + xy: 1607, 257 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-water-xlarge +block-water-extractor-xlarge rotate: false xy: 451, 266 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-wave-large +block-water-large rotate: false - xy: 1825, 849 + xy: 1741, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-wave-medium +block-water-medium rotate: false - xy: 1085, 53 + xy: 1285, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-wave-small +block-water-small rotate: false - xy: 1414, 275 + xy: 1027, 39 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-wave-tiny +block-water-tiny rotate: false - xy: 1647, 349 + xy: 1607, 239 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-wave-xlarge +block-water-xlarge rotate: false xy: 501, 316 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-white-tree-dead-large +block-wave-large rotate: false - xy: 1699, 681 + xy: 1699, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-white-tree-dead-medium +block-wave-medium rotate: false - xy: 1085, 19 + xy: 1319, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-white-tree-dead-small +block-wave-small rotate: false - xy: 1440, 275 + xy: 1027, 13 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-white-tree-dead-tiny +block-wave-tiny rotate: false - xy: 1665, 367 + xy: 1607, 221 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-white-tree-dead-xlarge +block-wave-xlarge rotate: false xy: 551, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-white-tree-large +block-white-tree-dead-large rotate: false - xy: 1741, 723 + xy: 1657, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-white-tree-medium +block-white-tree-dead-medium rotate: false - xy: 983, 571 + xy: 1353, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-white-tree-small +block-white-tree-dead-small rotate: false - xy: 1466, 275 + xy: 1053, 39 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-white-tree-tiny +block-white-tree-dead-tiny rotate: false - xy: 1683, 385 + xy: 1607, 203 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-white-tree-xlarge +block-white-tree-dead-xlarge rotate: false xy: 601, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 +block-white-tree-large + rotate: false + xy: 1615, 681 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-white-tree-medium + rotate: false + xy: 1387, 521 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-white-tree-small + rotate: false + xy: 1053, 13 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-white-tree-tiny + rotate: false + xy: 1553, 199 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-white-tree-xlarge + rotate: false + xy: 651, 466 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 button rotate: false - xy: 1437, 652 + xy: 1273, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19238,7 +21149,7 @@ button index: -1 button-disabled rotate: false - xy: 1133, 652 + xy: 1007, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19246,7 +21157,7 @@ button-disabled index: -1 button-down rotate: false - xy: 1133, 623 + xy: 1951, 812 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19254,7 +21165,7 @@ button-down index: -1 button-edge-1 rotate: false - xy: 1171, 652 + xy: 1007, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19262,7 +21173,7 @@ button-edge-1 index: -1 button-edge-2 rotate: false - xy: 1171, 623 + xy: 1045, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19270,7 +21181,7 @@ button-edge-2 index: -1 button-edge-3 rotate: false - xy: 1209, 652 + xy: 1951, 783 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19278,7 +21189,7 @@ button-edge-3 index: -1 button-edge-4 rotate: false - xy: 1209, 623 + xy: 1045, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19286,7 +21197,7 @@ button-edge-4 index: -1 button-right-disabled rotate: false - xy: 1209, 623 + xy: 1045, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19294,7 +21205,7 @@ button-right-disabled index: -1 button-edge-over-4 rotate: false - xy: 1247, 652 + xy: 1083, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19302,7 +21213,7 @@ button-edge-over-4 index: -1 button-over rotate: false - xy: 1247, 623 + xy: 1083, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19310,7 +21221,7 @@ button-over index: -1 button-red rotate: false - xy: 1285, 652 + xy: 1121, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19318,7 +21229,7 @@ button-red index: -1 button-right rotate: false - xy: 1323, 623 + xy: 1159, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19326,7 +21237,7 @@ button-right index: -1 button-right-down rotate: false - xy: 1285, 623 + xy: 1121, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19334,7 +21245,7 @@ button-right-down index: -1 button-right-over rotate: false - xy: 1323, 652 + xy: 1159, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19342,7 +21253,7 @@ button-right-over index: -1 button-select rotate: false - xy: 1492, 281 + xy: 1079, 39 size: 24, 24 split: 4, 4, 4, 4 orig: 24, 24 @@ -19350,7 +21261,7 @@ button-select index: -1 button-square rotate: false - xy: 1399, 652 + xy: 1235, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19358,7 +21269,7 @@ button-square index: -1 button-square-down rotate: false - xy: 1361, 652 + xy: 1197, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19366,7 +21277,7 @@ button-square-down index: -1 button-square-over rotate: false - xy: 1361, 623 + xy: 1197, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19374,7 +21285,7 @@ button-square-over index: -1 button-trans rotate: false - xy: 1399, 623 + xy: 1235, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19382,49 +21293,49 @@ button-trans index: -1 check-disabled rotate: false - xy: 1013, 521 + xy: 1319, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-off rotate: false - xy: 1013, 487 + xy: 1353, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on rotate: false - xy: 1013, 453 + xy: 1387, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-disabled rotate: false - xy: 1013, 419 + xy: 1353, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-over rotate: false - xy: 1013, 385 + xy: 1387, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-over rotate: false - xy: 1047, 521 + xy: 1387, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 clear rotate: false - xy: 795, 866 + xy: 1565, 325 size: 10, 10 orig: 10, 10 offset: 0, 0 @@ -19438,7 +21349,7 @@ crater index: -1 cursor rotate: false - xy: 1937, 683 + xy: 1319, 351 size: 4, 4 orig: 4, 4 offset: 0, 0 @@ -19452,7 +21363,7 @@ discord-banner index: -1 flat-down-base rotate: false - xy: 1437, 623 + xy: 1273, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19467,7 +21378,7 @@ info-banner index: -1 inventory rotate: false - xy: 1518, 265 + xy: 1105, 23 size: 24, 40 split: 10, 10, 10, 14 orig: 24, 40 @@ -19475,147 +21386,147 @@ inventory index: -1 item-blast-compound-icon rotate: false - xy: 1047, 487 + xy: 1013, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-coal-icon rotate: false - xy: 1047, 453 + xy: 1047, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-copper-icon rotate: false - xy: 1047, 419 + xy: 1081, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-graphite-icon rotate: false - xy: 1047, 385 + xy: 1115, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-lead-icon rotate: false - xy: 1042, 351 + xy: 1149, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-metaglass-icon rotate: false - xy: 1081, 537 + xy: 1183, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-phase-fabric-icon rotate: false - xy: 1081, 503 + xy: 1217, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-plastanium-icon rotate: false - xy: 1081, 469 + xy: 1251, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-pyratite-icon rotate: false - xy: 1081, 435 + xy: 1285, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-sand-icon rotate: false - xy: 1081, 401 + xy: 1319, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-scrap-icon rotate: false - xy: 1115, 521 + xy: 1353, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-silicon-icon rotate: false - xy: 1149, 521 + xy: 1387, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-spore-pod-icon rotate: false - xy: 1115, 487 + xy: 1421, 542 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-surge-alloy-icon rotate: false - xy: 1183, 521 + xy: 1421, 508 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-thorium-icon rotate: false - xy: 1149, 487 + xy: 1421, 474 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-titanium-icon rotate: false - xy: 1115, 453 + xy: 1421, 440 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-cryofluid-icon rotate: false - xy: 1217, 521 + xy: 1421, 406 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-oil-icon rotate: false - xy: 1183, 487 + xy: 1421, 372 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-slag-icon rotate: false - xy: 1149, 453 + xy: 1455, 529 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-water-icon rotate: false - xy: 1115, 419 + xy: 1455, 495 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 logic-node rotate: false - xy: 1251, 521 + xy: 1455, 461 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -19636,7 +21547,7 @@ nomap index: -1 pane rotate: false - xy: 1475, 623 + xy: 1311, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19644,7 +21555,7 @@ pane index: -1 pane-2 rotate: false - xy: 1475, 652 + xy: 1311, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19652,7 +21563,7 @@ pane-2 index: -1 scroll rotate: false - xy: 1492, 244 + xy: 1079, 2 size: 24, 35 split: 10, 10, 6, 5 orig: 24, 35 @@ -19675,63 +21586,63 @@ scroll-knob-horizontal-black index: -1 scroll-knob-vertical-black rotate: false - xy: 1544, 265 + xy: 1131, 23 size: 24, 40 orig: 24, 40 offset: 0, 0 index: -1 scroll-knob-vertical-thin rotate: false - xy: 1249, 171 + xy: 1697, 228 size: 12, 40 orig: 12, 40 offset: 0, 0 index: -1 selection rotate: false - xy: 1611, 315 + xy: 309, 866 size: 1, 1 orig: 1, 1 offset: 0, 0 index: -1 slider rotate: false - xy: 1039, 375 + xy: 1533, 621 size: 1, 8 orig: 1, 8 offset: 0, 0 index: -1 slider-knob rotate: false - xy: 1017, 565 + xy: 945, 293 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-down rotate: false - xy: 1489, 515 + xy: 976, 293 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-over rotate: false - xy: 1520, 515 + xy: 2017, 901 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-vertical rotate: false - xy: 1183, 421 + xy: 1681, 342 size: 8, 1 orig: 8, 1 offset: 0, 0 index: -1 underline rotate: false - xy: 1589, 652 + xy: 1425, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19739,7 +21650,7 @@ underline index: -1 underline-2 rotate: false - xy: 1513, 652 + xy: 1349, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19747,7 +21658,7 @@ underline-2 index: -1 underline-disabled rotate: false - xy: 1513, 623 + xy: 1349, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19755,7 +21666,7 @@ underline-disabled index: -1 underline-red rotate: false - xy: 1551, 652 + xy: 1387, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19763,7 +21674,7 @@ underline-red index: -1 underline-white rotate: false - xy: 1551, 623 + xy: 1387, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19771,42 +21682,42 @@ underline-white index: -1 unit-alpha-large rotate: false - xy: 1783, 765 + xy: 1825, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-alpha-medium rotate: false - xy: 1217, 487 + xy: 1455, 427 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-alpha-small rotate: false - xy: 1518, 239 + xy: 1157, 39 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-alpha-tiny rotate: false - xy: 1647, 331 + xy: 1571, 199 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-alpha-xlarge rotate: false - xy: 651, 466 + xy: 701, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-antumbra-large rotate: false - xy: 1951, 849 + xy: 1979, 891 size: 36, 40 orig: 36, 40 offset: 0, 0 @@ -19820,182 +21731,182 @@ unit-antumbra-medium index: -1 unit-antumbra-small rotate: false - xy: 418, 8 + xy: 511, 6 size: 21, 24 orig: 21, 24 offset: 0, 0 index: -1 unit-antumbra-tiny rotate: false - xy: 1444, 205 + xy: 619, 47 size: 14, 16 orig: 14, 16 offset: 0, 0 index: -1 unit-antumbra-xlarge rotate: false - xy: 601, 225 + xy: 551, 183 size: 43, 48 orig: 43, 48 offset: 0, 0 index: -1 unit-arkyid-large rotate: false - xy: 1825, 807 + xy: 1783, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-arkyid-medium rotate: false - xy: 1183, 453 + xy: 1455, 393 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-arkyid-small rotate: false - xy: 1544, 239 + xy: 1183, 39 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-arkyid-tiny rotate: false - xy: 1665, 349 + xy: 1589, 190 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-arkyid-xlarge rotate: false - xy: 701, 516 + xy: 351, 116 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-atrax-large rotate: false - xy: 1867, 860 + xy: 1741, 776 size: 40, 29 orig: 40, 29 offset: 0, 0 index: -1 unit-atrax-medium rotate: false - xy: 745, 55 + xy: 80, 3 size: 32, 23 orig: 32, 23 offset: 0, 0 index: -1 unit-atrax-small rotate: false - xy: 1075, 330 + xy: 976, 81 size: 24, 17 orig: 24, 17 offset: 0, 0 index: -1 unit-atrax-tiny rotate: false - xy: 711, 91 + xy: 1421, 576 size: 16, 11 orig: 16, 11 offset: 0, 0 index: -1 unit-atrax-xlarge rotate: false - xy: 351, 130 + xy: 401, 180 size: 48, 34 orig: 48, 34 offset: 0, 0 index: -1 unit-beta-large rotate: false - xy: 1741, 683 + xy: 1699, 725 size: 40, 38 orig: 40, 38 offset: 0, 0 index: -1 unit-beta-medium rotate: false - xy: 1149, 421 + xy: 877, 369 size: 32, 30 orig: 32, 30 offset: 0, 0 index: -1 unit-beta-small rotate: false - xy: 1362, 252 + xy: 1209, 40 size: 24, 23 orig: 24, 23 offset: 0, 0 index: -1 unit-beta-tiny rotate: false - xy: 1683, 368 + xy: 1607, 186 size: 16, 15 orig: 16, 15 offset: 0, 0 index: -1 unit-beta-xlarge rotate: false - xy: 401, 168 + xy: 451, 218 size: 48, 46 orig: 48, 46 offset: 0, 0 index: -1 unit-bryde-large rotate: false - xy: 1783, 723 + xy: 1657, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-bryde-medium rotate: false - xy: 1285, 521 + xy: 911, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-bryde-small rotate: false - xy: 1388, 251 + xy: 1235, 39 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-bryde-tiny rotate: false - xy: 1701, 385 + xy: 1625, 252 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-bryde-xlarge rotate: false - xy: 451, 216 + xy: 501, 266 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-corvus-large rotate: false - xy: 1825, 779 + xy: 1867, 863 size: 40, 26 orig: 40, 26 offset: 0, 0 index: -1 unit-corvus-medium rotate: false - xy: 1042, 329 + xy: 1489, 507 size: 31, 20 orig: 31, 20 offset: 0, 0 index: -1 unit-corvus-small rotate: false - xy: 1867, 681 + xy: 1105, 6 size: 24, 15 orig: 24, 15 offset: 0, 0 @@ -20009,336 +21920,336 @@ unit-corvus-tiny index: -1 unit-corvus-xlarge rotate: false - xy: 501, 283 + xy: 551, 333 size: 48, 31 orig: 48, 31 offset: 0, 0 index: -1 unit-crawler-large rotate: false - xy: 1867, 818 + xy: 1825, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-crawler-medium rotate: false - xy: 1251, 487 + xy: 945, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-crawler-small rotate: false - xy: 1414, 249 + xy: 1261, 39 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-crawler-tiny rotate: false - xy: 1665, 331 + xy: 1625, 234 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-crawler-xlarge rotate: false - xy: 551, 316 + xy: 601, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-dagger-large rotate: false - xy: 1909, 849 + xy: 1741, 734 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-dagger-medium rotate: false - xy: 1217, 453 + xy: 979, 367 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-dagger-small rotate: false - xy: 1440, 249 + xy: 1287, 39 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-dagger-tiny rotate: false - xy: 1683, 350 + xy: 1643, 252 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-dagger-xlarge rotate: false - xy: 601, 366 + xy: 651, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-eclipse-large rotate: false - xy: 1825, 737 + xy: 1783, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-eclipse-medium rotate: false - xy: 1319, 521 + xy: 911, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-eclipse-small rotate: false - xy: 1466, 249 + xy: 1313, 39 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-eclipse-tiny rotate: false - xy: 1701, 367 + xy: 1625, 216 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-eclipse-xlarge rotate: false - xy: 651, 416 + xy: 701, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-flare-large rotate: false - xy: 1867, 776 + xy: 1699, 683 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-flare-medium rotate: false - xy: 1285, 487 + xy: 945, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-flare-small rotate: false - xy: 1570, 281 + xy: 1339, 39 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-flare-tiny rotate: false - xy: 1719, 385 + xy: 1643, 234 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-flare-xlarge rotate: false - xy: 701, 466 + xy: 351, 66 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-fortress-large rotate: false - xy: 1783, 689 + xy: 443, 1 size: 40, 32 orig: 40, 32 offset: 0, 0 index: -1 unit-fortress-medium rotate: false - xy: 80, 1 + xy: 114, 1 size: 32, 25 orig: 32, 25 offset: 0, 0 index: -1 unit-fortress-small rotate: false - xy: 1570, 260 + xy: 1131, 2 size: 24, 19 orig: 24, 19 offset: 0, 0 index: -1 unit-fortress-tiny rotate: false - xy: 965, 597 + xy: 1703, 547 size: 16, 12 orig: 16, 12 offset: 0, 0 index: -1 unit-fortress-xlarge rotate: false - xy: 351, 90 + xy: 401, 140 size: 48, 38 orig: 48, 38 offset: 0, 0 index: -1 unit-gamma-large rotate: false - xy: 1909, 807 + xy: 1867, 821 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-gamma-medium rotate: false - xy: 1251, 453 + xy: 979, 333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-gamma-small rotate: false - xy: 1570, 234 + xy: 1157, 13 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-gamma-tiny rotate: false - xy: 1683, 332 + xy: 1661, 252 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-gamma-xlarge rotate: false - xy: 401, 118 + xy: 451, 168 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-horizon-large rotate: false - xy: 1825, 695 + xy: 1909, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-horizon-medium rotate: false - xy: 1353, 521 + xy: 1013, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-horizon-small rotate: false - xy: 1252, 242 + xy: 1183, 13 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-horizon-tiny rotate: false - xy: 1701, 349 + xy: 1625, 198 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-horizon-xlarge rotate: false - xy: 451, 166 + xy: 501, 216 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-mace-large rotate: false - xy: 1867, 734 + xy: 1741, 692 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-mace-medium rotate: false - xy: 1319, 487 + xy: 1047, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-mace-small rotate: false - xy: 1252, 216 + xy: 1209, 14 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-mace-tiny rotate: false - xy: 1719, 367 + xy: 1643, 216 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-mace-xlarge rotate: false - xy: 501, 233 + xy: 551, 283 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-mega-large rotate: false - xy: 1909, 765 + xy: 1783, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-mega-medium rotate: false - xy: 1285, 453 + xy: 1081, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-mega-small rotate: false - xy: 1278, 243 + xy: 1235, 13 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-mega-tiny rotate: false - xy: 1737, 385 + xy: 1661, 234 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-mega-xlarge rotate: false - xy: 551, 266 + xy: 601, 316 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-minke-large rotate: false - xy: 1951, 765 + xy: 1463, 610 size: 34, 40 orig: 34, 40 offset: 0, 0 index: -1 unit-minke-medium rotate: false - xy: 2020, 721 + xy: 950, 141 size: 27, 32 orig: 27, 32 offset: 0, 0 @@ -20352,581 +22263,581 @@ unit-minke-small index: -1 unit-minke-tiny rotate: false - xy: 1773, 349 + xy: 1793, 538 size: 13, 16 orig: 13, 16 offset: 0, 0 index: -1 unit-minke-xlarge rotate: false - xy: 601, 175 + xy: 551, 133 size: 41, 48 orig: 41, 48 offset: 0, 0 index: -1 unit-mono-large rotate: false - xy: 881, 639 + xy: 1825, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-mono-medium rotate: false - xy: 1387, 521 + xy: 1115, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-mono-small rotate: false - xy: 1278, 217 + xy: 1261, 13 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-mono-tiny rotate: false - xy: 1719, 349 + xy: 1679, 252 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-mono-xlarge rotate: false - xy: 601, 316 + xy: 651, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-nova-large rotate: false - xy: 881, 597 + xy: 1867, 779 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-nova-medium rotate: false - xy: 1353, 487 + xy: 1149, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-nova-small rotate: false - xy: 1304, 245 + xy: 1287, 13 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-nova-tiny rotate: false - xy: 1737, 367 + xy: 1643, 198 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-nova-xlarge rotate: false - xy: 651, 366 + xy: 701, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-oct-large rotate: false - xy: 923, 639 + xy: 1909, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-oct-medium rotate: false - xy: 1319, 453 + xy: 1183, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-oct-small rotate: false - xy: 1330, 245 + xy: 1313, 13 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-oct-tiny rotate: false - xy: 1755, 385 + xy: 1661, 216 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-oct-xlarge rotate: false - xy: 701, 416 + xy: 401, 90 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-omura-large rotate: false - xy: 1551, 513 + xy: 950, 251 size: 28, 40 orig: 28, 40 offset: 0, 0 index: -1 unit-omura-medium rotate: false - xy: 1486, 189 + xy: 983, 572 size: 22, 32 orig: 22, 32 offset: 0, 0 index: -1 unit-omura-small rotate: false - xy: 1737, 341 + xy: 1679, 226 size: 16, 24 orig: 16, 24 offset: 0, 0 index: -1 unit-omura-tiny rotate: false - xy: 1077, 580 + xy: 1389, 307 size: 11, 16 orig: 11, 16 offset: 0, 0 index: -1 unit-omura-xlarge rotate: false - xy: 1951, 715 + xy: 1501, 631 size: 33, 48 orig: 33, 48 offset: 0, 0 index: -1 unit-poly-large rotate: false - xy: 923, 597 + xy: 1825, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-poly-medium rotate: false - xy: 1421, 521 + xy: 1217, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-poly-small rotate: false - xy: 1304, 219 + xy: 1339, 13 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-poly-tiny rotate: false - xy: 1755, 367 + xy: 1661, 198 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-poly-xlarge rotate: false - xy: 351, 40 + xy: 451, 118 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-pulsar-large rotate: false - xy: 1867, 698 + xy: 1867, 743 size: 40, 34 orig: 40, 34 offset: 0, 0 index: -1 unit-pulsar-medium rotate: false - xy: 1183, 424 + xy: 1251, 356 size: 32, 27 orig: 32, 27 offset: 0, 0 index: -1 unit-pulsar-small rotate: false - xy: 1330, 223 + xy: 1499, 341 size: 24, 20 orig: 24, 20 offset: 0, 0 index: -1 unit-pulsar-tiny rotate: false - xy: 644, 175 + xy: 1697, 364 size: 16, 13 orig: 16, 13 offset: 0, 0 index: -1 unit-pulsar-xlarge rotate: false - xy: 401, 76 + xy: 351, 24 size: 48, 40 orig: 48, 40 offset: 0, 0 index: -1 unit-quad-large rotate: false - xy: 1909, 723 + xy: 1909, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-quad-medium rotate: false - xy: 385, 1 + xy: 1489, 474 size: 31, 31 orig: 31, 31 offset: 0, 0 index: -1 unit-quad-small rotate: false - xy: 1356, 226 + xy: 1525, 337 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-quad-tiny rotate: false - xy: 1701, 332 + xy: 1643, 181 size: 15, 15 orig: 15, 15 offset: 0, 0 index: -1 unit-quad-xlarge rotate: false - xy: 451, 116 + xy: 501, 166 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-quasar-large rotate: false - xy: 965, 639 + xy: 881, 639 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-quasar-medium rotate: false - xy: 1387, 487 + xy: 1285, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-quasar-small rotate: false - xy: 1382, 225 + xy: 1551, 337 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-quasar-tiny rotate: false - xy: 1773, 385 + xy: 1679, 208 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-quasar-xlarge rotate: false - xy: 501, 183 + xy: 551, 233 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-reign-large rotate: false - xy: 965, 611 + xy: 1783, 695 size: 40, 26 orig: 40, 26 offset: 0, 0 index: -1 unit-reign-medium rotate: false - xy: 114, 6 + xy: 1489, 452 size: 31, 20 orig: 31, 20 offset: 0, 0 index: -1 unit-reign-small rotate: false - xy: 301, 2 + xy: 1577, 346 size: 24, 15 orig: 24, 15 offset: 0, 0 index: -1 unit-reign-tiny rotate: false - xy: 781, 678 + xy: 1157, 1 size: 15, 10 orig: 15, 10 offset: 0, 0 index: -1 unit-reign-xlarge rotate: false - xy: 551, 233 + xy: 601, 283 size: 48, 31 orig: 48, 31 offset: 0, 0 index: -1 unit-risso-large rotate: false - xy: 1951, 807 + xy: 1993, 849 size: 35, 40 orig: 35, 40 offset: 0, 0 index: -1 unit-risso-medium rotate: false - xy: 2017, 579 + xy: 2019, 747 size: 28, 32 orig: 28, 32 offset: 0, 0 index: -1 unit-risso-small rotate: false - xy: 441, 6 + xy: 1629, 311 size: 21, 24 orig: 21, 24 offset: 0, 0 index: -1 unit-risso-tiny rotate: false - xy: 1791, 385 + xy: 1517, 579 size: 14, 16 orig: 14, 16 offset: 0, 0 index: -1 unit-risso-xlarge rotate: false - xy: 701, 326 + xy: 601, 233 size: 43, 48 orig: 43, 48 offset: 0, 0 index: -1 unit-scepter-large rotate: false - xy: 1007, 647 + xy: 881, 605 size: 40, 32 orig: 40, 32 offset: 0, 0 index: -1 unit-scepter-medium rotate: false - xy: 1353, 459 + xy: 1319, 357 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 unit-scepter-small rotate: false - xy: 1408, 228 + xy: 1603, 342 size: 24, 19 orig: 24, 19 offset: 0, 0 index: -1 unit-scepter-tiny rotate: false - xy: 662, 175 + xy: 1391, 218 size: 16, 13 orig: 16, 13 offset: 0, 0 index: -1 unit-scepter-xlarge rotate: false - xy: 601, 275 + xy: 651, 325 size: 48, 39 orig: 48, 39 offset: 0, 0 index: -1 unit-sei-large rotate: false - xy: 1007, 605 + xy: 923, 639 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-sei-medium rotate: false - xy: 1455, 521 + xy: 1489, 529 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-sei-small rotate: false - xy: 1434, 223 + xy: 1629, 337 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-sei-tiny rotate: false - xy: 1755, 349 + xy: 1699, 346 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-sei-xlarge rotate: false - xy: 651, 316 + xy: 701, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-spiroct-large rotate: false - xy: 1049, 648 + xy: 965, 648 size: 40, 31 orig: 40, 31 offset: 0, 0 index: -1 unit-spiroct-medium rotate: false - xy: 1387, 460 + xy: 1489, 425 size: 31, 25 orig: 31, 25 offset: 0, 0 index: -1 unit-spiroct-small rotate: false - xy: 1460, 228 + xy: 1655, 342 size: 24, 19 orig: 24, 19 offset: 0, 0 index: -1 unit-spiroct-tiny rotate: false - xy: 2022, 789 + xy: 2029, 647 size: 15, 12 orig: 15, 12 offset: 0, 0 index: -1 unit-spiroct-xlarge rotate: false - xy: 701, 376 + xy: 401, 50 size: 48, 38 orig: 48, 38 offset: 0, 0 index: -1 unit-toxopid-large rotate: false - xy: 1979, 891 + xy: 1536, 639 size: 33, 40 orig: 33, 40 offset: 0, 0 index: -1 unit-toxopid-medium rotate: false - xy: 2021, 755 + xy: 781, 682 size: 26, 32 orig: 26, 32 offset: 0, 0 index: -1 unit-toxopid-small rotate: false - xy: 1512, 213 + xy: 2027, 823 size: 20, 24 orig: 20, 24 offset: 0, 0 index: -1 unit-toxopid-tiny rotate: false - xy: 1791, 367 + xy: 1717, 347 size: 13, 16 orig: 13, 16 offset: 0, 0 index: -1 unit-toxopid-xlarge rotate: false - xy: 1049, 598 + xy: 1951, 841 size: 40, 48 orig: 40, 48 offset: 0, 0 index: -1 unit-vela-large rotate: false - xy: 1091, 647 + xy: 923, 605 size: 40, 32 orig: 40, 32 offset: 0, 0 index: -1 unit-vela-medium rotate: false - xy: 1217, 425 + xy: 1353, 357 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 unit-vela-small rotate: false - xy: 1486, 223 + xy: 1577, 325 size: 24, 19 orig: 24, 19 offset: 0, 0 index: -1 unit-vela-tiny rotate: false - xy: 482, 1 + xy: 814, 199 size: 16, 13 orig: 16, 13 offset: 0, 0 index: -1 unit-vela-xlarge rotate: false - xy: 501, 142 + xy: 451, 77 size: 48, 39 orig: 48, 39 offset: 0, 0 index: -1 unit-zenith-large rotate: false - xy: 1091, 605 + xy: 965, 606 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-zenith-medium rotate: false - xy: 1421, 487 + xy: 1387, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-zenith-small rotate: false - xy: 1460, 202 + xy: 1603, 316 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-zenith-tiny rotate: false - xy: 1773, 367 + xy: 1625, 180 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-zenith-xlarge rotate: false - xy: 551, 183 + xy: 501, 116 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 wavepane rotate: false - xy: 1589, 623 + xy: 1425, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -20934,7 +22845,7 @@ wavepane index: -1 white-pane rotate: false - xy: 1627, 652 + xy: 1463, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -20942,14 +22853,14 @@ white-pane index: -1 whiteui rotate: false - xy: 746, 371 + xy: 821, 928 size: 3, 3 orig: 3, 3 offset: 0, 0 index: -1 window-empty rotate: false - xy: 1073, 266 + xy: 980, 230 size: 27, 61 split: 4, 4, 2, 2 orig: 27, 61 diff --git a/core/assets/sprites/fallback/sprites4.png b/core/assets/sprites/fallback/sprites4.png index a54ba96e8b..45619c04fa 100644 Binary files a/core/assets/sprites/fallback/sprites4.png and b/core/assets/sprites/fallback/sprites4.png differ diff --git a/core/assets/sprites/fallback/sprites5.png b/core/assets/sprites/fallback/sprites5.png index c9946bf655..1b8a3ef066 100644 Binary files a/core/assets/sprites/fallback/sprites5.png and b/core/assets/sprites/fallback/sprites5.png differ diff --git a/core/assets/sprites/fallback/sprites6.png b/core/assets/sprites/fallback/sprites6.png index 43330a0028..a47c2d47eb 100644 Binary files a/core/assets/sprites/fallback/sprites6.png and b/core/assets/sprites/fallback/sprites6.png differ diff --git a/core/assets/sprites/fallback/sprites7.png b/core/assets/sprites/fallback/sprites7.png index 8ba18e157c..dd3d40dc80 100644 Binary files a/core/assets/sprites/fallback/sprites7.png and b/core/assets/sprites/fallback/sprites7.png differ diff --git a/core/assets/sprites/fallback/sprites8.png b/core/assets/sprites/fallback/sprites8.png index 4cb8e05377..212d169c38 100644 Binary files a/core/assets/sprites/fallback/sprites8.png and b/core/assets/sprites/fallback/sprites8.png differ diff --git a/core/assets/sprites/fog.png b/core/assets/sprites/fog.png new file mode 100644 index 0000000000..5121693e58 Binary files /dev/null and b/core/assets/sprites/fog.png differ diff --git a/core/assets/sprites/space.png b/core/assets/sprites/space.png new file mode 100644 index 0000000000..188e9e40ae Binary files /dev/null and b/core/assets/sprites/space.png differ diff --git a/core/assets/sprites/sprites.atlas b/core/assets/sprites/sprites.atlas index 303a643a31..75be83066e 100644 --- a/core/assets/sprites/sprites.atlas +++ b/core/assets/sprites/sprites.atlas @@ -7844,1456 +7844,3318 @@ filter: nearest,nearest repeat: none basalt-edge rotate: false - xy: 1, 149 + xy: 1, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 basalt1 rotate: false - xy: 2541, 213 + xy: 2739, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 basalt2 rotate: false - xy: 101, 17 + xy: 101, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 basalt3 rotate: false - xy: 2575, 213 + xy: 2773, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char1 rotate: false - xy: 135, 17 + xy: 135, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char2 rotate: false - xy: 2609, 213 + xy: 2807, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char3 rotate: false - xy: 169, 17 + xy: 169, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cliff rotate: false - xy: 2643, 213 + xy: 2841, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +cliff0 + rotate: false + xy: 1765, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask1 + rotate: false + xy: 1765, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask129 + rotate: false + xy: 1765, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask131 + rotate: false + xy: 1765, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask3 + rotate: false + xy: 1765, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff1 + rotate: false + xy: 1765, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask130 + rotate: false + xy: 1765, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask2 + rotate: false + xy: 1765, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff2 + rotate: false + xy: 1831, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask12 + rotate: false + xy: 1831, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask132 + rotate: false + xy: 1831, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask134 + rotate: false + xy: 1831, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask14 + rotate: false + xy: 1831, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask140 + rotate: false + xy: 1831, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask142 + rotate: false + xy: 1831, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask4 + rotate: false + xy: 1831, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask6 + rotate: false + xy: 1831, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff3 + rotate: false + xy: 1831, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff4 + rotate: false + xy: 1897, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff5 + rotate: false + xy: 1897, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff6 + rotate: false + xy: 1963, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliff7 + rotate: false + xy: 1963, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask0 + rotate: false + xy: 2029, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask128 + rotate: false + xy: 2029, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask10 + rotate: false + xy: 2161, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask138 + rotate: false + xy: 2161, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask112 + rotate: false + xy: 3151, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask120 + rotate: false + xy: 3151, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask113 + rotate: false + xy: 3217, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask115 + rotate: false + xy: 3217, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask121 + rotate: false + xy: 3217, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask123 + rotate: false + xy: 3217, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask114 + rotate: false + xy: 3217, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask122 + rotate: false + xy: 3217, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask116 + rotate: false + xy: 3283, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask118 + rotate: false + xy: 3283, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask117 + rotate: false + xy: 3283, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask119 + rotate: false + xy: 3283, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask124 + rotate: false + xy: 3349, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask126 + rotate: false + xy: 3349, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask125 + rotate: false + xy: 3349, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask127 + rotate: false + xy: 3349, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask16 + rotate: false + xy: 2161, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask144 + rotate: false + xy: 2161, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask152 + rotate: false + xy: 2161, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask176 + rotate: false + xy: 2161, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask184 + rotate: false + xy: 2161, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask24 + rotate: false + xy: 2161, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask48 + rotate: false + xy: 2161, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask56 + rotate: false + xy: 2161, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask17 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask145 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask147 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask153 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask155 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask177 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask179 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask185 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask187 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask19 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask25 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask27 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask49 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask51 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask57 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask59 + rotate: false + xy: 2227, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask18 + rotate: false + xy: 2227, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask146 + rotate: false + xy: 2227, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask154 + rotate: false + xy: 2227, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask178 + rotate: false + xy: 2227, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask186 + rotate: false + xy: 2227, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask26 + rotate: false + xy: 2227, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask50 + rotate: false + xy: 2227, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask58 + rotate: false + xy: 2227, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask192 + rotate: false + xy: 3415, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask224 + rotate: false + xy: 3415, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask193 + rotate: false + xy: 3415, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask195 + rotate: false + xy: 3415, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask225 + rotate: false + xy: 3415, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask227 + rotate: false + xy: 3415, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask194 + rotate: false + xy: 3481, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask226 + rotate: false + xy: 3481, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask196 + rotate: false + xy: 3481, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask198 + rotate: false + xy: 3481, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask204 + rotate: false + xy: 3481, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask206 + rotate: false + xy: 3481, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask228 + rotate: false + xy: 3481, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask230 + rotate: false + xy: 3481, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask236 + rotate: false + xy: 3481, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask238 + rotate: false + xy: 3481, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask197 + rotate: false + xy: 3547, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask199 + rotate: false + xy: 3547, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask205 + rotate: false + xy: 3547, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask207 + rotate: false + xy: 3547, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask229 + rotate: false + xy: 3547, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask231 + rotate: false + xy: 3547, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask237 + rotate: false + xy: 3547, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask239 + rotate: false + xy: 3547, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask20 + rotate: false + xy: 2293, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask148 + rotate: false + xy: 2293, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask150 + rotate: false + xy: 2293, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask180 + rotate: false + xy: 2293, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask182 + rotate: false + xy: 2293, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask22 + rotate: false + xy: 2293, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask52 + rotate: false + xy: 2293, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask54 + rotate: false + xy: 2293, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask200 + rotate: false + xy: 3547, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask232 + rotate: false + xy: 3547, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask201 + rotate: false + xy: 3613, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask203 + rotate: false + xy: 3613, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask233 + rotate: false + xy: 3613, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask235 + rotate: false + xy: 3613, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask202 + rotate: false + xy: 3613, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask234 + rotate: false + xy: 3613, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask208 + rotate: false + xy: 3679, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask216 + rotate: false + xy: 3679, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask209 + rotate: false + xy: 3679, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask211 + rotate: false + xy: 3679, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask217 + rotate: false + xy: 3679, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask219 + rotate: false + xy: 3679, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask21 + rotate: false + xy: 2293, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask149 + rotate: false + xy: 2293, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask151 + rotate: false + xy: 2293, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask181 + rotate: false + xy: 2293, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask183 + rotate: false + xy: 2293, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask23 + rotate: false + xy: 2293, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask53 + rotate: false + xy: 2293, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask55 + rotate: false + xy: 2293, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask210 + rotate: false + xy: 3745, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask218 + rotate: false + xy: 3745, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask212 + rotate: false + xy: 3745, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask214 + rotate: false + xy: 3745, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask213 + rotate: false + xy: 3811, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask215 + rotate: false + xy: 3811, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask220 + rotate: false + xy: 3811, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask222 + rotate: false + xy: 3811, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask221 + rotate: false + xy: 3877, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask223 + rotate: false + xy: 3877, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask240 + rotate: false + xy: 3877, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask248 + rotate: false + xy: 3877, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask241 + rotate: false + xy: 3943, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask243 + rotate: false + xy: 3943, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask249 + rotate: false + xy: 3943, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask251 + rotate: false + xy: 3943, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask242 + rotate: false + xy: 3943, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask250 + rotate: false + xy: 3943, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask244 + rotate: false + xy: 4009, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask246 + rotate: false + xy: 4009, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask245 + rotate: false + xy: 4009, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask247 + rotate: false + xy: 4009, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask252 + rotate: false + xy: 1765, 53 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask254 + rotate: false + xy: 1765, 53 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask253 + rotate: false + xy: 1831, 53 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask255 + rotate: false + xy: 1831, 53 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask28 + rotate: false + xy: 2359, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask156 + rotate: false + xy: 2359, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask158 + rotate: false + xy: 2359, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask188 + rotate: false + xy: 2359, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask190 + rotate: false + xy: 2359, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask30 + rotate: false + xy: 2359, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask60 + rotate: false + xy: 2359, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask62 + rotate: false + xy: 2359, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask29 + rotate: false + xy: 2359, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask157 + rotate: false + xy: 2359, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask159 + rotate: false + xy: 2359, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask189 + rotate: false + xy: 2359, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask191 + rotate: false + xy: 2359, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask31 + rotate: false + xy: 2359, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask61 + rotate: false + xy: 2359, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask63 + rotate: false + xy: 2359, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask32 + rotate: false + xy: 2425, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask160 + rotate: false + xy: 2425, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask33 + rotate: false + xy: 2425, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask161 + rotate: false + xy: 2425, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask163 + rotate: false + xy: 2425, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask35 + rotate: false + xy: 2425, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask34 + rotate: false + xy: 2491, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask162 + rotate: false + xy: 2491, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask36 + rotate: false + xy: 2491, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask164 + rotate: false + xy: 2491, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask166 + rotate: false + xy: 2491, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask172 + rotate: false + xy: 2491, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask174 + rotate: false + xy: 2491, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask38 + rotate: false + xy: 2491, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask44 + rotate: false + xy: 2491, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask46 + rotate: false + xy: 2491, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask37 + rotate: false + xy: 2557, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask165 + rotate: false + xy: 2557, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask167 + rotate: false + xy: 2557, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask173 + rotate: false + xy: 2557, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask175 + rotate: false + xy: 2557, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask39 + rotate: false + xy: 2557, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask45 + rotate: false + xy: 2557, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask47 + rotate: false + xy: 2557, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask40 + rotate: false + xy: 2557, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask168 + rotate: false + xy: 2557, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask41 + rotate: false + xy: 2623, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask169 + rotate: false + xy: 2623, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask171 + rotate: false + xy: 2623, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask43 + rotate: false + xy: 2623, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask42 + rotate: false + xy: 2623, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask170 + rotate: false + xy: 2623, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask5 + rotate: false + xy: 2029, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask13 + rotate: false + xy: 2029, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask133 + rotate: false + xy: 2029, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask135 + rotate: false + xy: 2029, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask141 + rotate: false + xy: 2029, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask143 + rotate: false + xy: 2029, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask15 + rotate: false + xy: 2029, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask7 + rotate: false + xy: 2029, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask64 + rotate: false + xy: 2689, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask96 + rotate: false + xy: 2689, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask65 + rotate: false + xy: 2689, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask67 + rotate: false + xy: 2689, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask97 + rotate: false + xy: 2689, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask99 + rotate: false + xy: 2689, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask66 + rotate: false + xy: 2755, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask98 + rotate: false + xy: 2755, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask68 + rotate: false + xy: 2755, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask100 + rotate: false + xy: 2755, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask102 + rotate: false + xy: 2755, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask108 + rotate: false + xy: 2755, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask110 + rotate: false + xy: 2755, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask70 + rotate: false + xy: 2755, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask76 + rotate: false + xy: 2755, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask78 + rotate: false + xy: 2755, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask69 + rotate: false + xy: 2821, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask101 + rotate: false + xy: 2821, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask103 + rotate: false + xy: 2821, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask109 + rotate: false + xy: 2821, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask111 + rotate: false + xy: 2821, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask71 + rotate: false + xy: 2821, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask77 + rotate: false + xy: 2821, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask79 + rotate: false + xy: 2821, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask72 + rotate: false + xy: 2821, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask104 + rotate: false + xy: 2821, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask73 + rotate: false + xy: 2887, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask105 + rotate: false + xy: 2887, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask107 + rotate: false + xy: 2887, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask75 + rotate: false + xy: 2887, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask74 + rotate: false + xy: 2887, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask106 + rotate: false + xy: 2887, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask8 + rotate: false + xy: 2095, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask136 + rotate: false + xy: 2095, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask80 + rotate: false + xy: 2953, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask88 + rotate: false + xy: 2953, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask81 + rotate: false + xy: 2953, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask83 + rotate: false + xy: 2953, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask89 + rotate: false + xy: 2953, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask91 + rotate: false + xy: 2953, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask82 + rotate: false + xy: 3019, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask90 + rotate: false + xy: 3019, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask84 + rotate: false + xy: 3019, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask86 + rotate: false + xy: 3019, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask85 + rotate: false + xy: 3085, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask87 + rotate: false + xy: 3085, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask9 + rotate: false + xy: 2095, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask11 + rotate: false + xy: 2095, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask137 + rotate: false + xy: 2095, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask139 + rotate: false + xy: 2095, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask92 + rotate: false + xy: 3085, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask94 + rotate: false + xy: 3085, 119 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask93 + rotate: false + xy: 3151, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +cliffmask95 + rotate: false + xy: 3151, 185 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 coal1 rotate: false - xy: 203, 17 + xy: 203, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 coal2 rotate: false - xy: 2677, 213 + xy: 2875, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 coal3 rotate: false - xy: 237, 17 + xy: 237, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper1 rotate: false - xy: 2711, 213 + xy: 2909, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper2 rotate: false - xy: 271, 17 + xy: 271, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper3 rotate: false - xy: 2745, 213 + xy: 2943, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters1 rotate: false - xy: 305, 17 + xy: 305, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters2 rotate: false - xy: 2779, 213 + xy: 2977, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters3 rotate: false - xy: 339, 17 + xy: 339, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters4 rotate: false - xy: 2813, 213 + xy: 3011, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters5 rotate: false - xy: 373, 17 + xy: 373, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters6 rotate: false - xy: 2847, 213 + xy: 3045, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite-edge rotate: false - xy: 1, 51 + xy: 1, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dacite-wall-large rotate: false - xy: 1667, 83 + xy: 1897, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dacite-wall1 rotate: false - xy: 2915, 213 + xy: 3113, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite-wall2 rotate: false - xy: 475, 17 + xy: 475, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite1 rotate: false - xy: 407, 17 + xy: 407, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite2 rotate: false - xy: 2881, 213 + xy: 3079, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dacite3 rotate: false - xy: 441, 17 + xy: 441, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-metal-large rotate: false - xy: 1765, 181 + xy: 1963, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dark-metal1 rotate: false - xy: 2949, 213 + xy: 3147, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-metal2 rotate: false - xy: 509, 17 + xy: 509, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-1 rotate: false - xy: 2983, 213 + xy: 3181, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-1-edge rotate: false - xy: 99, 149 + xy: 99, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-2 rotate: false - xy: 543, 17 + xy: 543, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-2-edge rotate: false - xy: 99, 51 + xy: 99, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-3 rotate: false - xy: 3017, 213 + xy: 3215, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-3-edge rotate: false - xy: 197, 149 + xy: 197, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-4 rotate: false - xy: 577, 17 + xy: 577, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-4-edge rotate: false - xy: 197, 51 + xy: 197, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-5 rotate: false - xy: 3051, 213 + xy: 3249, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-5-edge rotate: false - xy: 295, 149 + xy: 295, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dark-panel-6 rotate: false - xy: 611, 17 + xy: 611, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-6-edge rotate: false - xy: 295, 51 + xy: 295, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 darksand-edge rotate: false - xy: 393, 149 + xy: 393, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 darksand-tainted-water rotate: false - xy: 679, 17 + xy: 679, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water-edge rotate: false - xy: 393, 51 + xy: 393, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 darksand-tainted-water1 rotate: false - xy: 3153, 213 + xy: 3351, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water2 rotate: false - xy: 713, 17 + xy: 713, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water3 rotate: false - xy: 3187, 213 + xy: 3385, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water rotate: false - xy: 747, 17 + xy: 747, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water-edge rotate: false - xy: 491, 149 + xy: 491, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 darksand-water1 rotate: false - xy: 3221, 213 + xy: 3419, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water2 rotate: false - xy: 781, 17 + xy: 781, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water3 rotate: false - xy: 3255, 213 + xy: 3453, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand1 rotate: false - xy: 3085, 213 + xy: 3283, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand2 rotate: false - xy: 645, 17 + xy: 645, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand3 rotate: false - xy: 3119, 213 + xy: 3317, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 deepwater rotate: false - xy: 815, 17 + xy: 815, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 deepwater-edge rotate: false - xy: 491, 51 + xy: 491, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dirt-edge rotate: false - xy: 589, 149 + xy: 589, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dirt-wall-large rotate: false - xy: 1831, 181 + xy: 2029, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dirt-wall1 rotate: false - xy: 883, 17 + xy: 883, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dirt-wall2 rotate: false - xy: 3357, 213 + xy: 3555, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dirt1 rotate: false - xy: 3289, 213 + xy: 3487, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dirt2 rotate: false - xy: 849, 17 + xy: 849, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dirt3 rotate: false - xy: 3323, 213 + xy: 3521, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dune-wall-large rotate: false - xy: 1897, 181 + xy: 2095, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dune-wall1 rotate: false - xy: 917, 17 + xy: 917, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dune-wall2 rotate: false - xy: 3391, 213 + xy: 3589, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 edge rotate: false - xy: 951, 17 + xy: 951, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 edge-stencil rotate: false - xy: 589, 51 + xy: 589, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 edgier rotate: false - xy: 3425, 213 + xy: 3623, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass-edge rotate: false - xy: 687, 149 + xy: 687, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 grass1 rotate: false - xy: 985, 17 + xy: 985, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass2 rotate: false - xy: 3459, 213 + xy: 3657, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass3 rotate: false - xy: 1019, 17 + xy: 1019, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock1 rotate: false - xy: 3493, 213 + xy: 3691, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock2 rotate: false - xy: 1053, 17 + xy: 1053, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock3 rotate: false - xy: 3527, 213 + xy: 3725, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-edge rotate: false - xy: 687, 51 + xy: 687, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ice-snow-edge rotate: false - xy: 785, 149 + xy: 785, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ice-snow1 rotate: false - xy: 3595, 213 + xy: 3793, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-snow2 rotate: false - xy: 1155, 17 + xy: 1155, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-snow3 rotate: false - xy: 3629, 213 + xy: 3827, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-wall-large rotate: false - xy: 1963, 181 + xy: 2161, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 ice-wall1 rotate: false - xy: 1189, 17 + xy: 1189, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-wall2 rotate: false - xy: 3663, 213 + xy: 3861, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice1 rotate: false - xy: 1087, 17 + xy: 1087, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice2 rotate: false - xy: 3561, 213 + xy: 3759, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice3 rotate: false - xy: 1121, 17 + xy: 1121, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 lead1 rotate: false - xy: 1223, 17 + xy: 1223, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 lead2 rotate: false - xy: 3697, 213 + xy: 3895, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 lead3 rotate: false - xy: 1257, 17 + xy: 1257, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock1 rotate: false - xy: 3731, 213 + xy: 3929, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock2 rotate: false - xy: 1291, 17 + xy: 1291, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock3 rotate: false - xy: 3765, 213 + xy: 3963, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor rotate: false - xy: 1325, 17 + xy: 1325, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-2 rotate: false - xy: 3799, 213 + xy: 3997, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-2-edge rotate: false - xy: 785, 51 + xy: 785, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 metal-floor-3 rotate: false - xy: 1359, 17 + xy: 1359, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-3-edge rotate: false - xy: 883, 149 + xy: 883, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 metal-floor-5 rotate: false - xy: 3833, 213 + xy: 4031, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-5-edge rotate: false - xy: 883, 51 + xy: 883, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 metal-floor-damaged-edge rotate: false - xy: 981, 149 + xy: 981, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 metal-floor-damaged1 rotate: false - xy: 1393, 17 + xy: 1393, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-damaged2 rotate: false - xy: 3867, 213 + xy: 1427, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-damaged3 rotate: false - xy: 1427, 17 + xy: 1461, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-edge rotate: false - xy: 981, 51 + xy: 981, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 moss-edge rotate: false - xy: 1079, 149 + xy: 1079, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 moss1 rotate: false - xy: 3901, 213 + xy: 1495, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 moss2 rotate: false - xy: 1461, 17 + xy: 1529, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 moss3 rotate: false - xy: 3935, 213 + xy: 1563, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mud-edge rotate: false - xy: 1079, 51 + xy: 1079, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mud1 rotate: false - xy: 1495, 17 + xy: 1597, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mud2 rotate: false - xy: 3969, 213 + xy: 1631, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mud3 rotate: false - xy: 1529, 17 + xy: 1665, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-coal1 rotate: false - xy: 4003, 213 + xy: 1699, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-coal2 rotate: false - xy: 1563, 17 + xy: 2689, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-coal3 rotate: false - xy: 4037, 213 + xy: 2739, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-copper1 rotate: false - xy: 1597, 17 + xy: 2773, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-copper2 rotate: false - xy: 1631, 17 + xy: 2807, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-copper3 rotate: false - xy: 1667, 49 + xy: 2841, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-lead1 rotate: false - xy: 1733, 115 + xy: 2875, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-lead2 rotate: false - xy: 1701, 49 + xy: 2909, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-lead3 rotate: false - xy: 1665, 15 + xy: 2943, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-scrap1 rotate: false - xy: 1699, 15 + xy: 2977, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-scrap2 rotate: false - xy: 2491, 163 + xy: 3011, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-scrap3 rotate: false - xy: 2541, 179 + xy: 3045, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-thorium1 rotate: false - xy: 2575, 179 + xy: 3079, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-thorium2 rotate: false - xy: 2609, 179 + xy: 3113, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-thorium3 rotate: false - xy: 2643, 179 + xy: 3147, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-titanium1 rotate: false - xy: 2677, 179 + xy: 3181, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-titanium2 rotate: false - xy: 2711, 179 + xy: 3215, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-titanium3 rotate: false - xy: 2745, 179 + xy: 3249, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pebbles1 rotate: false - xy: 2779, 179 + xy: 3283, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pebbles2 rotate: false - xy: 2813, 179 + xy: 3317, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pebbles3 rotate: false - xy: 2847, 179 + xy: 3351, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pine rotate: false - xy: 1, 1 + xy: 1, 5 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 salt rotate: false - xy: 2881, 179 + xy: 3385, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salt-edge rotate: false - xy: 1177, 149 + xy: 1177, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 salt-wall-large rotate: false - xy: 2029, 181 + xy: 2227, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 salt-wall1 rotate: false - xy: 2915, 179 + xy: 3419, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salt-wall2 rotate: false - xy: 2949, 179 + xy: 3453, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-edge rotate: false - xy: 1177, 51 + xy: 1177, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 sand-wall-large rotate: false - xy: 2095, 181 + xy: 2293, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sand-wall1 rotate: false - xy: 3085, 179 + xy: 3589, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-wall2 rotate: false - xy: 3119, 179 + xy: 3623, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water rotate: false - xy: 3153, 179 + xy: 3657, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water-edge rotate: false - xy: 1275, 149 + xy: 1275, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 sand-water1 rotate: false - xy: 3187, 179 + xy: 3691, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water2 rotate: false - xy: 3221, 179 + xy: 3725, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water3 rotate: false - xy: 3255, 179 + xy: 3759, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand1 rotate: false - xy: 2983, 179 + xy: 3487, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand2 rotate: false - xy: 3017, 179 + xy: 3521, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand3 rotate: false - xy: 3051, 179 + xy: 3555, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap1 rotate: false - xy: 3289, 179 + xy: 3793, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap2 rotate: false - xy: 3323, 179 + xy: 3827, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap3 rotate: false - xy: 3357, 179 + xy: 3861, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-edge rotate: false - xy: 1275, 51 + xy: 1275, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 shale-wall-large rotate: false - xy: 2161, 181 + xy: 2359, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shale-wall1 rotate: false - xy: 3493, 179 + xy: 3997, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-wall2 rotate: false - xy: 3527, 179 + xy: 4031, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale1 rotate: false - xy: 3391, 179 + xy: 3895, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale2 rotate: false - xy: 3425, 179 + xy: 3929, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale3 rotate: false - xy: 3459, 179 + xy: 3963, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs-large rotate: false - xy: 2227, 181 + xy: 2425, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shrubs1 rotate: false - xy: 3561, 179 + xy: 1733, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs2 rotate: false - xy: 3595, 179 + xy: 1767, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 slag rotate: false - xy: 3629, 179 + xy: 1801, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 slag-edge rotate: false - xy: 1373, 149 + xy: 1373, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 snow-edge rotate: false - xy: 1373, 51 + xy: 1373, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 snow-pine rotate: false - xy: 2491, 197 + xy: 2689, 69 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snow-wall-large rotate: false - xy: 2293, 181 + xy: 2491, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 snow-wall1 rotate: false - xy: 3765, 179 + xy: 1937, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow-wall2 rotate: false - xy: 3799, 179 + xy: 1971, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow1 rotate: false - xy: 3663, 179 + xy: 1835, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow2 rotate: false - xy: 3697, 179 + xy: 1869, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow3 rotate: false - xy: 3731, 179 + xy: 1903, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +space + rotate: false + xy: 2005, 19 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +space-edge + rotate: false + xy: 1471, 153 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 spawn rotate: false - xy: 3833, 179 + xy: 2039, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss-edge rotate: false - xy: 1471, 149 + xy: 1471, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 spore-moss1 rotate: false - xy: 3867, 179 + xy: 2073, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss2 rotate: false - xy: 3901, 179 + xy: 2107, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss3 rotate: false - xy: 3935, 179 + xy: 2141, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-pine rotate: false - xy: 51, 1 + xy: 51, 5 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-wall-large rotate: false - xy: 2359, 181 + xy: 2557, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-wall1 rotate: false - xy: 3969, 179 + xy: 2175, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-wall2 rotate: false - xy: 4003, 179 + xy: 2209, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone-edge rotate: false - xy: 1471, 51 + xy: 1569, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 stone-wall-large rotate: false - xy: 2425, 181 + xy: 2623, 53 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 stone-wall1 rotate: false - xy: 1801, 147 + xy: 2345, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone-wall2 rotate: false - xy: 1835, 147 + xy: 2379, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone1 rotate: false - xy: 4037, 179 + xy: 2243, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone2 rotate: false - xy: 1733, 15 + xy: 2277, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone3 rotate: false - xy: 1767, 147 + xy: 2311, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tainted-water rotate: false - xy: 1869, 147 + xy: 2413, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tainted-water-edge rotate: false - xy: 1569, 149 + xy: 1569, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 tar rotate: false - xy: 1903, 147 + xy: 2447, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tar-edge rotate: false - xy: 1569, 51 + xy: 1667, 153 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 tendrils1 rotate: false - xy: 1937, 147 + xy: 2481, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tendrils2 rotate: false - xy: 1971, 147 + xy: 2515, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tendrils3 rotate: false - xy: 2005, 147 + xy: 2549, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium1 rotate: false - xy: 2039, 147 + xy: 2583, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium2 rotate: false - xy: 2073, 147 + xy: 2617, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium3 rotate: false - xy: 2107, 147 + xy: 2651, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium1 rotate: false - xy: 2141, 147 + xy: 2685, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium2 rotate: false - xy: 2175, 147 + xy: 2719, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium3 rotate: false - xy: 2209, 147 + xy: 2753, 17 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water rotate: false - xy: 2243, 147 + xy: 2787, 17 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water-edge rotate: false - xy: 1667, 149 + xy: 1667, 55 size: 96, 96 orig: 96, 96 offset: 0, 0 @@ -10487,128 +12349,142 @@ editor-snow3 orig: 32, 32 offset: 0, 0 index: -1 -editor-spawn +editor-space rotate: false xy: 2331, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +space-icon-editor + rotate: false + xy: 2331, 263 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +editor-spawn + rotate: false + xy: 2365, 263 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 editor-spore-moss1 - rotate: false - xy: 2365, 263 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -spore-moss-icon-editor - rotate: false - xy: 2365, 263 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -editor-spore-moss2 rotate: false xy: 2399, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -editor-spore-moss3 +spore-moss-icon-editor + rotate: false + xy: 2399, 263 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +editor-spore-moss2 rotate: false xy: 2433, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +editor-spore-moss3 + rotate: false + xy: 2467, 263 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 editor-stone1 - rotate: false - xy: 2467, 263 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -stone-icon-editor - rotate: false - xy: 2467, 263 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -editor-stone2 rotate: false xy: 2501, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -editor-stone3 +stone-icon-editor + rotate: false + xy: 2501, 263 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +editor-stone2 rotate: false xy: 2535, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -editor-tainted-water +editor-stone3 rotate: false xy: 2569, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +editor-tainted-water + rotate: false + xy: 2603, 263 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 tainted-water-icon-editor rotate: false - xy: 2569, 263 + xy: 2603, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tar rotate: false - xy: 2603, 263 + xy: 2637, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tar-icon-editor rotate: false - xy: 2603, 263 + xy: 2637, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils1 rotate: false - xy: 2637, 263 + xy: 2671, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils2 rotate: false - xy: 2671, 263 + xy: 2705, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils3 rotate: false - xy: 2705, 263 + xy: 2739, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-water rotate: false - xy: 2739, 263 + xy: 2773, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water-icon-editor rotate: false - xy: 2739, 263 + xy: 2773, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10657,7 +12533,7 @@ ground-factory-icon-editor index: -1 hail-icon-editor rotate: false - xy: 2773, 263 + xy: 2807, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10671,14 +12547,14 @@ hyper-processor-icon-editor index: -1 ice-wall-icon-editor rotate: false - xy: 2807, 263 + xy: 2841, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 illuminator-icon-editor rotate: false - xy: 2841, 263 + xy: 2875, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10692,35 +12568,35 @@ impact-reactor-icon-editor index: -1 incinerator-icon-editor rotate: false - xy: 2875, 263 + xy: 2909, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 inverted-sorter-icon-editor rotate: false - xy: 2909, 263 + xy: 2943, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source-icon-editor rotate: false - xy: 2943, 263 + xy: 2977, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void-icon-editor rotate: false - xy: 2977, 263 + xy: 3011, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 junction-icon-editor rotate: false - xy: 3011, 263 + xy: 3045, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10769,21 +12645,21 @@ launch-pad-large-icon-editor index: -1 liquid-junction-icon-editor rotate: false - xy: 3045, 263 + xy: 3079, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-icon-editor rotate: false - xy: 3079, 263 + xy: 3113, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-source-icon-editor rotate: false - xy: 3113, 263 + xy: 3147, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10797,7 +12673,7 @@ liquid-tank-icon-editor index: -1 liquid-void-icon-editor rotate: false - xy: 3147, 263 + xy: 3181, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10832,7 +12708,7 @@ mechanical-drill-icon-editor index: -1 mechanical-pump-icon-editor rotate: false - xy: 3181, 263 + xy: 3215, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10846,7 +12722,7 @@ meltdown-icon-editor index: -1 melter-icon-editor rotate: false - xy: 3215, 263 + xy: 3249, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10860,7 +12736,7 @@ memory-bank-icon-editor index: -1 memory-cell-icon-editor rotate: false - xy: 3249, 263 + xy: 3283, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10874,21 +12750,21 @@ mend-projector-icon-editor index: -1 mender-icon-editor rotate: false - xy: 3283, 263 + xy: 3317, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 message-icon-editor rotate: false - xy: 3317, 263 + xy: 3351, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 micro-processor-icon-editor rotate: false - xy: 3351, 263 + xy: 3385, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10937,7 +12813,7 @@ overdrive-projector-icon-editor index: -1 overflow-gate-icon-editor rotate: false - xy: 3385, 263 + xy: 3419, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -10965,28 +12841,28 @@ payload-router-icon-editor index: -1 pebbles-icon-editor rotate: false - xy: 3419, 263 + xy: 3453, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-icon-editor rotate: false - xy: 3453, 263 + xy: 3487, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-icon-editor rotate: false - xy: 3487, 263 + xy: 3521, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-icon-editor rotate: false - xy: 3521, 263 + xy: 3555, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11021,14 +12897,14 @@ plastanium-compressor-icon-editor index: -1 plastanium-conveyor-icon-editor rotate: false - xy: 3555, 263 + xy: 3589, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-wall-icon-editor rotate: false - xy: 3589, 263 + xy: 3623, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11042,7 +12918,7 @@ plastanium-wall-large-icon-editor index: -1 plated-conduit-icon-editor rotate: false - xy: 3623, 263 + xy: 3657, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11056,7 +12932,7 @@ pneumatic-drill-icon-editor index: -1 power-node-icon-editor rotate: false - xy: 3657, 263 + xy: 3691, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11070,28 +12946,28 @@ power-node-large-icon-editor index: -1 power-source-icon-editor rotate: false - xy: 3691, 263 + xy: 3725, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void-icon-editor rotate: false - xy: 3725, 263 + xy: 3759, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-icon-editor rotate: false - xy: 3759, 263 + xy: 3793, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-icon-editor rotate: false - xy: 3793, 263 + xy: 3827, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11105,7 +12981,7 @@ pyratite-mixer-icon-editor index: -1 repair-point-icon-editor rotate: false - xy: 3827, 263 + xy: 3861, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11133,7 +13009,7 @@ rotary-pump-icon-editor index: -1 router-icon-editor rotate: false - xy: 3861, 263 + xy: 3895, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11147,7 +13023,7 @@ rtg-generator-icon-editor index: -1 salt-wall-icon-editor rotate: false - xy: 3895, 263 + xy: 3929, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11161,21 +13037,21 @@ salvo-icon-editor index: -1 sand-boulder-icon-editor rotate: false - xy: 3929, 263 + xy: 3963, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-wall-icon-editor rotate: false - xy: 3963, 263 + xy: 3997, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water-icon-editor rotate: false - xy: 3997, 263 + xy: 4031, 263 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11189,7 +13065,7 @@ scatter-icon-editor index: -1 scorch-icon-editor rotate: false - xy: 4031, 263 + xy: 2263, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11210,7 +13086,7 @@ scrap-wall-huge-icon-editor index: -1 scrap-wall-icon-editor rotate: false - xy: 2263, 229 + xy: 2297, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11238,28 +13114,28 @@ separator-icon-editor index: -1 shale-boulder-icon-editor rotate: false - xy: 2297, 229 + xy: 2331, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-wall-icon-editor rotate: false - xy: 2331, 229 + xy: 2365, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shock-mine-icon-editor rotate: false - xy: 2365, 229 + xy: 2399, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs-icon-editor rotate: false - xy: 2399, 229 + xy: 2433, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11287,7 +13163,7 @@ snow-boulder-icon-editor index: -1 snow-icon-editor rotate: false - xy: 2433, 229 + xy: 2467, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11301,14 +13177,14 @@ snow-pine-icon-editor index: -1 snow-wall-icon-editor rotate: false - xy: 2467, 229 + xy: 2501, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-icon-editor rotate: false - xy: 2501, 229 + xy: 2535, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11322,14 +13198,14 @@ solar-panel-large-icon-editor index: -1 sorter-icon-editor rotate: false - xy: 2535, 229 + xy: 2569, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spawn-icon-editor rotate: false - xy: 2569, 229 + xy: 2603, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11364,7 +13240,7 @@ spore-press-icon-editor index: -1 spore-wall-icon-editor rotate: false - xy: 2603, 229 + xy: 2637, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11378,7 +13254,7 @@ steam-generator-icon-editor index: -1 stone-wall-icon-editor rotate: false - xy: 2637, 229 + xy: 2671, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11392,7 +13268,7 @@ surge-tower-icon-editor index: -1 surge-wall-icon-editor rotate: false - xy: 2671, 229 + xy: 2705, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11413,14 +13289,14 @@ swarmer-icon-editor index: -1 switch-icon-editor rotate: false - xy: 2705, 229 + xy: 2739, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tendrils-icon-editor rotate: false - xy: 2739, 229 + xy: 2773, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11455,7 +13331,7 @@ thorium-reactor-icon-editor index: -1 thorium-wall-icon-editor rotate: false - xy: 2773, 229 + xy: 2807, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11476,14 +13352,14 @@ thruster-icon-editor index: -1 titanium-conveyor-icon-editor rotate: false - xy: 2807, 229 + xy: 2841, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-icon-editor rotate: false - xy: 2841, 229 + xy: 2875, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11504,14 +13380,14 @@ tsunami-icon-editor index: -1 underflow-gate-icon-editor rotate: false - xy: 2875, 229 + xy: 2909, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unloader-icon-editor rotate: false - xy: 2909, 229 + xy: 2943, 229 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -11566,7 +13442,7 @@ alpha-bg index: -1 bar rotate: false - xy: 1869, 1 + xy: 2343, 150 size: 27, 36 split: 9, 9, 9, 9 orig: 27, 36 @@ -11574,7 +13450,7 @@ bar index: -1 bar-top rotate: false - xy: 1801, 1 + xy: 3550, 139 size: 27, 36 split: 9, 10, 9, 10 orig: 27, 36 @@ -11582,28 +13458,28 @@ bar-top index: -1 block-additive-reconstructor-large rotate: false - xy: 1078, 371 + xy: 1004, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-additive-reconstructor-medium rotate: false - xy: 881, 1 + xy: 3587, 253 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-additive-reconstructor-small rotate: false - xy: 3682, 351 + xy: 1605, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-additive-reconstructor-tiny rotate: false - xy: 3640, 395 + xy: 881, 1 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11617,28 +13493,28 @@ block-additive-reconstructor-xlarge index: -1 block-air-factory-large rotate: false - xy: 1120, 371 + xy: 1046, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-air-factory-medium rotate: false - xy: 915, 1 + xy: 3621, 253 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-air-factory-small rotate: false - xy: 1186, 7 + xy: 1731, 96 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-air-factory-tiny rotate: false - xy: 3640, 377 + xy: 309, 160 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11652,28 +13528,28 @@ block-air-factory-xlarge index: -1 block-alloy-smelter-large rotate: false - xy: 1162, 371 + xy: 1004, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-alloy-smelter-medium rotate: false - xy: 3464, 295 + xy: 3655, 253 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-alloy-smelter-small rotate: false - xy: 1898, 1 + xy: 1731, 70 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-alloy-smelter-tiny rotate: false - xy: 1060, 7 + xy: 2169, 29 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11687,28 +13563,28 @@ block-alloy-smelter-xlarge index: -1 block-arc-large rotate: false - xy: 1204, 371 + xy: 1088, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-arc-medium rotate: false - xy: 3498, 295 + xy: 901, 155 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-arc-small rotate: false - xy: 1212, 7 + xy: 1731, 44 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-arc-tiny rotate: false - xy: 2287, 193 + xy: 2187, 29 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11722,28 +13598,28 @@ block-arc-xlarge index: -1 block-armored-conveyor-large rotate: false - xy: 1246, 371 + xy: 1046, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-armored-conveyor-medium rotate: false - xy: 3532, 295 + xy: 935, 153 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-armored-conveyor-small rotate: false - xy: 1924, 1 + xy: 3810, 245 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-armored-conveyor-tiny rotate: false - xy: 309, 160 + xy: 2205, 29 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11757,28 +13633,28 @@ block-armored-conveyor-xlarge index: -1 block-basalt-large rotate: false - xy: 1288, 371 + xy: 1130, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-basalt-medium rotate: false - xy: 3566, 295 + xy: 969, 153 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-basalt-small rotate: false - xy: 1950, 1 + xy: 2372, 162 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-basalt-tiny rotate: false - xy: 2305, 193 + xy: 2223, 29 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11792,35 +13668,35 @@ block-basalt-xlarge index: -1 block-battery-large rotate: false - xy: 1330, 371 + xy: 1088, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-battery-large-large rotate: false - xy: 1372, 371 + xy: 1172, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-battery-large-medium rotate: false - xy: 3600, 295 + xy: 2639, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-battery-large-small rotate: false - xy: 1976, 1 + xy: 2372, 136 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-battery-large-tiny rotate: false - xy: 2323, 193 + xy: 2241, 29 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11834,21 +13710,21 @@ block-battery-large-xlarge index: -1 block-battery-medium rotate: false - xy: 2287, 211 + xy: 2673, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-battery-small rotate: false - xy: 2002, 1 + xy: 2398, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-battery-tiny rotate: false - xy: 2341, 193 + xy: 2259, 29 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11862,28 +13738,28 @@ block-battery-xlarge index: -1 block-blast-drill-large rotate: false - xy: 1414, 371 + xy: 1130, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-blast-drill-medium rotate: false - xy: 2321, 211 + xy: 2707, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-blast-drill-small rotate: false - xy: 2028, 1 + xy: 2424, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-blast-drill-tiny rotate: false - xy: 2359, 193 + xy: 2277, 29 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11897,28 +13773,28 @@ block-blast-drill-xlarge index: -1 block-blast-mixer-large rotate: false - xy: 1456, 371 + xy: 1214, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-blast-mixer-medium rotate: false - xy: 938, 161 + xy: 2741, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-blast-mixer-small rotate: false - xy: 2054, 1 + xy: 2398, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-blast-mixer-tiny rotate: false - xy: 2594, 71 + xy: 257, 2 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11932,28 +13808,28 @@ block-blast-mixer-xlarge index: -1 block-block-forge-large rotate: false - xy: 1498, 371 + xy: 1172, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-block-forge-medium rotate: false - xy: 972, 161 + xy: 2775, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-block-forge-small rotate: false - xy: 1830, 7 + xy: 2424, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-block-forge-tiny rotate: false - xy: 2594, 53 + xy: 2384, 81 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -11967,28 +13843,28 @@ block-block-forge-xlarge index: -1 block-block-loader-large rotate: false - xy: 1540, 371 + xy: 1256, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-block-loader-medium rotate: false - xy: 1006, 161 + xy: 2809, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-block-loader-small rotate: false - xy: 3711, 192 + xy: 3825, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-block-loader-tiny rotate: false - xy: 2594, 35 + xy: 2402, 81 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12002,28 +13878,28 @@ block-block-loader-xlarge index: -1 block-block-unloader-large rotate: false - xy: 1582, 371 + xy: 1214, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-block-unloader-medium rotate: false - xy: 1040, 161 + xy: 2843, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-block-unloader-small rotate: false - xy: 1238, 7 + xy: 3836, 245 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-block-unloader-tiny rotate: false - xy: 2491, 184 + xy: 2420, 81 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12037,28 +13913,28 @@ block-block-unloader-xlarge index: -1 block-boulder-large rotate: false - xy: 1624, 371 + xy: 1298, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-boulder-medium rotate: false - xy: 1074, 169 + xy: 2877, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-boulder-small rotate: false - xy: 1264, 16 + xy: 3825, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-boulder-tiny rotate: false - xy: 3757, 345 + xy: 2438, 81 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12072,28 +13948,28 @@ block-boulder-xlarge index: -1 block-bridge-conduit-large rotate: false - xy: 1666, 371 + xy: 1256, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-bridge-conduit-medium rotate: false - xy: 1108, 169 + xy: 2911, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-bridge-conduit-small rotate: false - xy: 1290, 7 + xy: 3824, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-bridge-conduit-tiny rotate: false - xy: 3775, 345 + xy: 2381, 63 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12107,28 +13983,28 @@ block-bridge-conduit-xlarge index: -1 block-bridge-conveyor-large rotate: false - xy: 1708, 371 + xy: 1340, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-bridge-conveyor-medium rotate: false - xy: 1142, 169 + xy: 2945, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-bridge-conveyor-small rotate: false - xy: 1316, 7 + xy: 3851, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-bridge-conveyor-tiny rotate: false - xy: 2594, 17 + xy: 2381, 45 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12142,28 +14018,28 @@ block-bridge-conveyor-xlarge index: -1 block-char-large rotate: false - xy: 1750, 371 + xy: 1298, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-char-medium rotate: false - xy: 1176, 169 + xy: 2979, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-char-small rotate: false - xy: 1342, 7 + xy: 3851, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-char-tiny rotate: false - xy: 2568, 7 + xy: 2399, 63 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12177,28 +14053,28 @@ block-char-xlarge index: -1 block-cliff-large rotate: false - xy: 1792, 371 + xy: 1382, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cliff-medium rotate: false - xy: 1210, 169 + xy: 3013, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cliff-small rotate: false - xy: 1368, 7 + xy: 3850, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cliff-tiny rotate: false - xy: 3781, 174 + xy: 2381, 27 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12212,28 +14088,28 @@ block-cliff-xlarge index: -1 block-coal-centrifuge-large rotate: false - xy: 1834, 371 + xy: 1340, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-coal-centrifuge-medium rotate: false - xy: 1244, 169 + xy: 3047, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-coal-centrifuge-small rotate: false - xy: 1394, 7 + xy: 3862, 245 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-coal-centrifuge-tiny rotate: false - xy: 2330, 175 + xy: 2399, 45 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12247,28 +14123,28 @@ block-coal-centrifuge-xlarge index: -1 block-combustion-generator-large rotate: false - xy: 1876, 371 + xy: 1424, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-combustion-generator-medium rotate: false - xy: 1278, 169 + xy: 3081, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-combustion-generator-small rotate: false - xy: 1420, 7 + xy: 3877, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-combustion-generator-tiny rotate: false - xy: 2330, 157 + xy: 2417, 63 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12282,28 +14158,28 @@ block-combustion-generator-xlarge index: -1 block-command-center-large rotate: false - xy: 1918, 371 + xy: 1382, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-command-center-medium rotate: false - xy: 1312, 169 + xy: 3115, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-command-center-small rotate: false - xy: 1446, 7 + xy: 3877, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-command-center-tiny rotate: false - xy: 2348, 175 + xy: 2381, 9 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12317,28 +14193,28 @@ block-command-center-xlarge index: -1 block-conduit-large rotate: false - xy: 1960, 371 + xy: 1466, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-conduit-medium rotate: false - xy: 1346, 169 + xy: 3149, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-conduit-small rotate: false - xy: 1472, 7 + xy: 3876, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-conduit-tiny rotate: false - xy: 2348, 157 + xy: 2399, 27 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12352,28 +14228,28 @@ block-conduit-xlarge index: -1 block-container-large rotate: false - xy: 2002, 371 + xy: 1424, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-container-medium rotate: false - xy: 1380, 169 + xy: 3183, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-container-small rotate: false - xy: 1498, 7 + xy: 3888, 245 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-container-tiny rotate: false - xy: 2366, 175 + xy: 2417, 45 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12387,28 +14263,28 @@ block-container-xlarge index: -1 block-conveyor-large rotate: false - xy: 2044, 371 + xy: 1508, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-conveyor-medium rotate: false - xy: 1414, 169 + xy: 3217, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-conveyor-small rotate: false - xy: 1524, 7 + xy: 3903, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-conveyor-tiny rotate: false - xy: 2366, 157 + xy: 2435, 63 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12422,35 +14298,35 @@ block-conveyor-xlarge index: -1 block-copper-wall-large rotate: false - xy: 2086, 371 + xy: 1466, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-copper-wall-large-large rotate: false - xy: 2128, 371 + xy: 1550, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-copper-wall-large-medium rotate: false - xy: 1448, 169 + xy: 3251, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-copper-wall-large-small rotate: false - xy: 1550, 7 + xy: 3903, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-copper-wall-large-tiny rotate: false - xy: 2384, 173 + xy: 2399, 9 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12464,21 +14340,21 @@ block-copper-wall-large-xlarge index: -1 block-copper-wall-medium rotate: false - xy: 1482, 169 + xy: 3285, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-copper-wall-small rotate: false - xy: 1576, 7 + xy: 3902, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-copper-wall-tiny rotate: false - xy: 2402, 173 + xy: 2417, 27 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12492,28 +14368,28 @@ block-copper-wall-xlarge index: -1 block-core-foundation-large rotate: false - xy: 2170, 371 + xy: 1508, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-core-foundation-medium rotate: false - xy: 1516, 169 + xy: 3319, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-core-foundation-small rotate: false - xy: 1602, 7 + xy: 3914, 245 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-core-foundation-tiny rotate: false - xy: 2420, 173 + xy: 2435, 45 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12527,28 +14403,28 @@ block-core-foundation-xlarge index: -1 block-core-nucleus-large rotate: false - xy: 2212, 371 + xy: 1592, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-core-nucleus-medium rotate: false - xy: 1550, 169 + xy: 3353, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-core-nucleus-small rotate: false - xy: 1628, 7 + xy: 3929, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-core-nucleus-tiny rotate: false - xy: 2384, 155 + xy: 2417, 9 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12562,28 +14438,28 @@ block-core-nucleus-xlarge index: -1 block-core-shard-large rotate: false - xy: 2254, 371 + xy: 1550, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-core-shard-medium rotate: false - xy: 1584, 169 + xy: 3387, 224 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-core-shard-small rotate: false - xy: 1654, 7 + xy: 3929, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-core-shard-tiny rotate: false - xy: 2402, 155 + xy: 2435, 27 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12597,28 +14473,28 @@ block-core-shard-xlarge index: -1 block-craters-large rotate: false - xy: 2296, 371 + xy: 1634, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-craters-medium rotate: false - xy: 1618, 169 + xy: 1799, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-craters-small rotate: false - xy: 1680, 7 + xy: 3928, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-craters-tiny rotate: false - xy: 2420, 155 + xy: 2435, 9 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12632,28 +14508,28 @@ block-craters-xlarge index: -1 block-cryofluid-mixer-large rotate: false - xy: 2338, 371 + xy: 1592, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cryofluid-mixer-medium rotate: false - xy: 1652, 169 + xy: 1833, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cryofluid-mixer-small rotate: false - xy: 1706, 7 + xy: 3940, 245 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cryofluid-mixer-tiny rotate: false - xy: 2509, 184 + xy: 2462, 107 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12667,28 +14543,28 @@ block-cryofluid-mixer-xlarge index: -1 block-cultivator-large rotate: false - xy: 2380, 371 + xy: 1676, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cultivator-medium rotate: false - xy: 1686, 169 + xy: 1867, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cultivator-small rotate: false - xy: 3708, 339 + xy: 3955, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cultivator-tiny rotate: false - xy: 2527, 188 + xy: 1809, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12702,28 +14578,28 @@ block-cultivator-xlarge index: -1 block-cyclone-large rotate: false - xy: 2422, 371 + xy: 1634, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-cyclone-medium rotate: false - xy: 1720, 169 + xy: 1901, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cyclone-small rotate: false - xy: 3702, 313 + xy: 3955, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-cyclone-tiny rotate: false - xy: 2545, 188 + xy: 1827, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12737,28 +14613,28 @@ block-cyclone-xlarge index: -1 block-dacite-boulder-large rotate: false - xy: 2464, 371 + xy: 1718, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dacite-boulder-medium rotate: false - xy: 1754, 169 + xy: 1935, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dacite-boulder-small rotate: false - xy: 2123, 7 + xy: 3954, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dacite-boulder-tiny rotate: false - xy: 3781, 156 + xy: 1845, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12772,56 +14648,56 @@ block-dacite-boulder-xlarge index: -1 block-dacite-large rotate: false - xy: 2506, 371 + xy: 1676, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dacite-medium rotate: false - xy: 1788, 169 + xy: 1969, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dacite-small rotate: false - xy: 2491, 228 + xy: 3966, 245 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dacite-tiny rotate: false - xy: 3757, 327 + xy: 1863, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-dacite-wall-large rotate: false - xy: 2548, 371 + xy: 1760, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dacite-wall-medium rotate: false - xy: 1822, 169 + xy: 2003, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dacite-wall-small rotate: false - xy: 2517, 232 + xy: 3981, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dacite-wall-tiny rotate: false - xy: 3775, 327 + xy: 1881, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12842,28 +14718,28 @@ block-dacite-xlarge index: -1 block-dark-metal-large rotate: false - xy: 2590, 371 + xy: 1718, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-metal-medium rotate: false - xy: 1856, 169 + xy: 2037, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-metal-small rotate: false - xy: 2543, 232 + xy: 3981, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-metal-tiny rotate: false - xy: 2080, 7 + xy: 1899, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12877,28 +14753,28 @@ block-dark-metal-xlarge index: -1 block-dark-panel-1-large rotate: false - xy: 2632, 371 + xy: 1802, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-1-medium rotate: false - xy: 1890, 169 + xy: 2071, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-1-small rotate: false - xy: 2569, 219 + xy: 3980, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-1-tiny rotate: false - xy: 2098, 7 + xy: 1917, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12912,28 +14788,28 @@ block-dark-panel-1-xlarge index: -1 block-dark-panel-2-large rotate: false - xy: 2674, 371 + xy: 1760, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-2-medium rotate: false - xy: 1924, 169 + xy: 2105, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-2-small rotate: false - xy: 2595, 219 + xy: 3992, 245 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-2-tiny rotate: false - xy: 2527, 170 + xy: 1935, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12947,28 +14823,28 @@ block-dark-panel-2-xlarge index: -1 block-dark-panel-3-large rotate: false - xy: 2716, 371 + xy: 1844, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-3-medium rotate: false - xy: 1958, 169 + xy: 2139, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-3-small rotate: false - xy: 2491, 202 + xy: 4018, 245 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-3-tiny rotate: false - xy: 2545, 170 + xy: 1953, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -12982,28 +14858,28 @@ block-dark-panel-3-xlarge index: -1 block-dark-panel-4-large rotate: false - xy: 2758, 371 + xy: 1802, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-4-medium rotate: false - xy: 1992, 169 + xy: 2173, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-4-small rotate: false - xy: 2517, 206 + xy: 4007, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-4-tiny rotate: false - xy: 2563, 175 + xy: 1971, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13017,28 +14893,28 @@ block-dark-panel-4-xlarge index: -1 block-dark-panel-5-large rotate: false - xy: 2800, 371 + xy: 1886, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-5-medium rotate: false - xy: 2026, 169 + xy: 2207, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-5-small rotate: false - xy: 2543, 206 + xy: 4007, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-5-tiny rotate: false - xy: 2581, 175 + xy: 2169, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13052,28 +14928,28 @@ block-dark-panel-5-xlarge index: -1 block-dark-panel-6-large rotate: false - xy: 2842, 371 + xy: 1844, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dark-panel-6-medium rotate: false - xy: 2060, 169 + xy: 2241, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-6-small rotate: false - xy: 2569, 193 + xy: 4006, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dark-panel-6-tiny rotate: false - xy: 2599, 175 + xy: 2187, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13087,49 +14963,49 @@ block-dark-panel-6-xlarge index: -1 block-darksand-large rotate: false - xy: 2884, 371 + xy: 1928, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-darksand-medium rotate: false - xy: 2094, 171 + xy: 2275, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-small rotate: false - xy: 2595, 193 + xy: 4033, 219 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-darksand-tainted-water-large rotate: false - xy: 2926, 371 + xy: 1886, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-darksand-tainted-water-medium rotate: false - xy: 2128, 177 + xy: 2309, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-tainted-water-small rotate: false - xy: 2621, 235 + xy: 4033, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-darksand-tainted-water-tiny rotate: false - xy: 2563, 157 + xy: 2205, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13143,35 +15019,35 @@ block-darksand-tainted-water-xlarge index: -1 block-darksand-tiny rotate: false - xy: 2581, 157 + xy: 2223, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-darksand-water-large rotate: false - xy: 2968, 371 + xy: 1970, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-darksand-water-medium rotate: false - xy: 2162, 180 + xy: 1969, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-water-small rotate: false - xy: 2621, 209 + xy: 4032, 167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-darksand-water-tiny rotate: false - xy: 2599, 157 + xy: 2241, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13192,28 +15068,28 @@ block-darksand-xlarge index: -1 block-deepwater-large rotate: false - xy: 3010, 371 + xy: 1928, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-deepwater-medium rotate: false - xy: 2623, 261 + xy: 2003, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-deepwater-small rotate: false - xy: 2647, 227 + xy: 4059, 226 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-deepwater-tiny rotate: false - xy: 2617, 165 + xy: 2259, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13227,28 +15103,28 @@ block-deepwater-xlarge index: -1 block-differential-generator-large rotate: false - xy: 3052, 371 + xy: 2012, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-differential-generator-medium rotate: false - xy: 2657, 253 + xy: 2037, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-differential-generator-small rotate: false - xy: 2673, 227 + xy: 4059, 200 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-differential-generator-tiny rotate: false - xy: 2617, 147 + xy: 2277, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13262,28 +15138,28 @@ block-differential-generator-xlarge index: -1 block-diode-large rotate: false - xy: 3094, 371 + xy: 1970, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-diode-medium rotate: false - xy: 2355, 211 + xy: 2071, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-diode-small rotate: false - xy: 2699, 227 + xy: 4059, 174 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-diode-tiny rotate: false - xy: 2612, 129 + xy: 2295, 18 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13297,56 +15173,56 @@ block-diode-xlarge index: -1 block-dirt-large rotate: false - xy: 3136, 371 + xy: 2054, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dirt-medium rotate: false - xy: 2389, 217 + xy: 2105, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dirt-small rotate: false - xy: 2647, 201 + xy: 4058, 148 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dirt-tiny rotate: false - xy: 2612, 111 + xy: 2462, 89 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-dirt-wall-large rotate: false - xy: 3178, 371 + xy: 2012, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dirt-wall-medium rotate: false - xy: 2423, 219 + xy: 2139, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dirt-wall-small rotate: false - xy: 2673, 201 + xy: 2445, 177 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dirt-wall-tiny rotate: false - xy: 2610, 93 + xy: 2069, 8 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13367,28 +15243,28 @@ block-dirt-xlarge index: -1 block-disassembler-large rotate: false - xy: 3220, 371 + xy: 2096, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-disassembler-medium rotate: false - xy: 2457, 220 + xy: 2173, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-disassembler-small rotate: false - xy: 2699, 201 + xy: 2450, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-disassembler-tiny rotate: false - xy: 2612, 75 + xy: 2087, 8 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13402,28 +15278,28 @@ block-disassembler-xlarge index: -1 block-distributor-large rotate: false - xy: 3262, 371 + xy: 2054, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-distributor-medium rotate: false - xy: 2691, 253 + xy: 2207, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-distributor-small rotate: false - xy: 2725, 206 + xy: 2450, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-distributor-tiny rotate: false - xy: 2612, 57 + xy: 2453, 63 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13437,35 +15313,35 @@ block-distributor-xlarge index: -1 block-door-large rotate: false - xy: 3304, 371 + xy: 2138, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-door-large-large rotate: false - xy: 3346, 371 + xy: 2096, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-door-large-medium rotate: false - xy: 2725, 266 + xy: 2241, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-door-large-small rotate: false - xy: 2751, 206 + xy: 2471, 193 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-door-large-tiny rotate: false - xy: 2612, 39 + xy: 2453, 45 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13479,21 +15355,21 @@ block-door-large-xlarge index: -1 block-door-medium rotate: false - xy: 2759, 266 + xy: 2275, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-door-small rotate: false - xy: 2777, 206 + xy: 2497, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-door-tiny rotate: false - xy: 2612, 21 + xy: 2453, 27 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13507,28 +15383,28 @@ block-door-xlarge index: -1 block-dune-wall-large rotate: false - xy: 3388, 371 + xy: 2180, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-dune-wall-medium rotate: false - xy: 2793, 266 + xy: 2309, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dune-wall-small rotate: false - xy: 2803, 206 + xy: 2523, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-dune-wall-tiny rotate: false - xy: 2635, 157 + xy: 2453, 9 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13542,28 +15418,28 @@ block-dune-wall-xlarge index: -1 block-duo-large rotate: false - xy: 3430, 371 + xy: 2138, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-duo-medium rotate: false - xy: 2827, 266 + xy: 881, 121 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-duo-small rotate: false - xy: 2829, 206 + xy: 2549, 194 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-duo-tiny rotate: false - xy: 2653, 157 + xy: 4047, 123 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13577,28 +15453,28 @@ block-duo-xlarge index: -1 block-exponential-reconstructor-large rotate: false - xy: 3472, 371 + xy: 2222, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-exponential-reconstructor-medium rotate: false - xy: 2861, 266 + xy: 881, 87 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-exponential-reconstructor-small rotate: false - xy: 2855, 206 + xy: 2549, 168 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-exponential-reconstructor-tiny rotate: false - xy: 2671, 157 + xy: 4065, 130 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13612,28 +15488,28 @@ block-exponential-reconstructor-xlarge index: -1 block-force-projector-large rotate: false - xy: 3514, 371 + xy: 2180, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-force-projector-medium rotate: false - xy: 2895, 266 + xy: 881, 53 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-force-projector-small rotate: false - xy: 2881, 206 + xy: 2575, 177 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-force-projector-tiny rotate: false - xy: 2689, 157 + xy: 4047, 105 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13647,28 +15523,28 @@ block-force-projector-xlarge index: -1 block-foreshadow-large rotate: false - xy: 3556, 371 + xy: 2264, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-foreshadow-medium rotate: false - xy: 2929, 266 + xy: 881, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-foreshadow-small rotate: false - xy: 2907, 206 + xy: 2601, 177 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-foreshadow-tiny rotate: false - xy: 2707, 157 + xy: 4065, 112 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13682,28 +15558,28 @@ block-foreshadow-xlarge index: -1 block-fuse-large rotate: false - xy: 3598, 371 + xy: 2222, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-fuse-medium rotate: false - xy: 2963, 266 + xy: 915, 119 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-fuse-small rotate: false - xy: 2933, 206 + xy: 2575, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-fuse-tiny rotate: false - xy: 2635, 139 + xy: 4065, 94 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13717,28 +15593,28 @@ block-fuse-xlarge index: -1 block-graphite-press-large rotate: false - xy: 4009, 281 + xy: 2306, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-graphite-press-medium rotate: false - xy: 2997, 266 + xy: 915, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-graphite-press-small rotate: false - xy: 2959, 206 + xy: 2601, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-graphite-press-tiny rotate: false - xy: 2653, 139 + xy: 3809, 311 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13752,28 +15628,28 @@ block-graphite-press-xlarge index: -1 block-grass-large rotate: false - xy: 1078, 329 + xy: 2264, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-grass-medium rotate: false - xy: 3031, 266 + xy: 949, 119 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-grass-small rotate: false - xy: 2985, 206 + xy: 3581, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-grass-tiny rotate: false - xy: 2671, 139 + xy: 2476, 175 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13787,28 +15663,28 @@ block-grass-xlarge index: -1 block-ground-factory-large rotate: false - xy: 1120, 329 + xy: 2348, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ground-factory-medium rotate: false - xy: 3065, 266 + xy: 915, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ground-factory-small rotate: false - xy: 3011, 206 + xy: 3607, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ground-factory-tiny rotate: false - xy: 2689, 139 + xy: 2476, 157 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13822,28 +15698,28 @@ block-ground-factory-xlarge index: -1 block-hail-large rotate: false - xy: 1162, 329 + xy: 2306, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-hail-medium rotate: false - xy: 3099, 266 + xy: 949, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hail-small rotate: false - xy: 3037, 206 + xy: 3633, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-hail-tiny rotate: false - xy: 2707, 139 + xy: 2476, 139 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13857,28 +15733,28 @@ block-hail-xlarge index: -1 block-hotrock-large rotate: false - xy: 1204, 329 + xy: 2390, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-hotrock-medium rotate: false - xy: 3133, 266 + xy: 949, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hotrock-small rotate: false - xy: 3063, 206 + xy: 3659, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-hotrock-tiny rotate: false - xy: 2725, 136 + xy: 2494, 167 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13892,28 +15768,28 @@ block-hotrock-xlarge index: -1 block-hyper-processor-large rotate: false - xy: 1246, 329 + xy: 2348, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-hyper-processor-medium rotate: false - xy: 3167, 266 + xy: 915, 17 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hyper-processor-small rotate: false - xy: 3089, 206 + xy: 3685, 157 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-hyper-processor-tiny rotate: false - xy: 2743, 136 + xy: 2512, 167 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13927,49 +15803,49 @@ block-hyper-processor-xlarge index: -1 block-ice-large rotate: false - xy: 1288, 329 + xy: 2432, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ice-medium rotate: false - xy: 3201, 266 + xy: 949, 17 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-small rotate: false - xy: 3115, 206 + xy: 3579, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ice-snow-large rotate: false - xy: 1330, 329 + xy: 2390, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ice-snow-medium rotate: false - xy: 3235, 266 + xy: 983, 119 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-snow-small rotate: false - xy: 3141, 206 + xy: 3605, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ice-snow-tiny rotate: false - xy: 2761, 136 + xy: 2494, 149 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -13983,35 +15859,35 @@ block-ice-snow-xlarge index: -1 block-ice-tiny rotate: false - xy: 2779, 136 + xy: 2530, 167 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-ice-wall-large rotate: false - xy: 1372, 329 + xy: 2474, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ice-wall-medium rotate: false - xy: 3269, 266 + xy: 983, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-wall-small rotate: false - xy: 3167, 206 + xy: 3631, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ice-wall-tiny rotate: false - xy: 2797, 136 + xy: 2512, 149 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14032,28 +15908,28 @@ block-ice-xlarge index: -1 block-illuminator-large rotate: false - xy: 1414, 329 + xy: 2432, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-illuminator-medium rotate: false - xy: 3303, 266 + xy: 983, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-illuminator-small rotate: false - xy: 3193, 206 + xy: 3657, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-illuminator-tiny rotate: false - xy: 2815, 136 + xy: 2530, 149 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14067,28 +15943,28 @@ block-illuminator-xlarge index: -1 block-impact-reactor-large rotate: false - xy: 1456, 329 + xy: 2516, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-impact-reactor-medium rotate: false - xy: 3337, 266 + xy: 983, 17 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-impact-reactor-small rotate: false - xy: 3219, 206 + xy: 3683, 131 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-impact-reactor-tiny rotate: false - xy: 2833, 136 + xy: 2548, 150 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14102,28 +15978,28 @@ block-impact-reactor-xlarge index: -1 block-incinerator-large rotate: false - xy: 1498, 329 + xy: 2474, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-incinerator-medium rotate: false - xy: 3371, 266 + xy: 2741, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-incinerator-small rotate: false - xy: 3245, 206 + xy: 1731, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-incinerator-tiny rotate: false - xy: 2851, 136 + xy: 2494, 131 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14137,28 +16013,28 @@ block-incinerator-xlarge index: -1 block-inverted-sorter-large rotate: false - xy: 1540, 329 + xy: 2558, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-inverted-sorter-medium rotate: false - xy: 918, 127 + xy: 2775, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-inverted-sorter-small rotate: false - xy: 3271, 206 + xy: 1757, 205 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-inverted-sorter-tiny rotate: false - xy: 2869, 136 + xy: 2512, 131 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14172,28 +16048,28 @@ block-inverted-sorter-xlarge index: -1 block-item-source-large rotate: false - xy: 1582, 329 + xy: 2516, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-item-source-medium rotate: false - xy: 917, 93 + xy: 2809, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-item-source-small rotate: false - xy: 3297, 206 + xy: 1757, 96 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-item-source-tiny rotate: false - xy: 2887, 136 + xy: 2530, 131 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14207,28 +16083,28 @@ block-item-source-xlarge index: -1 block-item-void-large rotate: false - xy: 1624, 329 + xy: 2600, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-item-void-medium rotate: false - xy: 952, 127 + xy: 2843, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-item-void-small rotate: false - xy: 3323, 206 + xy: 1757, 70 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-item-void-tiny rotate: false - xy: 2905, 136 + xy: 2548, 132 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14242,28 +16118,28 @@ block-item-void-xlarge index: -1 block-junction-large rotate: false - xy: 1666, 329 + xy: 2558, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-junction-medium rotate: false - xy: 951, 93 + xy: 2877, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-junction-small rotate: false - xy: 3349, 206 + xy: 1757, 44 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-junction-tiny rotate: false - xy: 2923, 136 + xy: 2566, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14277,28 +16153,28 @@ block-junction-xlarge index: -1 block-kiln-large rotate: false - xy: 1708, 329 + xy: 2642, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-kiln-medium rotate: false - xy: 986, 127 + xy: 2911, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-kiln-small rotate: false - xy: 3375, 206 + xy: 3711, 145 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-kiln-tiny rotate: false - xy: 2941, 136 + xy: 2584, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14312,28 +16188,28 @@ block-kiln-xlarge index: -1 block-lancer-large rotate: false - xy: 1750, 329 + xy: 2600, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-lancer-medium rotate: false - xy: 985, 93 + xy: 2945, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-lancer-small rotate: false - xy: 2621, 183 + xy: 3737, 145 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-lancer-tiny rotate: false - xy: 2959, 136 + xy: 2602, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14347,28 +16223,28 @@ block-lancer-xlarge index: -1 block-large-logic-display-large rotate: false - xy: 1792, 329 + xy: 2684, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-large-logic-display-medium rotate: false - xy: 1020, 127 + xy: 2979, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-large-logic-display-small rotate: false - xy: 2647, 175 + xy: 3763, 145 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-large-logic-display-tiny rotate: false - xy: 2977, 136 + xy: 2620, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14382,28 +16258,28 @@ block-large-logic-display-xlarge index: -1 block-laser-drill-large rotate: false - xy: 1834, 329 + xy: 2642, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-laser-drill-medium rotate: false - xy: 1019, 93 + xy: 3013, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-laser-drill-small rotate: false - xy: 2673, 175 + xy: 3789, 145 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-laser-drill-tiny rotate: false - xy: 2995, 136 + xy: 1989, 11 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14417,35 +16293,35 @@ block-laser-drill-xlarge index: -1 block-launch-pad-large rotate: false - xy: 1876, 329 + xy: 2726, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-launch-pad-large-large rotate: false - xy: 1918, 329 + xy: 2684, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-launch-pad-large-medium rotate: false - xy: 1054, 127 + xy: 3047, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-launch-pad-large-small rotate: false - xy: 2699, 175 + xy: 3815, 141 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-launch-pad-large-tiny rotate: false - xy: 3013, 136 + xy: 2007, 8 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14459,21 +16335,21 @@ block-launch-pad-large-xlarge index: -1 block-launch-pad-medium rotate: false - xy: 1053, 93 + xy: 3081, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-launch-pad-small rotate: false - xy: 2725, 180 + xy: 3841, 141 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-launch-pad-tiny rotate: false - xy: 3031, 136 + xy: 2025, 8 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14487,28 +16363,28 @@ block-launch-pad-xlarge index: -1 block-liquid-junction-large rotate: false - xy: 1960, 329 + xy: 2768, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-junction-medium rotate: false - xy: 1088, 135 + xy: 3115, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-junction-small rotate: false - xy: 2751, 180 + xy: 3867, 141 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-junction-tiny rotate: false - xy: 3049, 136 + xy: 2043, 3 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14522,28 +16398,28 @@ block-liquid-junction-xlarge index: -1 block-liquid-router-large rotate: false - xy: 2002, 329 + xy: 2726, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-router-medium rotate: false - xy: 1122, 135 + xy: 3149, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-router-small rotate: false - xy: 2777, 180 + xy: 3893, 141 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-router-tiny rotate: false - xy: 3067, 136 + xy: 3887, 312 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14557,28 +16433,28 @@ block-liquid-router-xlarge index: -1 block-liquid-source-large rotate: false - xy: 2044, 329 + xy: 2810, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-source-medium rotate: false - xy: 1156, 135 + xy: 3183, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-source-small rotate: false - xy: 2803, 180 + xy: 3919, 141 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-source-tiny rotate: false - xy: 3085, 136 + xy: 3887, 294 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14592,28 +16468,28 @@ block-liquid-source-xlarge index: -1 block-liquid-tank-large rotate: false - xy: 2086, 329 + xy: 2768, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-tank-medium rotate: false - xy: 1190, 135 + xy: 3217, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-tank-small rotate: false - xy: 2829, 180 + xy: 3945, 141 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-tank-tiny rotate: false - xy: 3103, 136 + xy: 3887, 276 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14627,28 +16503,28 @@ block-liquid-tank-xlarge index: -1 block-liquid-void-large rotate: false - xy: 2128, 329 + xy: 2852, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-void-medium rotate: false - xy: 1224, 135 + xy: 3251, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-void-small rotate: false - xy: 2855, 180 + xy: 3971, 141 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-void-tiny rotate: false - xy: 3121, 136 + xy: 3905, 305 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14662,28 +16538,28 @@ block-liquid-void-xlarge index: -1 block-logic-display-large rotate: false - xy: 2170, 329 + xy: 2810, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-logic-display-medium rotate: false - xy: 1258, 135 + xy: 3285, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-logic-display-small rotate: false - xy: 2881, 180 + xy: 3997, 141 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-logic-display-tiny rotate: false - xy: 3139, 136 + xy: 3923, 305 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14697,28 +16573,28 @@ block-logic-display-xlarge index: -1 block-logic-processor-large rotate: false - xy: 2212, 329 + xy: 2894, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-logic-processor-medium rotate: false - xy: 1292, 135 + xy: 3319, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-logic-processor-small rotate: false - xy: 2907, 180 + xy: 4023, 141 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-logic-processor-tiny rotate: false - xy: 3157, 136 + xy: 3941, 305 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14732,28 +16608,28 @@ block-logic-processor-xlarge index: -1 block-magmarock-large rotate: false - xy: 2254, 329 + xy: 2852, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-magmarock-medium rotate: false - xy: 1326, 135 + xy: 3353, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-magmarock-small rotate: false - xy: 2933, 180 + xy: 3709, 119 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-magmarock-tiny rotate: false - xy: 3175, 136 + xy: 3905, 287 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14767,28 +16643,28 @@ block-magmarock-xlarge index: -1 block-mass-driver-large rotate: false - xy: 2296, 329 + xy: 2936, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mass-driver-medium rotate: false - xy: 1360, 135 + xy: 3387, 190 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mass-driver-small rotate: false - xy: 2959, 180 + xy: 3735, 119 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mass-driver-tiny rotate: false - xy: 3193, 136 + xy: 3923, 287 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14802,28 +16678,28 @@ block-mass-driver-xlarge index: -1 block-mechanical-drill-large rotate: false - xy: 2338, 329 + xy: 2894, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mechanical-drill-medium rotate: false - xy: 1394, 135 + xy: 1631, 222 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mechanical-drill-small rotate: false - xy: 2985, 180 + xy: 3761, 119 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mechanical-drill-tiny rotate: false - xy: 3211, 136 + xy: 3941, 287 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14837,28 +16713,28 @@ block-mechanical-drill-xlarge index: -1 block-mechanical-pump-large rotate: false - xy: 2380, 329 + xy: 2978, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mechanical-pump-medium rotate: false - xy: 1428, 135 + xy: 1665, 213 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mechanical-pump-small rotate: false - xy: 3011, 180 + xy: 3787, 119 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mechanical-pump-tiny rotate: false - xy: 3229, 136 + xy: 3959, 295 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14872,28 +16748,28 @@ block-mechanical-pump-xlarge index: -1 block-meltdown-large rotate: false - xy: 2422, 329 + xy: 2936, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-meltdown-medium rotate: false - xy: 1462, 135 + xy: 1699, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-meltdown-small rotate: false - xy: 3037, 180 + xy: 3813, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-meltdown-tiny rotate: false - xy: 3247, 136 + xy: 3977, 295 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14907,28 +16783,28 @@ block-meltdown-xlarge index: -1 block-melter-large rotate: false - xy: 2464, 329 + xy: 3020, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-melter-medium rotate: false - xy: 1496, 135 + xy: 3421, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-melter-small rotate: false - xy: 3063, 180 + xy: 3839, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-melter-tiny rotate: false - xy: 3265, 136 + xy: 3959, 277 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14942,28 +16818,28 @@ block-melter-xlarge index: -1 block-memory-bank-large rotate: false - xy: 2506, 329 + xy: 2978, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-memory-bank-medium rotate: false - xy: 1530, 135 + xy: 3455, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-memory-bank-small rotate: false - xy: 3089, 180 + xy: 3865, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-memory-bank-tiny rotate: false - xy: 3283, 136 + xy: 3977, 277 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -14977,28 +16853,28 @@ block-memory-bank-xlarge index: -1 block-memory-cell-large rotate: false - xy: 2548, 329 + xy: 3062, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-memory-cell-medium rotate: false - xy: 1564, 135 + xy: 3421, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-memory-cell-small rotate: false - xy: 3115, 180 + xy: 3891, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-memory-cell-tiny rotate: false - xy: 3301, 136 + xy: 2471, 71 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15012,28 +16888,28 @@ block-memory-cell-xlarge index: -1 block-mend-projector-large rotate: false - xy: 2590, 329 + xy: 3020, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mend-projector-medium rotate: false - xy: 1598, 135 + xy: 3455, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mend-projector-small rotate: false - xy: 3141, 180 + xy: 3917, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mend-projector-tiny rotate: false - xy: 3319, 136 + xy: 2471, 53 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15047,28 +16923,28 @@ block-mend-projector-xlarge index: -1 block-mender-large rotate: false - xy: 2632, 329 + xy: 3104, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mender-medium rotate: false - xy: 1632, 135 + xy: 2555, 220 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mender-small rotate: false - xy: 3167, 180 + xy: 3943, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mender-tiny rotate: false - xy: 3337, 136 + xy: 2471, 35 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15082,28 +16958,28 @@ block-mender-xlarge index: -1 block-message-large rotate: false - xy: 2674, 329 + xy: 3062, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-message-medium rotate: false - xy: 1666, 135 + xy: 2589, 203 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-message-small rotate: false - xy: 3193, 180 + xy: 3969, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-message-tiny rotate: false - xy: 3355, 136 + xy: 2471, 17 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15117,28 +16993,28 @@ block-message-xlarge index: -1 block-metal-floor-2-large rotate: false - xy: 2716, 329 + xy: 3146, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-2-medium rotate: false - xy: 1700, 135 + xy: 2471, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-2-small rotate: false - xy: 3219, 180 + xy: 3995, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-2-tiny rotate: false - xy: 3373, 136 + xy: 2548, 114 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15152,28 +17028,28 @@ block-metal-floor-2-xlarge index: -1 block-metal-floor-3-large rotate: false - xy: 2758, 329 + xy: 3104, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-3-medium rotate: false - xy: 1734, 135 + xy: 2505, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-3-small rotate: false - xy: 3245, 180 + xy: 4021, 115 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-3-tiny rotate: false - xy: 2630, 121 + xy: 2566, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15187,28 +17063,28 @@ block-metal-floor-3-xlarge index: -1 block-metal-floor-5-large rotate: false - xy: 2800, 329 + xy: 3188, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-5-medium rotate: false - xy: 1768, 135 + xy: 3552, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-5-small rotate: false - xy: 3271, 180 + xy: 1760, 179 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-5-tiny rotate: false - xy: 2648, 121 + xy: 2584, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15222,28 +17098,28 @@ block-metal-floor-5-xlarge index: -1 block-metal-floor-damaged-large rotate: false - xy: 2842, 329 + xy: 3146, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-damaged-medium rotate: false - xy: 1802, 135 + xy: 3587, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-damaged-small rotate: false - xy: 3297, 180 + xy: 1760, 153 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-damaged-tiny rotate: false - xy: 2666, 121 + xy: 2602, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15257,28 +17133,28 @@ block-metal-floor-damaged-xlarge index: -1 block-metal-floor-large rotate: false - xy: 2884, 329 + xy: 3230, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-medium rotate: false - xy: 1836, 135 + xy: 3621, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-small rotate: false - xy: 3323, 180 + xy: 1760, 127 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-tiny rotate: false - xy: 2684, 121 + xy: 2620, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15292,28 +17168,28 @@ block-metal-floor-xlarge index: -1 block-micro-processor-large rotate: false - xy: 2926, 329 + xy: 3188, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-micro-processor-medium rotate: false - xy: 1870, 135 + xy: 3655, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-micro-processor-small rotate: false - xy: 3349, 180 + xy: 1786, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-micro-processor-tiny rotate: false - xy: 2702, 121 + xy: 2566, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15327,28 +17203,28 @@ block-micro-processor-xlarge index: -1 block-moss-large rotate: false - xy: 2968, 329 + xy: 3272, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-moss-medium rotate: false - xy: 1904, 135 + xy: 3689, 217 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-moss-small rotate: false - xy: 3375, 180 + xy: 1786, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-moss-tiny rotate: false - xy: 2630, 103 + xy: 2584, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15362,28 +17238,28 @@ block-moss-xlarge index: -1 block-mud-large rotate: false - xy: 3010, 329 + xy: 3230, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mud-medium rotate: false - xy: 1938, 135 + xy: 3723, 205 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mud-small rotate: false - xy: 3401, 193 + xy: 1812, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mud-tiny rotate: false - xy: 2648, 103 + xy: 2602, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15397,28 +17273,28 @@ block-mud-xlarge index: -1 block-multi-press-large rotate: false - xy: 3052, 329 + xy: 3314, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-multi-press-medium rotate: false - xy: 1972, 135 + xy: 3757, 205 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-multi-press-small rotate: false - xy: 3427, 193 + xy: 1812, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-multi-press-tiny rotate: false - xy: 2666, 103 + xy: 2620, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15432,28 +17308,28 @@ block-multi-press-xlarge index: -1 block-multiplicative-reconstructor-large rotate: false - xy: 3094, 329 + xy: 3272, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-multiplicative-reconstructor-medium rotate: false - xy: 2006, 135 + xy: 993, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-multiplicative-reconstructor-small rotate: false - xy: 3401, 167 + xy: 1786, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-multiplicative-reconstructor-tiny rotate: false - xy: 2684, 103 + xy: 2627, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15467,28 +17343,28 @@ block-multiplicative-reconstructor-xlarge index: -1 block-naval-factory-large rotate: false - xy: 3136, 329 + xy: 3356, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-naval-factory-medium rotate: false - xy: 2040, 135 + xy: 1027, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-naval-factory-small rotate: false - xy: 3427, 167 + xy: 1838, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-naval-factory-tiny rotate: false - xy: 2702, 103 + xy: 2627, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15502,28 +17378,28 @@ block-naval-factory-xlarge index: -1 block-oil-extractor-large rotate: false - xy: 3178, 329 + xy: 3314, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-oil-extractor-medium rotate: false - xy: 2074, 135 + xy: 1061, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-oil-extractor-small rotate: false - xy: 2142, 83 + xy: 1838, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-oil-extractor-tiny rotate: false - xy: 2720, 118 + xy: 2638, 136 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15537,28 +17413,28 @@ block-oil-extractor-xlarge index: -1 block-ore-coal-large rotate: false - xy: 3220, 329 + xy: 3398, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-coal-medium rotate: false - xy: 2108, 137 + xy: 1095, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-coal-small rotate: false - xy: 2168, 83 + xy: 1812, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-coal-tiny rotate: false - xy: 2738, 118 + xy: 2638, 118 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15572,28 +17448,28 @@ block-ore-coal-xlarge index: -1 block-ore-copper-large rotate: false - xy: 3262, 329 + xy: 3356, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-copper-medium rotate: false - xy: 2142, 143 + xy: 1129, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-copper-small rotate: false - xy: 2194, 86 + xy: 1864, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-copper-tiny rotate: false - xy: 2756, 118 + xy: 2638, 100 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15607,28 +17483,28 @@ block-ore-copper-xlarge index: -1 block-ore-lead-large rotate: false - xy: 3304, 329 + xy: 3440, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-lead-medium rotate: false - xy: 2176, 146 + xy: 1163, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-lead-small rotate: false - xy: 2220, 86 + xy: 1864, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-lead-tiny rotate: false - xy: 2774, 118 + xy: 2638, 82 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15642,28 +17518,28 @@ block-ore-lead-xlarge index: -1 block-ore-scrap-large rotate: false - xy: 3346, 329 + xy: 3398, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-scrap-medium rotate: false - xy: 2196, 180 + xy: 1197, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-scrap-small rotate: false - xy: 2246, 89 + xy: 1838, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-scrap-tiny rotate: false - xy: 2792, 118 + xy: 2480, 96 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15677,28 +17553,28 @@ block-ore-scrap-xlarge index: -1 block-ore-thorium-large rotate: false - xy: 3388, 329 + xy: 3482, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-thorium-medium rotate: false - xy: 2230, 183 + xy: 1231, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-thorium-small rotate: false - xy: 2152, 57 + xy: 1890, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-thorium-tiny rotate: false - xy: 2810, 118 + xy: 2489, 78 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15712,28 +17588,28 @@ block-ore-thorium-xlarge index: -1 block-ore-titanium-large rotate: false - xy: 3430, 329 + xy: 3440, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-titanium-medium rotate: false - xy: 2210, 146 + xy: 1265, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-titanium-small rotate: false - xy: 2152, 31 + xy: 1890, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-titanium-tiny rotate: false - xy: 2828, 118 + xy: 2489, 60 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15747,28 +17623,28 @@ block-ore-titanium-xlarge index: -1 block-overdrive-dome-large rotate: false - xy: 3472, 329 + xy: 3524, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-overdrive-dome-medium rotate: false - xy: 2244, 149 + xy: 1299, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-overdrive-dome-small rotate: false - xy: 2149, 5 + xy: 1864, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-overdrive-dome-tiny rotate: false - xy: 2846, 118 + xy: 2489, 42 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15782,28 +17658,28 @@ block-overdrive-dome-xlarge index: -1 block-overdrive-projector-large rotate: false - xy: 3514, 329 + xy: 3482, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-overdrive-projector-medium rotate: false - xy: 2573, 245 + xy: 1333, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-overdrive-projector-small rotate: false - xy: 2178, 57 + xy: 1916, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-overdrive-projector-tiny rotate: false - xy: 2864, 118 + xy: 2489, 24 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15817,28 +17693,28 @@ block-overdrive-projector-xlarge index: -1 block-overflow-gate-large rotate: false - xy: 3556, 329 + xy: 3566, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-overflow-gate-medium rotate: false - xy: 2725, 232 + xy: 1367, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-overflow-gate-small rotate: false - xy: 2178, 31 + xy: 1916, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-overflow-gate-tiny rotate: false - xy: 2882, 118 + xy: 2498, 96 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15852,28 +17728,28 @@ block-overflow-gate-xlarge index: -1 block-parallax-large rotate: false - xy: 3598, 329 + xy: 3524, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-parallax-medium rotate: false - xy: 2759, 232 + xy: 1401, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-parallax-small rotate: false - xy: 2175, 5 + xy: 1890, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-parallax-tiny rotate: false - xy: 2900, 118 + xy: 2507, 78 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15887,28 +17763,28 @@ block-parallax-xlarge index: -1 block-payload-conveyor-large rotate: false - xy: 3640, 335 + xy: 3608, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-payload-conveyor-medium rotate: false - xy: 2793, 232 + xy: 1435, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-payload-conveyor-small rotate: false - xy: 2204, 60 + xy: 1942, 185 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-payload-conveyor-tiny rotate: false - xy: 2918, 118 + xy: 2507, 60 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15922,28 +17798,28 @@ block-payload-conveyor-xlarge index: -1 block-payload-router-large rotate: false - xy: 4051, 281 + xy: 3566, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-payload-router-medium rotate: false - xy: 2827, 232 + xy: 1469, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-payload-router-small rotate: false - xy: 2204, 34 + xy: 1942, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-payload-router-tiny rotate: false - xy: 2936, 118 + xy: 2507, 42 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15957,28 +17833,28 @@ block-payload-router-xlarge index: -1 block-pebbles-large rotate: false - xy: 859, 321 + xy: 3650, 371 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pebbles-medium rotate: false - xy: 2861, 232 + xy: 1503, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pebbles-small rotate: false - xy: 2230, 60 + xy: 1916, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pebbles-tiny rotate: false - xy: 2954, 118 + xy: 2507, 24 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -15992,28 +17868,28 @@ block-pebbles-xlarge index: -1 block-phase-conduit-large rotate: false - xy: 901, 321 + xy: 3608, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-conduit-medium rotate: false - xy: 2895, 232 + xy: 1537, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-conduit-small rotate: false - xy: 2230, 34 + xy: 1942, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-conduit-tiny rotate: false - xy: 2972, 118 + xy: 2516, 96 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16027,28 +17903,28 @@ block-phase-conduit-xlarge index: -1 block-phase-conveyor-large rotate: false - xy: 859, 279 + xy: 3650, 329 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-conveyor-medium rotate: false - xy: 2929, 232 + xy: 1571, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-conveyor-small rotate: false - xy: 2256, 63 + xy: 1968, 159 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-conveyor-tiny rotate: false - xy: 2990, 118 + xy: 2525, 78 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16062,35 +17938,35 @@ block-phase-conveyor-xlarge index: -1 block-phase-wall-large rotate: false - xy: 943, 321 + xy: 959, 271 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-wall-large-large rotate: false - xy: 859, 237 + xy: 131, 4 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-wall-large-medium rotate: false - xy: 2963, 232 + xy: 1003, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-wall-large-small rotate: false - xy: 2256, 37 + xy: 1968, 133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-wall-large-tiny rotate: false - xy: 3008, 118 + xy: 2525, 60 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16104,21 +17980,21 @@ block-phase-wall-large-xlarge index: -1 block-phase-wall-medium rotate: false - xy: 2997, 232 + xy: 1037, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-wall-small rotate: false - xy: 2272, 89 + xy: 1994, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-wall-tiny rotate: false - xy: 3026, 118 + xy: 2525, 42 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16132,28 +18008,28 @@ block-phase-wall-xlarge index: -1 block-phase-weaver-large rotate: false - xy: 901, 279 + xy: 173, 4 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-weaver-medium rotate: false - xy: 3031, 232 + xy: 1071, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-weaver-small rotate: false - xy: 2282, 63 + xy: 2020, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-weaver-tiny rotate: false - xy: 3044, 118 + xy: 2525, 24 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16167,28 +18043,28 @@ block-phase-weaver-xlarge index: -1 block-pine-large rotate: false - xy: 985, 321 + xy: 215, 4 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pine-medium rotate: false - xy: 3065, 232 + xy: 1105, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pine-small rotate: false - xy: 2282, 37 + xy: 2046, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pine-tiny rotate: false - xy: 3062, 118 + xy: 2534, 96 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16202,28 +18078,28 @@ block-pine-xlarge index: -1 block-plastanium-compressor-large rotate: false - xy: 859, 195 + xy: 3692, 335 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-compressor-medium rotate: false - xy: 3099, 232 + xy: 1139, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-compressor-small rotate: false - xy: 3677, 173 + xy: 2072, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-compressor-tiny rotate: false - xy: 3080, 118 + xy: 2543, 78 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16237,28 +18113,28 @@ block-plastanium-compressor-xlarge index: -1 block-plastanium-conveyor-large rotate: false - xy: 901, 237 + xy: 909, 231 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-conveyor-medium rotate: false - xy: 3133, 232 + xy: 1173, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-conveyor-small rotate: false - xy: 3703, 166 + xy: 2098, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-conveyor-tiny rotate: false - xy: 3098, 118 + xy: 2543, 60 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16272,35 +18148,35 @@ block-plastanium-conveyor-xlarge index: -1 block-plastanium-wall-large rotate: false - xy: 943, 279 + xy: 951, 229 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-wall-large-large rotate: false - xy: 1027, 321 + xy: 902, 189 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-wall-large-medium rotate: false - xy: 3167, 232 + xy: 1207, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-wall-large-small rotate: false - xy: 3729, 166 + xy: 2124, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-wall-large-tiny rotate: false - xy: 3116, 118 + xy: 2543, 42 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16314,21 +18190,21 @@ block-plastanium-wall-large-xlarge index: -1 block-plastanium-wall-medium rotate: false - xy: 3201, 232 + xy: 1241, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-wall-small rotate: false - xy: 3737, 192 + xy: 2150, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-wall-tiny rotate: false - xy: 3134, 118 + xy: 2543, 24 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16342,28 +18218,28 @@ block-plastanium-wall-xlarge index: -1 block-plated-conduit-large rotate: false - xy: 901, 195 + xy: 944, 187 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plated-conduit-medium rotate: false - xy: 3235, 232 + xy: 1275, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plated-conduit-small rotate: false - xy: 3755, 166 + xy: 2176, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plated-conduit-tiny rotate: false - xy: 3152, 118 + xy: 2561, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16377,28 +18253,28 @@ block-plated-conduit-xlarge index: -1 block-pneumatic-drill-large rotate: false - xy: 943, 237 + xy: 1004, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pneumatic-drill-medium rotate: false - xy: 3269, 232 + xy: 1309, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pneumatic-drill-small rotate: false - xy: 3728, 313 + xy: 2202, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pneumatic-drill-tiny rotate: false - xy: 3170, 118 + xy: 2561, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16412,35 +18288,35 @@ block-pneumatic-drill-xlarge index: -1 block-power-node-large rotate: false - xy: 985, 279 + xy: 1046, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-node-large-large rotate: false - xy: 943, 195 + xy: 1088, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-node-large-medium rotate: false - xy: 3303, 232 + xy: 1343, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-node-large-small rotate: false - xy: 3711, 287 + xy: 2228, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-node-large-tiny rotate: false - xy: 3188, 118 + xy: 2579, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16454,21 +18330,21 @@ block-power-node-large-xlarge index: -1 block-power-node-medium rotate: false - xy: 3337, 232 + xy: 1377, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-node-small rotate: false - xy: 3737, 287 + xy: 2254, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-node-tiny rotate: false - xy: 3206, 118 + xy: 2561, 43 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16482,28 +18358,28 @@ block-power-node-xlarge index: -1 block-power-source-large rotate: false - xy: 985, 237 + xy: 1130, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-source-medium rotate: false - xy: 3371, 232 + xy: 1411, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-source-small rotate: false - xy: 3740, 261 + xy: 2280, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-source-tiny rotate: false - xy: 3224, 118 + xy: 2579, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16517,28 +18393,28 @@ block-power-source-xlarge index: -1 block-power-void-large rotate: false - xy: 1027, 279 + xy: 1172, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-void-medium rotate: false - xy: 3405, 253 + xy: 1445, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-void-small rotate: false - xy: 3740, 235 + xy: 2306, 151 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-void-tiny rotate: false - xy: 3242, 118 + xy: 2597, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16552,28 +18428,28 @@ block-power-void-xlarge index: -1 block-pulse-conduit-large rotate: false - xy: 985, 195 + xy: 1214, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pulse-conduit-medium rotate: false - xy: 3439, 253 + xy: 1479, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pulse-conduit-small rotate: false - xy: 2389, 191 + xy: 1994, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pulse-conduit-tiny rotate: false - xy: 3260, 118 + xy: 2561, 25 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16587,28 +18463,28 @@ block-pulse-conduit-xlarge index: -1 block-pulverizer-large rotate: false - xy: 1027, 237 + xy: 1256, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pulverizer-medium rotate: false - xy: 3473, 261 + xy: 1513, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pulverizer-small rotate: false - xy: 2415, 191 + xy: 2020, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pulverizer-tiny rotate: false - xy: 3278, 118 + xy: 2579, 43 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16622,28 +18498,28 @@ block-pulverizer-xlarge index: -1 block-pyratite-mixer-large rotate: false - xy: 1027, 195 + xy: 1298, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pyratite-mixer-medium rotate: false - xy: 3507, 261 + xy: 1547, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pyratite-mixer-small rotate: false - xy: 2441, 193 + xy: 2046, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pyratite-mixer-tiny rotate: false - xy: 3296, 118 + xy: 2597, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16657,28 +18533,28 @@ block-pyratite-mixer-xlarge index: -1 block-repair-point-large rotate: false - xy: 1069, 287 + xy: 1340, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-repair-point-medium rotate: false - xy: 3541, 261 + xy: 1581, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-repair-point-small rotate: false - xy: 3453, 167 + xy: 2072, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-repair-point-tiny rotate: false - xy: 3314, 118 + xy: 2615, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16692,28 +18568,28 @@ block-repair-point-xlarge index: -1 block-resupply-point-large rotate: false - xy: 1111, 287 + xy: 1382, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-resupply-point-medium rotate: false - xy: 3575, 261 + xy: 1017, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-resupply-point-small rotate: false - xy: 3479, 167 + xy: 2098, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-resupply-point-tiny rotate: false - xy: 3332, 118 + xy: 2579, 25 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16727,28 +18603,28 @@ block-resupply-point-xlarge index: -1 block-ripple-large rotate: false - xy: 1069, 245 + xy: 1424, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ripple-medium rotate: false - xy: 3609, 261 + xy: 1017, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ripple-small rotate: false - xy: 3505, 167 + xy: 2124, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ripple-tiny rotate: false - xy: 3350, 118 + xy: 2597, 43 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16762,28 +18638,28 @@ block-ripple-xlarge index: -1 block-rotary-pump-large rotate: false - xy: 1153, 287 + xy: 1466, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-rotary-pump-medium rotate: false - xy: 3405, 219 + xy: 1051, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rotary-pump-small rotate: false - xy: 3531, 167 + xy: 2150, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-rotary-pump-tiny rotate: false - xy: 3368, 118 + xy: 2615, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16797,28 +18673,28 @@ block-rotary-pump-xlarge index: -1 block-router-large rotate: false - xy: 1069, 203 + xy: 1508, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-router-medium rotate: false - xy: 3439, 219 + xy: 1017, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-router-small rotate: false - xy: 3557, 167 + xy: 2176, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-router-tiny rotate: false - xy: 2720, 100 + xy: 2597, 25 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16832,28 +18708,28 @@ block-router-xlarge index: -1 block-rtg-generator-large rotate: false - xy: 1111, 245 + xy: 1550, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-rtg-generator-medium rotate: false - xy: 3473, 227 + xy: 1051, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rtg-generator-small rotate: false - xy: 3583, 167 + xy: 2202, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-rtg-generator-tiny rotate: false - xy: 2738, 100 + xy: 2615, 43 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16867,56 +18743,56 @@ block-rtg-generator-xlarge index: -1 block-salt-large rotate: false - xy: 1195, 287 + xy: 1592, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-salt-medium rotate: false - xy: 3507, 227 + xy: 1085, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salt-small rotate: false - xy: 3609, 167 + xy: 2228, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-salt-tiny rotate: false - xy: 2756, 100 + xy: 2615, 25 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-salt-wall-large rotate: false - xy: 1111, 203 + xy: 1634, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-salt-wall-medium rotate: false - xy: 3541, 227 + xy: 1017, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salt-wall-small rotate: false - xy: 3635, 167 + xy: 2254, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-salt-wall-tiny rotate: false - xy: 2774, 100 + xy: 2633, 64 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16937,28 +18813,28 @@ block-salt-xlarge index: -1 block-salvo-large rotate: false - xy: 1153, 245 + xy: 1676, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-salvo-medium rotate: false - xy: 3575, 227 + xy: 1051, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salvo-small rotate: false - xy: 1733, 12 + xy: 2280, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-salvo-tiny rotate: false - xy: 2792, 100 + xy: 2633, 46 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -16972,28 +18848,28 @@ block-salvo-xlarge index: -1 block-sand-boulder-large rotate: false - xy: 1237, 287 + xy: 1718, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-boulder-medium rotate: false - xy: 3609, 227 + xy: 1085, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-boulder-small rotate: false - xy: 1759, 7 + xy: 2306, 125 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-boulder-tiny rotate: false - xy: 2810, 100 + xy: 2633, 28 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17007,56 +18883,56 @@ block-sand-boulder-xlarge index: -1 block-sand-large rotate: false - xy: 1153, 203 + xy: 1760, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-medium rotate: false - xy: 3634, 295 + xy: 1119, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-small rotate: false - xy: 2725, 154 + xy: 2332, 124 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-tiny rotate: false - xy: 2828, 100 + xy: 2489, 6 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-sand-wall-large rotate: false - xy: 1195, 245 + xy: 1802, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-wall-medium rotate: false - xy: 3643, 261 + xy: 1051, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-wall-small rotate: false - xy: 2751, 154 + xy: 1786, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-wall-tiny rotate: false - xy: 2846, 100 + xy: 2507, 6 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17070,28 +18946,28 @@ block-sand-wall-xlarge index: -1 block-sand-water-large rotate: false - xy: 1279, 287 + xy: 1844, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-water-medium rotate: false - xy: 3643, 227 + xy: 1085, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-water-small rotate: false - xy: 2777, 154 + xy: 1812, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-water-tiny rotate: false - xy: 2864, 100 + xy: 2525, 6 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17112,28 +18988,28 @@ block-sand-xlarge index: -1 block-scatter-large rotate: false - xy: 1195, 203 + xy: 1886, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scatter-medium rotate: false - xy: 917, 59 + xy: 1119, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scatter-small rotate: false - xy: 2803, 154 + xy: 1838, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scatter-tiny rotate: false - xy: 2882, 100 + xy: 2543, 6 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17147,28 +19023,28 @@ block-scatter-xlarge index: -1 block-scorch-large rotate: false - xy: 1237, 245 + xy: 1928, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scorch-medium rotate: false - xy: 951, 59 + xy: 1153, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scorch-small rotate: false - xy: 2829, 154 + xy: 1864, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scorch-tiny rotate: false - xy: 2900, 100 + xy: 2561, 7 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17182,28 +19058,28 @@ block-scorch-xlarge index: -1 block-scrap-wall-gigantic-large rotate: false - xy: 1321, 287 + xy: 1970, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-gigantic-medium rotate: false - xy: 985, 59 + xy: 1085, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-gigantic-small rotate: false - xy: 2855, 154 + xy: 1890, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-gigantic-tiny rotate: false - xy: 2918, 100 + xy: 2579, 7 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17217,28 +19093,28 @@ block-scrap-wall-gigantic-xlarge index: -1 block-scrap-wall-huge-large rotate: false - xy: 1237, 203 + xy: 2012, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-huge-medium rotate: false - xy: 1019, 59 + xy: 1119, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-huge-small rotate: false - xy: 2881, 154 + xy: 1916, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-huge-tiny rotate: false - xy: 2936, 100 + xy: 2597, 7 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17252,35 +19128,35 @@ block-scrap-wall-huge-xlarge index: -1 block-scrap-wall-large rotate: false - xy: 1279, 245 + xy: 2054, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-large-large rotate: false - xy: 1363, 287 + xy: 2096, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-large-medium rotate: false - xy: 1053, 59 + xy: 1153, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-large-small rotate: false - xy: 2907, 154 + xy: 1942, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-large-tiny rotate: false - xy: 2954, 100 + xy: 2615, 7 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17294,21 +19170,21 @@ block-scrap-wall-large-xlarge index: -1 block-scrap-wall-medium rotate: false - xy: 949, 25 + xy: 1187, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-small rotate: false - xy: 2933, 154 + xy: 1968, 107 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-tiny rotate: false - xy: 2972, 100 + xy: 2633, 10 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17322,28 +19198,28 @@ block-scrap-wall-xlarge index: -1 block-segment-large rotate: false - xy: 1279, 203 + xy: 2138, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-segment-medium rotate: false - xy: 983, 25 + xy: 1119, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-segment-small rotate: false - xy: 2959, 154 + xy: 1783, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-segment-tiny rotate: false - xy: 2990, 100 + xy: 2651, 64 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17357,28 +19233,28 @@ block-segment-xlarge index: -1 block-separator-large rotate: false - xy: 1321, 245 + xy: 2180, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-separator-medium rotate: false - xy: 1017, 25 + xy: 1153, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-separator-small rotate: false - xy: 2985, 154 + xy: 1783, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-separator-tiny rotate: false - xy: 3008, 100 + xy: 2651, 46 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17392,28 +19268,28 @@ block-separator-xlarge index: -1 block-shale-boulder-large rotate: false - xy: 1405, 287 + xy: 2222, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shale-boulder-medium rotate: false - xy: 1051, 25 + xy: 1187, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-boulder-small rotate: false - xy: 3011, 154 + xy: 1809, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shale-boulder-tiny rotate: false - xy: 3026, 100 + xy: 2651, 28 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17427,56 +19303,56 @@ block-shale-boulder-xlarge index: -1 block-shale-large rotate: false - xy: 1321, 203 + xy: 2264, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shale-medium rotate: false - xy: 1088, 101 + xy: 1221, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-small rotate: false - xy: 3037, 154 + xy: 1809, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shale-tiny rotate: false - xy: 3044, 100 + xy: 2651, 10 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-shale-wall-large rotate: false - xy: 1363, 245 + xy: 2306, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shale-wall-medium rotate: false - xy: 1122, 101 + xy: 1153, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-wall-small rotate: false - xy: 3063, 154 + xy: 1835, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shale-wall-tiny rotate: false - xy: 3062, 100 + xy: 2645, 201 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17497,28 +19373,28 @@ block-shale-xlarge index: -1 block-shock-mine-large rotate: false - xy: 1447, 287 + xy: 2348, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shock-mine-medium rotate: false - xy: 1156, 101 + xy: 1187, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shock-mine-small rotate: false - xy: 3089, 154 + xy: 1835, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shock-mine-tiny rotate: false - xy: 3080, 100 + xy: 2627, 201 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17532,28 +19408,28 @@ block-shock-mine-xlarge index: -1 block-shrubs-large rotate: false - xy: 1363, 203 + xy: 2390, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shrubs-medium rotate: false - xy: 1190, 101 + xy: 1221, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shrubs-small rotate: false - xy: 3115, 154 + xy: 1861, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shrubs-tiny rotate: false - xy: 3098, 100 + xy: 2645, 183 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17567,28 +19443,28 @@ block-shrubs-xlarge index: -1 block-silicon-crucible-large rotate: false - xy: 1405, 245 + xy: 2432, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-silicon-crucible-medium rotate: false - xy: 1224, 101 + xy: 1255, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-silicon-crucible-small rotate: false - xy: 3141, 154 + xy: 1861, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-silicon-crucible-tiny rotate: false - xy: 3116, 100 + xy: 2645, 165 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17602,28 +19478,28 @@ block-silicon-crucible-xlarge index: -1 block-silicon-smelter-large rotate: false - xy: 1489, 287 + xy: 2474, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-silicon-smelter-medium rotate: false - xy: 1258, 101 + xy: 1187, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-silicon-smelter-small rotate: false - xy: 3167, 154 + xy: 1887, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-silicon-smelter-tiny rotate: false - xy: 3134, 100 + xy: 2663, 193 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17637,28 +19513,28 @@ block-silicon-smelter-xlarge index: -1 block-slag-large rotate: false - xy: 1405, 203 + xy: 2516, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-slag-medium rotate: false - xy: 1292, 101 + xy: 1221, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-slag-small rotate: false - xy: 3193, 154 + xy: 1887, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-slag-tiny rotate: false - xy: 3152, 100 + xy: 2681, 193 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17672,28 +19548,28 @@ block-slag-xlarge index: -1 block-snow-boulder-large rotate: false - xy: 1447, 245 + xy: 2558, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-boulder-medium rotate: false - xy: 1326, 101 + xy: 1255, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-boulder-small rotate: false - xy: 3219, 154 + xy: 1913, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-boulder-tiny rotate: false - xy: 3170, 100 + xy: 2663, 175 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17707,42 +19583,42 @@ block-snow-boulder-xlarge index: -1 block-snow-large rotate: false - xy: 1531, 287 + xy: 2600, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-medium rotate: false - xy: 1360, 101 + xy: 1289, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-pine-large rotate: false - xy: 1447, 203 + xy: 2642, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-pine-medium rotate: false - xy: 1394, 101 + xy: 1221, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-pine-small rotate: false - xy: 3245, 154 + xy: 1913, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-pine-tiny rotate: false - xy: 3188, 100 + xy: 2699, 193 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17756,42 +19632,42 @@ block-snow-pine-xlarge index: -1 block-snow-small rotate: false - xy: 3271, 154 + xy: 1939, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-tiny rotate: false - xy: 3206, 100 + xy: 2681, 175 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-snow-wall-large rotate: false - xy: 1489, 245 + xy: 2684, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-wall-medium rotate: false - xy: 1428, 101 + xy: 1255, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-wall-small rotate: false - xy: 3297, 154 + xy: 1939, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-wall-tiny rotate: false - xy: 3224, 100 + xy: 2717, 193 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17812,35 +19688,35 @@ block-snow-xlarge index: -1 block-solar-panel-large rotate: false - xy: 1573, 287 + xy: 2726, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-solar-panel-large-large rotate: false - xy: 1489, 203 + xy: 2768, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-solar-panel-large-medium rotate: false - xy: 1462, 101 + xy: 1289, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-solar-panel-large-small rotate: false - xy: 3323, 154 + xy: 1965, 81 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-solar-panel-large-tiny rotate: false - xy: 3242, 100 + xy: 2699, 175 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17854,21 +19730,21 @@ block-solar-panel-large-xlarge index: -1 block-solar-panel-medium rotate: false - xy: 1496, 101 + xy: 1323, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-solar-panel-small rotate: false - xy: 3349, 154 + xy: 1965, 55 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-solar-panel-tiny rotate: false - xy: 3260, 100 + xy: 2717, 175 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17882,28 +19758,28 @@ block-solar-panel-xlarge index: -1 block-sorter-large rotate: false - xy: 1531, 245 + xy: 2810, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sorter-medium rotate: false - xy: 1530, 101 + xy: 1255, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sorter-small rotate: false - xy: 3375, 154 + xy: 1994, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sorter-tiny rotate: false - xy: 3278, 100 + xy: 2663, 157 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -17915,1304 +19791,1339 @@ block-sorter-xlarge orig: 48, 48 offset: 0, 0 index: -1 -block-spawn-large +block-space-large rotate: false - xy: 1615, 287 + xy: 2852, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spawn-medium +block-space-medium rotate: false - xy: 1564, 101 + xy: 1289, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spawn-small +block-space-small rotate: false - xy: 3401, 141 + xy: 2020, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spawn-tiny +block-space-tiny rotate: false - xy: 3296, 100 + xy: 2681, 157 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spawn-xlarge +block-space-xlarge rotate: false xy: 1709, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spectre-large +block-spawn-large rotate: false - xy: 1531, 203 + xy: 2894, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spectre-medium +block-spawn-medium rotate: false - xy: 1598, 101 + xy: 1323, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spectre-small +block-spawn-small rotate: false - xy: 3427, 141 + xy: 2046, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spectre-tiny +block-spawn-tiny rotate: false - xy: 3314, 100 + xy: 2699, 157 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spectre-xlarge +block-spawn-xlarge rotate: false xy: 1759, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-cluster-large +block-spectre-large rotate: false - xy: 1573, 245 + xy: 2936, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-cluster-medium +block-spectre-medium rotate: false - xy: 1632, 101 + xy: 1357, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-cluster-small +block-spectre-small rotate: false - xy: 3453, 141 + xy: 2072, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-cluster-tiny +block-spectre-tiny rotate: false - xy: 3332, 100 + xy: 2717, 157 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-cluster-xlarge +block-spectre-xlarge rotate: false xy: 1809, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-moss-large +block-spore-cluster-large rotate: false - xy: 1657, 287 + xy: 2978, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-moss-medium +block-spore-cluster-medium rotate: false - xy: 1666, 101 + xy: 1289, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-moss-small +block-spore-cluster-small rotate: false - xy: 3479, 141 + xy: 2098, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-moss-tiny +block-spore-cluster-tiny rotate: false - xy: 3350, 100 + xy: 2735, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-moss-xlarge +block-spore-cluster-xlarge rotate: false xy: 1859, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-pine-large +block-spore-moss-large rotate: false - xy: 1573, 203 + xy: 3020, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-pine-medium +block-spore-moss-medium rotate: false - xy: 1700, 101 + xy: 1323, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-pine-small +block-spore-moss-small rotate: false - xy: 3505, 141 + xy: 2124, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-pine-tiny +block-spore-moss-tiny rotate: false - xy: 3368, 100 + xy: 2753, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-pine-xlarge +block-spore-moss-xlarge rotate: false xy: 1909, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-press-large +block-spore-pine-large rotate: false - xy: 1615, 245 + xy: 3062, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-press-medium +block-spore-pine-medium rotate: false - xy: 1734, 101 + xy: 1357, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-press-small +block-spore-pine-small rotate: false - xy: 3531, 141 + xy: 2150, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-press-tiny +block-spore-pine-tiny rotate: false - xy: 2630, 85 + xy: 2771, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-press-xlarge +block-spore-pine-xlarge rotate: false xy: 1959, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-spore-wall-large +block-spore-press-large rotate: false - xy: 1699, 287 + xy: 3104, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-spore-wall-medium +block-spore-press-medium rotate: false - xy: 1768, 101 + xy: 1391, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-spore-wall-small +block-spore-press-small rotate: false - xy: 3557, 141 + xy: 2176, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-spore-wall-tiny +block-spore-press-tiny rotate: false - xy: 2630, 67 + xy: 2789, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-spore-wall-xlarge +block-spore-press-xlarge rotate: false xy: 2009, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-steam-generator-large +block-spore-wall-large rotate: false - xy: 1615, 203 + xy: 3146, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-steam-generator-medium +block-spore-wall-medium rotate: false - xy: 1802, 101 + xy: 1323, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-steam-generator-small +block-spore-wall-small rotate: false - xy: 3583, 141 + xy: 2202, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-steam-generator-tiny +block-spore-wall-tiny rotate: false - xy: 2648, 85 + xy: 2807, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-steam-generator-xlarge +block-spore-wall-xlarge rotate: false xy: 2059, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-stone-large +block-steam-generator-large rotate: false - xy: 1657, 245 + xy: 3188, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-stone-medium +block-steam-generator-medium rotate: false - xy: 1836, 101 + xy: 1357, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-stone-small +block-steam-generator-small rotate: false - xy: 3609, 141 + xy: 2228, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-stone-tiny +block-steam-generator-tiny rotate: false - xy: 2630, 49 + xy: 2825, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-stone-wall-large - rotate: false - xy: 1741, 287 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-stone-wall-medium - rotate: false - xy: 1870, 101 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-stone-wall-small - rotate: false - xy: 3635, 141 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-stone-wall-tiny - rotate: false - xy: 2648, 67 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-stone-wall-xlarge +block-steam-generator-xlarge rotate: false xy: 2109, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-stone-xlarge +block-stone-large + rotate: false + xy: 3230, 287 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-stone-medium + rotate: false + xy: 1391, 109 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-stone-small + rotate: false + xy: 2254, 99 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-stone-tiny + rotate: false + xy: 2843, 172 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-stone-wall-large + rotate: false + xy: 3272, 287 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-stone-wall-medium + rotate: false + xy: 1425, 143 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-stone-wall-small + rotate: false + xy: 2280, 99 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-stone-wall-tiny + rotate: false + xy: 2861, 172 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-stone-wall-xlarge rotate: false xy: 2159, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-surge-tower-large - rotate: false - xy: 1657, 203 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-surge-tower-medium - rotate: false - xy: 1904, 101 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-surge-tower-small - rotate: false - xy: 2278, 115 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-surge-tower-tiny - rotate: false - xy: 2666, 85 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-surge-tower-xlarge +block-stone-xlarge rotate: false xy: 2209, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-surge-wall-large +block-surge-tower-large rotate: false - xy: 1699, 245 + xy: 3314, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-surge-wall-large-large +block-surge-tower-medium rotate: false - xy: 1783, 287 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-surge-wall-large-medium - rotate: false - xy: 1938, 101 + xy: 1357, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-surge-wall-large-small +block-surge-tower-small rotate: false - xy: 2298, 89 + xy: 2306, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-surge-wall-large-tiny +block-surge-tower-tiny rotate: false - xy: 2630, 31 + xy: 2879, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-surge-wall-large-xlarge +block-surge-tower-xlarge rotate: false xy: 2259, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-surge-wall-medium +block-surge-wall-large rotate: false - xy: 1972, 101 + xy: 3356, 287 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-surge-wall-large-large + rotate: false + xy: 3398, 287 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-surge-wall-large-medium + rotate: false + xy: 1391, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-surge-wall-small +block-surge-wall-large-small rotate: false - xy: 2304, 115 + xy: 2332, 98 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-surge-wall-tiny +block-surge-wall-large-tiny rotate: false - xy: 2648, 49 + xy: 2897, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-surge-wall-xlarge +block-surge-wall-large-xlarge rotate: false xy: 2309, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-swarmer-large +block-surge-wall-medium rotate: false - xy: 1699, 203 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-swarmer-medium - rotate: false - xy: 2006, 101 + xy: 1425, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-swarmer-small +block-surge-wall-small rotate: false - xy: 2308, 63 + xy: 1991, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-swarmer-tiny +block-surge-wall-tiny rotate: false - xy: 2666, 67 + xy: 2915, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-swarmer-xlarge +block-surge-wall-xlarge rotate: false xy: 2359, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-switch-large +block-swarmer-large rotate: false - xy: 1741, 245 + xy: 3440, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-switch-medium +block-swarmer-medium rotate: false - xy: 2040, 101 + xy: 1459, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-switch-small +block-swarmer-small rotate: false - xy: 2308, 37 + xy: 2017, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-switch-tiny +block-swarmer-tiny rotate: false - xy: 2684, 85 + xy: 2933, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-switch-xlarge +block-swarmer-xlarge rotate: false xy: 2409, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tainted-water-large +block-switch-large rotate: false - xy: 1825, 287 + xy: 3482, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-tainted-water-medium +block-switch-medium rotate: false - xy: 2074, 101 + xy: 1391, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tainted-water-small +block-switch-small rotate: false - xy: 2324, 89 + xy: 2043, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tainted-water-tiny +block-switch-tiny rotate: false - xy: 2702, 85 + xy: 2951, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tainted-water-xlarge +block-switch-xlarge rotate: false xy: 2459, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tar-large +block-tainted-water-large rotate: false - xy: 1741, 203 + xy: 3524, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-tar-medium +block-tainted-water-medium rotate: false - xy: 2108, 103 + xy: 1425, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tar-small +block-tainted-water-small rotate: false - xy: 2330, 115 + xy: 2069, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tar-tiny +block-tainted-water-tiny rotate: false - xy: 2648, 31 + xy: 2969, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tar-xlarge +block-tainted-water-xlarge rotate: false xy: 2509, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tendrils-large +block-tar-large rotate: false - xy: 1783, 245 + xy: 3566, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-tendrils-medium +block-tar-medium rotate: false - xy: 2142, 109 + xy: 1459, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tendrils-small +block-tar-small rotate: false - xy: 2334, 63 + xy: 2095, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tendrils-tiny +block-tar-tiny rotate: false - xy: 2666, 49 + xy: 2987, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tendrils-xlarge +block-tar-xlarge rotate: false xy: 2559, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tetrative-reconstructor-large +block-tendrils-large rotate: false - xy: 1867, 287 + xy: 3608, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-tetrative-reconstructor-medium +block-tendrils-medium rotate: false - xy: 2176, 112 + xy: 1493, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tetrative-reconstructor-small +block-tendrils-small rotate: false - xy: 2334, 37 + xy: 2121, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tetrative-reconstructor-tiny +block-tendrils-tiny rotate: false - xy: 2684, 67 + xy: 3005, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tetrative-reconstructor-xlarge +block-tendrils-xlarge rotate: false xy: 2609, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thermal-generator-large +block-tetrative-reconstructor-large rotate: false - xy: 1783, 203 + xy: 3650, 287 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-thermal-generator-medium +block-tetrative-reconstructor-medium rotate: false - xy: 2210, 112 + xy: 1425, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thermal-generator-small +block-tetrative-reconstructor-small rotate: false - xy: 2350, 89 + xy: 2147, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thermal-generator-tiny +block-tetrative-reconstructor-tiny rotate: false - xy: 2666, 31 + xy: 3023, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thermal-generator-xlarge +block-tetrative-reconstructor-xlarge rotate: false xy: 2659, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thermal-pump-large +block-thermal-generator-large rotate: false - xy: 1825, 245 + xy: 3692, 293 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-thermal-pump-medium +block-thermal-generator-medium rotate: false - xy: 2244, 115 + xy: 1459, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thermal-pump-small +block-thermal-generator-small rotate: false - xy: 2356, 115 + xy: 2173, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thermal-pump-tiny +block-thermal-generator-tiny rotate: false - xy: 2684, 49 + xy: 3041, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thermal-pump-xlarge +block-thermal-generator-xlarge rotate: false xy: 2709, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thorium-reactor-large +block-thermal-pump-large rotate: false - xy: 1909, 287 + xy: 3734, 323 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-thorium-reactor-medium +block-thermal-pump-medium rotate: false - xy: 1087, 67 + xy: 1493, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thorium-reactor-small +block-thermal-pump-small rotate: false - xy: 2360, 63 + xy: 2199, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thorium-reactor-tiny +block-thermal-pump-tiny rotate: false - xy: 2702, 67 + xy: 3059, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thorium-reactor-xlarge +block-thermal-pump-xlarge rotate: false xy: 2759, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thorium-wall-large +block-thorium-reactor-large rotate: false - xy: 1825, 203 + xy: 3734, 281 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-thorium-wall-large-large +block-thorium-reactor-medium rotate: false - xy: 1867, 245 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thorium-wall-large-medium - rotate: false - xy: 1121, 67 + xy: 1527, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thorium-wall-large-small +block-thorium-reactor-small rotate: false - xy: 2360, 37 + xy: 2225, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thorium-wall-large-tiny +block-thorium-reactor-tiny rotate: false - xy: 2720, 82 + xy: 3077, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thorium-wall-large-xlarge +block-thorium-reactor-xlarge rotate: false xy: 2809, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thorium-wall-medium +block-thorium-wall-large rotate: false - xy: 1155, 67 + xy: 3692, 251 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thorium-wall-large-large + rotate: false + xy: 3734, 239 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-thorium-wall-large-medium + rotate: false + xy: 1459, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thorium-wall-small +block-thorium-wall-large-small rotate: false - xy: 2376, 89 + xy: 2251, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thorium-wall-tiny +block-thorium-wall-large-tiny rotate: false - xy: 2684, 31 + xy: 3095, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thorium-wall-xlarge +block-thorium-wall-large-xlarge rotate: false xy: 2859, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-thruster-large +block-thorium-wall-medium rotate: false - xy: 1951, 287 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-thruster-medium - rotate: false - xy: 1189, 67 + xy: 1493, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-thruster-small +block-thorium-wall-small rotate: false - xy: 2382, 115 + xy: 2277, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-thruster-tiny +block-thorium-wall-tiny rotate: false - xy: 2702, 49 + xy: 3113, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-thruster-xlarge +block-thorium-wall-xlarge rotate: false xy: 2909, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-titanium-conveyor-large +block-thruster-large rotate: false - xy: 1867, 203 + xy: 1001, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-titanium-conveyor-medium +block-thruster-medium rotate: false - xy: 1223, 67 + xy: 1527, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-titanium-conveyor-small +block-thruster-small rotate: false - xy: 2386, 63 + xy: 2303, 73 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-titanium-conveyor-tiny +block-thruster-tiny rotate: false - xy: 2720, 64 + xy: 3131, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-titanium-conveyor-xlarge +block-thruster-xlarge rotate: false xy: 2959, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-titanium-wall-large +block-titanium-conveyor-large rotate: false - xy: 1909, 245 + xy: 1043, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-titanium-wall-large-large +block-titanium-conveyor-medium rotate: false - xy: 1993, 287 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-titanium-wall-large-medium - rotate: false - xy: 1257, 67 + xy: 1561, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-titanium-wall-large-small +block-titanium-conveyor-small rotate: false - xy: 2386, 37 + xy: 2329, 72 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-titanium-wall-large-tiny +block-titanium-conveyor-tiny rotate: false - xy: 2738, 82 + xy: 3149, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-titanium-wall-large-xlarge +block-titanium-conveyor-xlarge rotate: false xy: 3009, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-titanium-wall-medium +block-titanium-wall-large rotate: false - xy: 1291, 67 + xy: 1085, 245 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-titanium-wall-large-large + rotate: false + xy: 1127, 245 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-titanium-wall-large-medium + rotate: false + xy: 1493, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-titanium-wall-small +block-titanium-wall-large-small rotate: false - xy: 2402, 89 + xy: 1991, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-titanium-wall-tiny +block-titanium-wall-large-tiny rotate: false - xy: 2702, 31 + xy: 3167, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-titanium-wall-xlarge +block-titanium-wall-large-xlarge rotate: false xy: 3059, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-tsunami-large +block-titanium-wall-medium rotate: false - xy: 1909, 203 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-tsunami-medium - rotate: false - xy: 1325, 67 + xy: 1527, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-tsunami-small +block-titanium-wall-small rotate: false - xy: 2408, 115 + xy: 2017, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-tsunami-tiny +block-titanium-wall-tiny rotate: false - xy: 2720, 46 + xy: 3185, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-tsunami-xlarge +block-titanium-wall-xlarge rotate: false xy: 3109, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-underflow-gate-large +block-tsunami-large rotate: false - xy: 1951, 245 + xy: 1169, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-underflow-gate-medium +block-tsunami-medium rotate: false - xy: 1359, 67 + xy: 1561, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-underflow-gate-small +block-tsunami-small rotate: false - xy: 2412, 63 + xy: 2043, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-underflow-gate-tiny +block-tsunami-tiny rotate: false - xy: 2738, 64 + xy: 3203, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-underflow-gate-xlarge +block-tsunami-xlarge rotate: false xy: 3159, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-unloader-large +block-underflow-gate-large rotate: false - xy: 2035, 287 + xy: 1211, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-unloader-medium +block-underflow-gate-medium rotate: false - xy: 1393, 67 + xy: 1527, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-unloader-small +block-underflow-gate-small rotate: false - xy: 2412, 37 + xy: 2069, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-unloader-tiny +block-underflow-gate-tiny rotate: false - xy: 2756, 82 + xy: 3221, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-unloader-xlarge +block-underflow-gate-xlarge rotate: false xy: 3209, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-vault-large +block-unloader-large rotate: false - xy: 1951, 203 + xy: 1253, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-vault-medium +block-unloader-medium rotate: false - xy: 1427, 67 + xy: 1561, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-vault-small +block-unloader-small rotate: false - xy: 2428, 89 + xy: 2095, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-vault-tiny +block-unloader-tiny rotate: false - xy: 2738, 46 + xy: 3239, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-vault-xlarge +block-unloader-xlarge rotate: false xy: 3259, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-water-extractor-large +block-vault-large rotate: false - xy: 1993, 245 + xy: 1295, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-water-extractor-medium +block-vault-medium rotate: false - xy: 1461, 67 + xy: 1561, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-water-extractor-small +block-vault-small rotate: false - xy: 2434, 115 + xy: 2121, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-water-extractor-tiny +block-vault-tiny rotate: false - xy: 2756, 64 + xy: 3257, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-water-extractor-xlarge +block-vault-xlarge rotate: false xy: 3309, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-water-large +block-water-extractor-large rotate: false - xy: 2077, 287 + xy: 1337, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-water-medium +block-water-extractor-medium rotate: false - xy: 1495, 67 + xy: 1017, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-water-small +block-water-extractor-small rotate: false - xy: 2438, 63 + xy: 2147, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-water-tiny +block-water-extractor-tiny rotate: false - xy: 2774, 82 + xy: 3275, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-water-xlarge +block-water-extractor-xlarge rotate: false xy: 3359, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-wave-large +block-water-large rotate: false - xy: 1993, 203 + xy: 1379, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-wave-medium +block-water-medium rotate: false - xy: 1529, 67 + xy: 1051, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-wave-small +block-water-small rotate: false - xy: 2438, 37 + xy: 2173, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-wave-tiny +block-water-tiny rotate: false - xy: 2756, 46 + xy: 3293, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-wave-xlarge +block-water-xlarge rotate: false xy: 3409, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-white-tree-dead-large +block-wave-large rotate: false - xy: 2035, 245 + xy: 1421, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-white-tree-dead-medium +block-wave-medium rotate: false - xy: 1563, 67 + xy: 1085, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-white-tree-dead-small +block-wave-small rotate: false - xy: 2454, 89 + xy: 2199, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-white-tree-dead-tiny +block-wave-tiny rotate: false - xy: 2774, 64 + xy: 3311, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-white-tree-dead-xlarge +block-wave-xlarge rotate: false xy: 3459, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-white-tree-large +block-white-tree-dead-large rotate: false - xy: 2119, 287 + xy: 1463, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-white-tree-medium +block-white-tree-dead-medium rotate: false - xy: 1597, 67 + xy: 1119, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-white-tree-small +block-white-tree-dead-small rotate: false - xy: 2460, 115 + xy: 2225, 47 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-white-tree-tiny +block-white-tree-dead-tiny rotate: false - xy: 2792, 82 + xy: 3329, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-white-tree-xlarge +block-white-tree-dead-xlarge rotate: false xy: 3509, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 +block-white-tree-large + rotate: false + xy: 1505, 245 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-white-tree-medium + rotate: false + xy: 1153, 7 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-white-tree-small + rotate: false + xy: 2251, 47 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-white-tree-tiny + rotate: false + xy: 3347, 172 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-white-tree-xlarge + rotate: false + xy: 3559, 413 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 button rotate: false - xy: 3011, 300 + xy: 2989, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19276,7 +21187,7 @@ button-right-disabled index: -1 button-edge-over-4 rotate: false - xy: 2497, 258 + xy: 4059, 310 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19284,7 +21195,7 @@ button-edge-over-4 index: -1 button-over rotate: false - xy: 2707, 300 + xy: 4059, 281 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19292,7 +21203,7 @@ button-over index: -1 button-red rotate: false - xy: 2535, 258 + xy: 4059, 252 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19300,7 +21211,7 @@ button-red index: -1 button-right rotate: false - xy: 2821, 300 + xy: 2799, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19308,7 +21219,7 @@ button-right index: -1 button-right-down rotate: false - xy: 2745, 300 + xy: 2723, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19316,7 +21227,7 @@ button-right-down index: -1 button-right-over rotate: false - xy: 2783, 300 + xy: 2761, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19324,7 +21235,7 @@ button-right-over index: -1 button-select rotate: false - xy: 2464, 63 + xy: 2277, 47 size: 24, 24 split: 4, 4, 4, 4 orig: 24, 24 @@ -19332,7 +21243,7 @@ button-select index: -1 button-square rotate: false - xy: 2935, 300 + xy: 2913, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19340,7 +21251,7 @@ button-square index: -1 button-square-down rotate: false - xy: 2859, 300 + xy: 2837, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19348,7 +21259,7 @@ button-square-down index: -1 button-square-over rotate: false - xy: 2897, 300 + xy: 2875, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19356,7 +21267,7 @@ button-square-over index: -1 button-trans rotate: false - xy: 2973, 300 + xy: 2951, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19364,42 +21275,42 @@ button-trans index: -1 check-disabled rotate: false - xy: 1631, 67 + xy: 1187, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-off rotate: false - xy: 1665, 67 + xy: 1221, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on rotate: false - xy: 1699, 67 + xy: 1255, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-disabled rotate: false - xy: 1733, 67 + xy: 1289, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-over rotate: false - xy: 1767, 67 + xy: 1323, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-over rotate: false - xy: 1801, 67 + xy: 1357, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -19413,14 +21324,14 @@ clear index: -1 crater rotate: false - xy: 3453, 199 + xy: 1789, 1 size: 18, 18 orig: 18, 18 offset: 0, 0 index: -1 cursor rotate: false - xy: 845, 366 + xy: 2003, 247 size: 4, 4 orig: 4, 4 offset: 0, 0 @@ -19434,7 +21345,7 @@ discord-banner index: -1 flat-down-base rotate: false - xy: 3049, 300 + xy: 3027, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19449,7 +21360,7 @@ info-banner index: -1 inventory rotate: false - xy: 2278, 141 + xy: 3835, 271 size: 24, 40 split: 10, 10, 10, 14 orig: 24, 40 @@ -19457,147 +21368,147 @@ inventory index: -1 item-blast-compound-icon rotate: false - xy: 1835, 67 + xy: 1391, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-coal-icon rotate: false - xy: 1869, 67 + xy: 1425, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-copper-icon rotate: false - xy: 1903, 67 + xy: 1459, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-graphite-icon rotate: false - xy: 1937, 67 + xy: 1493, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-lead-icon rotate: false - xy: 1971, 67 + xy: 1527, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-metaglass-icon rotate: false - xy: 2005, 67 + xy: 1561, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-phase-fabric-icon rotate: false - xy: 2039, 67 + xy: 1595, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-plastanium-icon rotate: false - xy: 2073, 67 + xy: 1595, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-pyratite-icon rotate: false - xy: 3473, 193 + xy: 1595, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-sand-icon rotate: false - xy: 3507, 193 + xy: 1595, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-scrap-icon rotate: false - xy: 3541, 193 + xy: 1595, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-silicon-icon rotate: false - xy: 3575, 193 + xy: 1615, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-spore-pod-icon rotate: false - xy: 3609, 193 + xy: 1629, 143 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-surge-alloy-icon rotate: false - xy: 3643, 193 + xy: 1629, 109 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-thorium-icon rotate: false - xy: 3668, 301 + xy: 1629, 75 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-titanium-icon rotate: false - xy: 3677, 267 + xy: 1629, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-cryofluid-icon rotate: false - xy: 3677, 233 + xy: 1629, 7 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-oil-icon rotate: false - xy: 3677, 199 + xy: 1649, 179 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-slag-icon rotate: false - xy: 1087, 33 + xy: 1663, 145 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-water-icon rotate: false - xy: 1121, 33 + xy: 1663, 111 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 logic-node rotate: false - xy: 1155, 33 + xy: 1663, 77 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -19618,7 +21529,7 @@ nomap index: -1 pane rotate: false - xy: 3125, 300 + xy: 3103, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19626,7 +21537,7 @@ pane index: -1 pane-2 rotate: false - xy: 3087, 300 + xy: 3065, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19634,7 +21545,7 @@ pane-2 index: -1 scroll rotate: false - xy: 2464, 26 + xy: 2303, 36 size: 24, 35 split: 10, 10, 6, 5 orig: 24, 35 @@ -19642,7 +21553,7 @@ scroll index: -1 scroll-horizontal rotate: false - xy: 901, 169 + xy: 3407, 261 size: 35, 24 split: 6, 5, 10, 10 orig: 35, 24 @@ -19650,70 +21561,70 @@ scroll-horizontal index: -1 scroll-knob-horizontal-black rotate: false - xy: 859, 169 + xy: 859, 172 size: 40, 24 orig: 40, 24 offset: 0, 0 index: -1 scroll-knob-vertical-black rotate: false - xy: 2304, 141 + xy: 3861, 271 size: 24, 40 orig: 24, 40 offset: 0, 0 index: -1 scroll-knob-vertical-thin rotate: false - xy: 3766, 245 + xy: 3995, 271 size: 12, 40 orig: 12, 40 offset: 0, 0 index: -1 selection rotate: false - xy: 309, 354 + xy: 1001, 310 size: 1, 1 orig: 1, 1 offset: 0, 0 index: -1 slider rotate: false - xy: 3754, 329 + xy: 3689, 277 size: 1, 8 orig: 1, 8 offset: 0, 0 index: -1 slider-knob rotate: false - xy: 1970, 27 + xy: 3489, 197 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-down rotate: false - xy: 2001, 27 + xy: 3520, 197 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-over rotate: false - xy: 2032, 27 + xy: 3489, 157 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-vertical rotate: false - xy: 2194, 83 + xy: 309, 354 size: 8, 1 orig: 8, 1 offset: 0, 0 index: -1 underline rotate: false - xy: 3315, 300 + xy: 3293, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19721,7 +21632,7 @@ underline index: -1 underline-2 rotate: false - xy: 3163, 300 + xy: 3141, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19729,7 +21640,7 @@ underline-2 index: -1 underline-disabled rotate: false - xy: 3201, 300 + xy: 3179, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19737,7 +21648,7 @@ underline-disabled index: -1 underline-red rotate: false - xy: 3239, 300 + xy: 3217, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19745,7 +21656,7 @@ underline-red index: -1 underline-white rotate: false - xy: 3277, 300 + xy: 3255, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -19753,35 +21664,35 @@ underline-white index: -1 unit-alpha-large rotate: false - xy: 2035, 203 + xy: 1547, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-alpha-medium rotate: false - xy: 1189, 33 + xy: 1663, 43 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-alpha-small rotate: false - xy: 2480, 89 + xy: 2329, 46 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-alpha-tiny rotate: false - xy: 2774, 46 + xy: 3365, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-alpha-xlarge rotate: false - xy: 3559, 413 + xy: 3609, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 @@ -19795,189 +21706,189 @@ unit-antumbra-large index: -1 unit-antumbra-medium rotate: false - xy: 2063, 33 + xy: 3776, 271 size: 28, 32 orig: 28, 32 offset: 0, 0 index: -1 unit-antumbra-small rotate: false - xy: 3734, 339 + xy: 257, 20 size: 21, 24 orig: 21, 24 offset: 0, 0 index: -1 unit-antumbra-tiny rotate: false - xy: 2607, 261 + xy: 2623, 219 size: 14, 16 orig: 14, 16 offset: 0, 0 index: -1 unit-antumbra-xlarge rotate: false - xy: 945, 363 + xy: 959, 363 size: 43, 48 orig: 43, 48 offset: 0, 0 index: -1 unit-arkyid-large rotate: false - xy: 2077, 245 + xy: 1589, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-arkyid-medium rotate: false - xy: 1223, 33 + xy: 1663, 9 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-arkyid-small rotate: false - xy: 2486, 115 + xy: 2358, 110 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-arkyid-tiny rotate: false - xy: 2792, 64 + xy: 3383, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-arkyid-xlarge rotate: false - xy: 3609, 413 + xy: 3659, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-atrax-large rotate: false - xy: 2161, 298 + xy: 1631, 256 size: 40, 29 orig: 40, 29 offset: 0, 0 index: -1 unit-atrax-medium rotate: false - xy: 1257, 42 + xy: 1683, 186 size: 32, 23 orig: 32, 23 offset: 0, 0 index: -1 unit-atrax-small rotate: false - xy: 982, 6 + xy: 1731, 25 size: 24, 17 orig: 24, 17 offset: 0, 0 index: -1 unit-atrax-tiny rotate: false - xy: 2707, 287 + xy: 2723, 245 size: 16, 11 orig: 16, 11 offset: 0, 0 index: -1 unit-atrax-xlarge rotate: false - xy: 3659, 427 + xy: 3709, 427 size: 48, 34 orig: 48, 34 offset: 0, 0 index: -1 unit-beta-large rotate: false - xy: 2077, 205 + xy: 1673, 247 size: 40, 38 orig: 40, 38 offset: 0, 0 index: -1 unit-beta-medium rotate: false - xy: 1085, 1 + xy: 3776, 239 size: 32, 30 orig: 32, 30 offset: 0, 0 index: -1 unit-beta-small rotate: false - xy: 2201, 1 + xy: 2358, 85 size: 24, 23 orig: 24, 23 offset: 0, 0 index: -1 unit-beta-tiny rotate: false - xy: 2810, 83 + xy: 881, 155 size: 16, 15 orig: 16, 15 offset: 0, 0 index: -1 unit-beta-xlarge rotate: false - xy: 3709, 415 + xy: 3759, 415 size: 48, 46 orig: 48, 46 offset: 0, 0 index: -1 unit-bryde-large rotate: false - xy: 2119, 245 + xy: 1715, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-bryde-medium rotate: false - xy: 1291, 33 + xy: 3791, 205 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-bryde-small rotate: false - xy: 2227, 8 + xy: 2355, 59 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-bryde-tiny rotate: false - xy: 2792, 46 + xy: 3401, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-bryde-xlarge rotate: false - xy: 3759, 413 + xy: 3809, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-corvus-large rotate: false - xy: 2203, 301 + xy: 1757, 259 size: 40, 26 orig: 40, 26 offset: 0, 0 index: -1 unit-corvus-medium rotate: false - xy: 916, 37 + xy: 1697, 1 size: 31, 20 orig: 31, 20 offset: 0, 0 index: -1 unit-corvus-small rotate: false - xy: 3740, 218 + xy: 3859, 313 size: 24, 15 orig: 24, 15 offset: 0, 0 @@ -19991,336 +21902,336 @@ unit-corvus-tiny index: -1 unit-corvus-xlarge rotate: false - xy: 3809, 430 + xy: 3859, 430 size: 48, 31 orig: 48, 31 offset: 0, 0 index: -1 unit-crawler-large rotate: false - xy: 2161, 256 + xy: 1799, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-crawler-medium rotate: false - xy: 1325, 33 + xy: 3825, 329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-crawler-small rotate: false - xy: 3763, 192 + xy: 2355, 33 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-crawler-tiny rotate: false - xy: 2810, 65 + xy: 2735, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-crawler-xlarge rotate: false - xy: 3859, 413 + xy: 3909, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-dagger-large rotate: false - xy: 2203, 259 + xy: 1841, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-dagger-medium rotate: false - xy: 1359, 33 + xy: 1697, 152 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-dagger-small rotate: false - xy: 2490, 63 + xy: 2329, 20 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-dagger-tiny rotate: false - xy: 2828, 82 + xy: 2753, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-dagger-xlarge rotate: false - xy: 3909, 413 + xy: 3959, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-eclipse-large rotate: false - xy: 2245, 287 + xy: 1883, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-eclipse-medium rotate: false - xy: 1393, 33 + xy: 1697, 118 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-eclipse-small rotate: false - xy: 2490, 37 + xy: 2355, 7 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-eclipse-tiny rotate: false - xy: 2810, 47 + xy: 2771, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-eclipse-xlarge rotate: false - xy: 3959, 413 + xy: 4009, 413 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-flare-large rotate: false - xy: 2287, 287 + xy: 1925, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-flare-medium rotate: false - xy: 1427, 33 + xy: 1697, 84 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-flare-small rotate: false - xy: 2506, 89 + xy: 2384, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-flare-tiny rotate: false - xy: 2828, 64 + xy: 2789, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-flare-xlarge rotate: false - xy: 4009, 413 + xy: 3859, 380 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-fortress-large rotate: false - xy: 2119, 211 + xy: 1967, 253 size: 40, 32 orig: 40, 32 offset: 0, 0 index: -1 unit-fortress-medium rotate: false - xy: 1119, 6 + xy: 1697, 57 size: 32, 25 orig: 32, 25 offset: 0, 0 index: -1 unit-fortress-small rotate: false - xy: 1008, 4 + xy: 1757, 23 size: 24, 19 orig: 24, 19 offset: 0, 0 index: -1 unit-fortress-tiny rotate: false - xy: 3754, 313 + xy: 2476, 125 size: 16, 12 orig: 16, 12 offset: 0, 0 index: -1 unit-fortress-xlarge rotate: false - xy: 3809, 390 + xy: 3909, 373 size: 48, 38 orig: 48, 38 offset: 0, 0 index: -1 unit-gamma-large rotate: false - xy: 2161, 214 + xy: 2009, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-gamma-medium rotate: false - xy: 1461, 33 + xy: 1697, 23 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-gamma-small rotate: false - xy: 2512, 115 + xy: 1783, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-gamma-tiny rotate: false - xy: 2846, 82 + xy: 2807, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-gamma-xlarge rotate: false - xy: 3659, 377 + xy: 3959, 363 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-horizon-large rotate: false - xy: 2203, 217 + xy: 2051, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-horizon-medium rotate: false - xy: 1495, 33 + xy: 3586, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-horizon-small rotate: false - xy: 2516, 63 + xy: 2410, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-horizon-tiny rotate: false - xy: 2846, 64 + xy: 2825, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-horizon-xlarge rotate: false - xy: 3709, 365 + xy: 4009, 363 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-mace-large rotate: false - xy: 2245, 245 + xy: 2093, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-mace-medium rotate: false - xy: 1529, 33 + xy: 3620, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-mace-small rotate: false - xy: 2516, 37 + xy: 1809, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-mace-tiny rotate: false - xy: 2864, 82 + xy: 2843, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-mace-xlarge rotate: false - xy: 3759, 363 + xy: 3709, 377 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-mega-large rotate: false - xy: 2329, 287 + xy: 2135, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-mega-medium rotate: false - xy: 1563, 33 + xy: 3654, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-mega-small rotate: false - xy: 2532, 89 + xy: 2436, 99 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-mega-tiny rotate: false - xy: 2864, 64 + xy: 2861, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-mega-xlarge rotate: false - xy: 3809, 340 + xy: 3759, 365 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-minke-large rotate: false - xy: 881, 85 + xy: 3481, 245 size: 34, 40 orig: 34, 40 offset: 0, 0 index: -1 unit-minke-medium rotate: false - xy: 2123, 33 + xy: 3806, 271 size: 27, 32 orig: 27, 32 offset: 0, 0 @@ -20334,210 +22245,210 @@ unit-minke-small index: -1 unit-minke-tiny rotate: false - xy: 1785, 15 + xy: 4044, 253 size: 13, 16 orig: 13, 16 offset: 0, 0 index: -1 unit-minke-xlarge rotate: false - xy: 1035, 363 + xy: 859, 198 size: 41, 48 orig: 41, 48 offset: 0, 0 index: -1 unit-mono-large rotate: false - xy: 2287, 245 + xy: 2177, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-mono-medium rotate: false - xy: 1597, 33 + xy: 3688, 183 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-mono-small rotate: false - xy: 2538, 115 + xy: 1835, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-mono-tiny rotate: false - xy: 2882, 82 + xy: 2879, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-mono-xlarge rotate: false - xy: 3859, 363 + xy: 3809, 363 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-nova-large rotate: false - xy: 2371, 287 + xy: 2219, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-nova-medium rotate: false - xy: 1631, 33 + xy: 3722, 171 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-nova-small rotate: false - xy: 2542, 63 + xy: 1861, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-nova-tiny rotate: false - xy: 2882, 64 + xy: 2897, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-nova-xlarge rotate: false - xy: 3909, 363 + xy: 3859, 330 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-oct-large rotate: false - xy: 2329, 245 + xy: 2261, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-oct-medium rotate: false - xy: 1665, 33 + xy: 3756, 171 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-oct-small rotate: false - xy: 2542, 37 + xy: 1887, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-oct-tiny rotate: false - xy: 2900, 82 + xy: 2915, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-oct-xlarge rotate: false - xy: 3959, 363 + xy: 3909, 323 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-omura-large rotate: false - xy: 2093, 25 + xy: 3520, 155 size: 28, 40 orig: 28, 40 offset: 0, 0 index: -1 unit-omura-medium rotate: false - xy: 2467, 186 + xy: 1733, 211 size: 22, 32 orig: 22, 32 offset: 0, 0 index: -1 unit-omura-small rotate: false - xy: 3763, 287 + xy: 2933, 146 size: 16, 24 orig: 16, 24 offset: 0, 0 index: -1 unit-omura-tiny rotate: false - xy: 1856, 15 + xy: 4084, 156 size: 11, 16 orig: 11, 16 offset: 0, 0 index: -1 unit-omura-xlarge rotate: false - xy: 881, 35 + xy: 3517, 237 size: 33, 48 orig: 33, 48 offset: 0, 0 index: -1 unit-poly-large rotate: false - xy: 2413, 287 + xy: 2303, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-poly-medium rotate: false - xy: 1699, 33 + xy: 3790, 171 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-poly-small rotate: false - xy: 2558, 89 + xy: 1913, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-poly-tiny rotate: false - xy: 2900, 64 + xy: 2951, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-poly-xlarge rotate: false - xy: 4009, 363 + xy: 3959, 313 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-pulsar-large rotate: false - xy: 2371, 251 + xy: 2345, 251 size: 40, 34 orig: 40, 34 offset: 0, 0 index: -1 unit-pulsar-medium rotate: false - xy: 1733, 38 + xy: 2345, 222 size: 32, 27 orig: 32, 27 offset: 0, 0 index: -1 unit-pulsar-small rotate: false - xy: 1034, 3 + xy: 1763, 1 size: 24, 20 orig: 24, 20 offset: 0, 0 @@ -20551,168 +22462,168 @@ unit-pulsar-tiny index: -1 unit-pulsar-xlarge rotate: false - xy: 131, 4 + xy: 4009, 321 size: 48, 40 orig: 48, 40 offset: 0, 0 index: -1 unit-quad-large rotate: false - xy: 2455, 287 + xy: 2387, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-quad-medium rotate: false - xy: 1937, 34 + xy: 3776, 332 size: 31, 31 orig: 31, 31 offset: 0, 0 index: -1 unit-quad-small rotate: false - xy: 2564, 115 + xy: 1939, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-quad-tiny rotate: false - xy: 2828, 47 + xy: 3692, 396 size: 15, 15 orig: 15, 15 offset: 0, 0 index: -1 unit-quad-xlarge rotate: false - xy: 3859, 313 + xy: 4009, 271 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-quasar-large rotate: false - xy: 2497, 287 + xy: 2429, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-quasar-medium rotate: false - xy: 1767, 33 + xy: 2343, 188 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-quasar-small rotate: false - xy: 2568, 63 + xy: 1965, 29 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-quasar-tiny rotate: false - xy: 2918, 82 + xy: 2969, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-quasar-xlarge rotate: false - xy: 3909, 313 + xy: 859, 363 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-reign-large rotate: false - xy: 2245, 217 + xy: 1757, 231 size: 40, 26 orig: 40, 26 offset: 0, 0 index: -1 unit-reign-medium rotate: false - xy: 949, 3 + xy: 1730, 1 size: 31, 20 orig: 31, 20 offset: 0, 0 index: -1 unit-reign-small rotate: false - xy: 2568, 46 + xy: 1991, 30 size: 24, 15 orig: 24, 15 offset: 0, 0 index: -1 unit-reign-tiny rotate: false - xy: 181, 1 + xy: 3734, 365 size: 15, 10 orig: 15, 10 offset: 0, 0 index: -1 unit-reign-xlarge rotate: false - xy: 181, 13 + xy: 859, 330 size: 48, 31 orig: 48, 31 offset: 0, 0 index: -1 unit-risso-large rotate: false - xy: 881, 127 + xy: 3444, 245 size: 35, 40 orig: 35, 40 offset: 0, 0 index: -1 unit-risso-medium rotate: false - xy: 2107, 67 + xy: 3551, 177 size: 28, 32 orig: 28, 32 offset: 0, 0 index: -1 unit-risso-small rotate: false - xy: 2264, 191 + xy: 2447, 219 size: 21, 24 orig: 21, 24 offset: 0, 0 index: -1 unit-risso-tiny rotate: false - xy: 3661, 175 + xy: 2539, 227 size: 14, 16 orig: 14, 16 offset: 0, 0 index: -1 unit-risso-xlarge rotate: false - xy: 990, 363 + xy: 959, 313 size: 43, 48 orig: 43, 48 offset: 0, 0 index: -1 unit-scepter-large rotate: false - xy: 2413, 253 + xy: 2471, 253 size: 40, 32 orig: 40, 32 offset: 0, 0 index: -1 unit-scepter-medium rotate: false - xy: 1801, 39 + xy: 2379, 217 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 unit-scepter-small rotate: false - xy: 2490, 16 + xy: 2017, 26 size: 24, 19 orig: 24, 19 offset: 0, 0 @@ -20726,84 +22637,84 @@ unit-scepter-tiny index: -1 unit-scepter-xlarge rotate: false - xy: 231, 5 + xy: 859, 289 size: 48, 39 orig: 48, 39 offset: 0, 0 index: -1 unit-sei-large rotate: false - xy: 2539, 287 + xy: 2513, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-sei-medium rotate: false - xy: 1835, 33 + xy: 2413, 211 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-sei-small rotate: false - xy: 2516, 11 + xy: 2043, 21 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-sei-tiny rotate: false - xy: 2918, 64 + xy: 2987, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-sei-xlarge rotate: false - xy: 3959, 313 + xy: 909, 363 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-spiroct-large rotate: false - xy: 2455, 254 + xy: 2555, 254 size: 40, 31 orig: 40, 31 offset: 0, 0 index: -1 unit-spiroct-medium rotate: false - xy: 1153, 6 + xy: 3776, 305 size: 31, 25 orig: 31, 25 offset: 0, 0 index: -1 unit-spiroct-small rotate: false - xy: 2542, 16 + xy: 2069, 26 size: 24, 19 orig: 24, 19 offset: 0, 0 index: -1 unit-spiroct-tiny rotate: false - xy: 3772, 313 + xy: 3692, 382 size: 15, 12 orig: 15, 12 offset: 0, 0 index: -1 unit-spiroct-xlarge rotate: false - xy: 4009, 323 + xy: 909, 323 size: 48, 38 orig: 48, 38 offset: 0, 0 index: -1 unit-toxopid-large rotate: false - xy: 3429, 287 + xy: 3552, 245 size: 33, 40 orig: 33, 40 offset: 0, 0 @@ -20817,42 +22728,42 @@ unit-toxopid-medium index: -1 unit-toxopid-small rotate: false - xy: 2590, 115 + xy: 2147, 21 size: 20, 24 orig: 20, 24 offset: 0, 0 index: -1 unit-toxopid-tiny rotate: false - xy: 3793, 345 + xy: 899, 1 size: 13, 16 orig: 13, 16 offset: 0, 0 index: -1 unit-toxopid-xlarge rotate: false - xy: 2581, 279 + xy: 2597, 237 size: 40, 48 orig: 40, 48 offset: 0, 0 index: -1 unit-vela-large rotate: false - xy: 2623, 295 + xy: 2639, 253 size: 40, 32 orig: 40, 32 offset: 0, 0 index: -1 unit-vela-medium rotate: false - xy: 1869, 39 + xy: 2377, 189 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 unit-vela-small rotate: false - xy: 2568, 25 + xy: 2095, 26 size: 24, 19 orig: 24, 19 offset: 0, 0 @@ -20866,49 +22777,49 @@ unit-vela-tiny index: -1 unit-vela-xlarge rotate: false - xy: 845, 372 + xy: 859, 248 size: 48, 39 orig: 48, 39 offset: 0, 0 index: -1 unit-zenith-large rotate: false - xy: 2665, 287 + xy: 2681, 245 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 unit-zenith-medium rotate: false - xy: 1903, 33 + xy: 2411, 177 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unit-zenith-small rotate: false - xy: 2584, 89 + xy: 2121, 21 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 unit-zenith-tiny rotate: false - xy: 2936, 82 + xy: 3005, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 unit-zenith-xlarge rotate: false - xy: 895, 363 + xy: 909, 273 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 wavepane rotate: false - xy: 3353, 300 + xy: 3331, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -20916,7 +22827,7 @@ wavepane index: -1 white-pane rotate: false - xy: 3391, 300 + xy: 3369, 258 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -20931,7 +22842,7 @@ whiteui index: -1 window-empty rotate: false - xy: 3711, 218 + xy: 1731, 122 size: 27, 61 split: 4, 4, 2, 2 orig: 27, 61 diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png index 6a698b472a..71293fe7a0 100644 Binary files a/core/assets/sprites/sprites.png and b/core/assets/sprites/sprites.png differ diff --git a/core/assets/sprites/sprites2.png b/core/assets/sprites/sprites2.png index efc457f2e4..a088daddcf 100644 Binary files a/core/assets/sprites/sprites2.png and b/core/assets/sprites/sprites2.png differ diff --git a/core/assets/sprites/sprites3.png b/core/assets/sprites/sprites3.png index 6e90118bff..627f4e763c 100644 Binary files a/core/assets/sprites/sprites3.png and b/core/assets/sprites/sprites3.png differ diff --git a/core/assets/sprites/sprites4.png b/core/assets/sprites/sprites4.png index 1a7eeb2a5c..20eed12539 100644 Binary files a/core/assets/sprites/sprites4.png and b/core/assets/sprites/sprites4.png differ diff --git a/core/assets/sprites/sprites5.png b/core/assets/sprites/sprites5.png index 9fb3b87450..2fe5605d60 100644 Binary files a/core/assets/sprites/sprites5.png and b/core/assets/sprites/sprites5.png differ diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 99d5567fda..2cf07cbea6 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -36,6 +36,8 @@ public class Vars implements Loadable{ public static boolean loadLocales = true; /** Whether the logger is loaded. */ public static boolean loadedLogger = false, loadedFileLogger = false; + /** Whether to show the cliff button in the editor*/ + public static boolean addCliffButton = false; /** Maximum extra padding around deployment schematics. */ public static final int maxLoadoutSchematicPad = 5; /** Maximum schematic size.*/ @@ -82,10 +84,14 @@ public class Vars implements Loadable{ public static final float buildingRange = 220f; /** range for moving items */ public static final float itemTransferRange = 220f; + /** range for moving items for logic units */ + public static final float logicItemTransferRange = 45f; /** duration of time between turns in ticks */ - public static final float turnDuration = 20 * Time.toMinutes; - /** turns needed to destroy a sector completely */ - public static final float sectorDestructionTurns = 3f; + public static final float turnDuration = 2 * Time.toMinutes; + /** chance of an invasion per turn, 1 = 100% */ + public static final float baseInvasionChance = 1f / 30f; + /** how many turns have to pass before invasions start */ + public static final int invasionGracePeriod = 20; /** min armor fraction damage; e.g. 0.05 = at least 5% damage */ public static final float minArmorDamage = 0.1f; /** launch animation duration */ @@ -182,13 +188,12 @@ public class Vars implements Loadable{ public static GameState state; public static EntityCollisions collisions; public static DefaultWaves defaultWaves; - public static mindustry.audio.LoopControl loops; + public static LoopControl loops; public static Platform platform = new Platform(){}; public static Mods mods; public static Schematics schematics; public static BeControl becontrol; public static AsyncCore asyncCore; - public static TeamIndexProcess teamIndex; public static BaseRegistry bases; public static Universe universe; @@ -280,10 +285,10 @@ public class Vars implements Loadable{ if(loadedLogger) return; String[] tags = {"[green][D][]", "[royal][I][]", "[yellow][W][]", "[scarlet][E][]", ""}; - String[] stags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""}; + String[] stags = {"&lc&fb[D]", "&lb&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""}; Seq logBuffer = new Seq<>(); - Log.setLogger((level, text) -> { + Log.logger = (level, text) -> { String result = text; String rawText = Log.format(stags[level.ordinal()] + "&fr " + text); System.out.println(rawText); @@ -299,9 +304,9 @@ public class Vars implements Loadable{ } } - ui.scriptfrag.addMessage(Log.removeCodes(result)); + ui.scriptfrag.addMessage(Log.removeColors(result)); } - }); + }; Events.on(ClientLoadEvent.class, e -> logBuffer.each(ui.scriptfrag::addMessage)); @@ -314,18 +319,19 @@ public class Vars implements Loadable{ settings.setAppName(appName); Writer writer = settings.getDataDirectory().child("last_log.txt").writer(false); - LogHandler log = Log.getLogger(); - Log.setLogger((level, text) -> { + LogHandler log = Log.logger; + //ignore it + Log.logger = (level, text) -> { log.log(level, text); try{ - writer.write("[" + Character.toUpperCase(level.name().charAt(0)) +"] " + Log.removeCodes(text) + "\n"); + writer.write("[" + Character.toUpperCase(level.name().charAt(0)) +"] " + Log.removeColors(text) + "\n"); writer.flush(); }catch(IOException e){ e.printStackTrace(); //ignore it } - }); + }; loadedFileLogger = true; } diff --git a/core/src/mindustry/ai/BaseAI.java b/core/src/mindustry/ai/BaseAI.java index 83f393cc83..2c1fb11617 100644 --- a/core/src/mindustry/ai/BaseAI.java +++ b/core/src/mindustry/ai/BaseAI.java @@ -7,6 +7,7 @@ import arc.util.*; import mindustry.*; import mindustry.ai.BaseRegistry.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.game.*; import mindustry.game.Schematic.*; import mindustry.game.Teams.*; @@ -23,7 +24,7 @@ public class BaseAI{ private static final Vec2 axis = new Vec2(), rotator = new Vec2(); private static final float correctPercent = 0.5f; private static final float step = 5; - private static final int attempts = 5; + private static final int attempts = 4; private static final float emptyChance = 0.01f; private static final int timerStep = 0, timerSpawn = 1; @@ -40,11 +41,11 @@ public class BaseAI{ } public void update(){ - if(timer.get(timerSpawn, 60) && data.hasCore()){ + if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 2.5f) && data.hasCore()){ CoreBlock block = (CoreBlock)data.core().block; //create AI core unit - if(!Groups.unit.contains(u -> u.team() == data.team && u.type() == block.unitType)){ + if(!state.isEditor() && !Groups.unit.contains(u -> u.team() == data.team && u.type == block.unitType)){ Unit unit = block.unitType.create(data.team); unit.set(data.core()); unit.add(); @@ -68,9 +69,14 @@ public class BaseAI{ if(pos == null) return; Tmp.v1.rnd(Mathf.random(range)); - int wx = (int)(world.toTile(pos.getX()) + Tmp.v1.x), wy = (int)(world.toTile(pos.getY()) + Tmp.v1.y); + int wx = (int)(World.toTile(pos.getX()) + Tmp.v1.x), wy = (int)(World.toTile(pos.getY()) + Tmp.v1.y); Tile tile = world.tiles.getc(wx, wy); + //try not to block the spawn point + if(spawner.getSpawns().contains(t -> t.within(tile, tilesize * 40f))){ + continue; + } + Seq parts = null; //pick a completely random base part, and place it a random location diff --git a/core/src/mindustry/ai/BaseRegistry.java b/core/src/mindustry/ai/BaseRegistry.java index d5922ac822..269b79d3bf 100644 --- a/core/src/mindustry/ai/BaseRegistry.java +++ b/core/src/mindustry/ai/BaseRegistry.java @@ -9,6 +9,7 @@ import mindustry.game.*; import mindustry.game.Schematic.*; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.environment.*; import mindustry.world.blocks.production.*; import mindustry.world.blocks.sandbox.*; import mindustry.world.blocks.storage.*; @@ -19,9 +20,13 @@ import java.io.*; import static mindustry.Vars.*; public class BaseRegistry{ + /** cores, sorted by tier */ public Seq cores = new Seq<>(); + /** parts with no requirement */ public Seq parts = new Seq<>(); public ObjectMap> reqParts = new ObjectMap<>(); + public ObjectMap ores = new ObjectMap<>(); + public ObjectMap oreFloors = new ObjectMap<>(); public Seq forResource(Content item){ return reqParts.get(item, Seq::new); @@ -32,6 +37,15 @@ public class BaseRegistry{ parts.clear(); reqParts.clear(); + //load ore types and corresponding items + for(Block block : content.blocks()){ + if(block instanceof OreBlock && block.asFloor().itemDrop != null){ + ores.put(block.asFloor().itemDrop, (OreBlock)block); + }else if(block.isFloor() && block.asFloor().itemDrop != null && !oreFloors.containsKey(block.asFloor().itemDrop)){ + oreFloors.put(block.asFloor().itemDrop, block.asFloor()); + } + } + String[] names = Core.files.internal("basepartnames").readString().split("\n"); for(String name : names){ diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index 3f2c4981e1..a75b0758ea 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -8,8 +8,10 @@ import arc.struct.EnumSet; import arc.struct.*; import arc.util.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; @@ -178,8 +180,8 @@ public class BlockIndexer{ public boolean eachBlock(Team team, float wx, float wy, float range, Boolf pred, Cons cons){ intSet.clear(); - int tx = world.toTile(wx); - int ty = world.toTile(wy); + int tx = World.toTile(wx); + int ty = World.toTile(wy); int tileRange = (int)(range / tilesize + 1); boolean any = false; @@ -192,7 +194,7 @@ public class BlockIndexer{ if(other == null) continue; - if(other.team == team && pred.get(other) && intSet.add(other.pos())){ + if((team == null || other.team == team) && pred.get(other) && intSet.add(other.pos())){ cons.get(other); any = true; } @@ -205,13 +207,14 @@ public class BlockIndexer{ /** Get all enemy blocks with a flag. */ public Seq getEnemy(Team team, BlockFlag type){ returnArray.clear(); - for(Team enemy : team.enemies()){ - if(state.teams.isActive(enemy)){ - TileArray set = getFlagged(enemy)[type.ordinal()]; - if(set != null){ - for(Tile tile : set){ - returnArray.add(tile); - } + Seq data = state.teams.present; + for(int i = 0; i < data.size; i++){ + Team enemy = data.items[i].team; + if(enemy == team) continue; + TileArray set = getFlagged(enemy)[type.ordinal()]; + if(set != null){ + for(Tile tile : set){ + returnArray.add(tile); } } } diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index c24cecd49c..78a596bb9d 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -7,6 +7,7 @@ import arc.struct.*; import arc.util.*; import arc.util.async.*; import mindustry.annotations.Annotations.*; +import mindustry.core.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.gen.*; @@ -85,9 +86,6 @@ public class Pathfinder implements Runnable{ tiles[tile.x][tile.y] = packTile(tile); } - //special preset which may help speed things up; this is optional - preloadPath(getField(state.rules.waveTeam, costGround, fieldCore)); - start(); }); @@ -105,7 +103,7 @@ public class Pathfinder implements Runnable{ boolean nearLiquid = false, nearSolid = false, nearGround = false; for(int i = 0; i < 4; i++){ - Tile other = tile.getNearby(i); + Tile other = tile.nearby(i); if(other != null){ if(other.floor().isLiquid) nearLiquid = true; if(other.solid()) nearSolid = true; @@ -114,7 +112,7 @@ public class Pathfinder implements Runnable{ } return PathTile.get( - tile.build == null ? 0 : Math.min((int)(tile.build.health / 40), 80), + tile.build == null || !tile.solid() ? 0 : Math.min((int)(tile.build.health / 40), 80), tile.getTeamID(), tile.solid(), tile.floor().isLiquid, @@ -444,7 +442,7 @@ public class Pathfinder implements Runnable{ @Override public void getPositions(IntSeq out){ - out.add(Point2.pack(world.toTile(position.getX()), world.toTile(position.getY()))); + out.add(Point2.pack(World.toTile(position.getX()), World.toTile(position.getY()))); } } @@ -453,7 +451,7 @@ public class Pathfinder implements Runnable{ * Data for a flow field to some set of destinations. * Concrete subclasses must specify a way to fetch costs and destinations. * */ - static abstract class Flowfield{ + public static abstract class Flowfield{ /** Refresh rate in milliseconds. Return any number <= 0 to disable. */ protected int refreshRate; /** Team this path is for. Set before using. */ @@ -462,7 +460,7 @@ public class Pathfinder implements Runnable{ protected PathCost cost = costTypes.get(costGround); /** costs of getting to a specific tile */ - int[][] weights; + public int[][] weights; /** search IDs of each position - the highest, most recent search is prioritized and overwritten */ int[][] searches; /** search frontier, these are Pos objects */ diff --git a/core/src/mindustry/ai/WaveSpawner.java b/core/src/mindustry/ai/WaveSpawner.java index 417909a92b..c420972457 100644 --- a/core/src/mindustry/ai/WaveSpawner.java +++ b/core/src/mindustry/ai/WaveSpawner.java @@ -8,6 +8,7 @@ import arc.struct.*; import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.entities.*; import mindustry.game.EventType.*; import mindustry.game.*; @@ -23,11 +24,21 @@ public class WaveSpawner{ private Seq spawns = new Seq<>(); private boolean spawning = false; private boolean any = false; + private Tile firstSpawn = null; public WaveSpawner(){ Events.on(WorldLoadEvent.class, e -> reset()); } + @Nullable + public Tile getFirstSpawn(){ + firstSpawn = null; + eachGroundSpawn((cx, cy) -> { + firstSpawn = world.tile(cx, cy); + }); + return firstSpawn; + } + public int countSpawns(){ return spawns.size; } @@ -38,7 +49,7 @@ public class WaveSpawner{ /** @return true if the player is near a ground spawn point. */ public boolean playerNear(){ - return !player.dead() && spawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius && player.team() != state.rules.waveTeam); + return state.hasSpawns() && !player.dead() && spawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius && player.team() != state.rules.waveTeam); } public void spawnEnemies(){ @@ -47,7 +58,7 @@ public class WaveSpawner{ for(SpawnGroup group : state.rules.spawns){ if(group.type == null) continue; - int spawned = group.getUnitsSpawned(state.wave - 1); + int spawned = group.getSpawned(state.wave - 1); if(group.type.flying){ float spread = margin / 1.5f; @@ -69,7 +80,7 @@ public class WaveSpawner{ Unit unit = group.createUnit(state.rules.waveTeam, state.wave - 1); unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y); - Time.run(Math.min(i * 5, 60 * 2), () -> spawnEffect(unit)); + spawnEffect(unit); } }); } @@ -77,17 +88,27 @@ public class WaveSpawner{ eachGroundSpawn((spawnX, spawnY, doShockwave) -> { if(doShockwave){ - Time.run(20f, () -> Fx.spawnShockwave.at(spawnX, spawnY, state.rules.dropZoneRadius)); - Time.run(40f, () -> Damage.damage(state.rules.waveTeam, spawnX, spawnY, state.rules.dropZoneRadius, 99999999f, true)); + doShockwave(spawnX, spawnY); } }); Time.runTask(121f, () -> spawning = false); } + public void doShockwave(float x, float y){ + Time.run(20f, () -> Fx.spawnShockwave.at(x, y, state.rules.dropZoneRadius)); + Time.run(40f, () -> Damage.damage(state.rules.waveTeam, x, y, state.rules.dropZoneRadius, 99999999f, true)); + } + + public void eachGroundSpawn(Intc2 cons){ + eachGroundSpawn((x, y, shock) -> cons.get(World.toTile(x), World.toTile(y))); + } + private void eachGroundSpawn(SpawnConsumer cons){ - for(Tile spawn : spawns){ - cons.accept(spawn.worldx(), spawn.worldy(), true); + if(state.hasSpawns()){ + for(Tile spawn : spawns){ + cons.accept(spawn.worldx(), spawn.worldy(), true); + } } if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam) && !state.teams.playerCores().isEmpty()){ @@ -100,7 +121,7 @@ public class WaveSpawner{ //keep moving forward until the max step amount is reached while(steps++ < maxSteps){ - int tx = world.toTile(core.x + Tmp.v1.x), ty = world.toTile(core.y + Tmp.v1.y); + int tx = World.toTile(core.x + Tmp.v1.x), ty = World.toTile(core.y + Tmp.v1.y); any = false; Geometry.circle(tx, ty, world.width(), world.height(), 3, (x, y) -> { if(world.solid(x, y)){ @@ -157,7 +178,7 @@ public class WaveSpawner{ } private void spawnEffect(Unit unit){ - Call.spawnEffect(unit.x, unit.y, unit.type()); + Call.spawnEffect(unit.x, unit.y, unit.type); Time.run(30f, unit::add); } diff --git a/core/src/mindustry/ai/formations/patterns/CircleFormation.java b/core/src/mindustry/ai/formations/patterns/CircleFormation.java index 0988657adf..9636d97036 100644 --- a/core/src/mindustry/ai/formations/patterns/CircleFormation.java +++ b/core/src/mindustry/ai/formations/patterns/CircleFormation.java @@ -15,7 +15,7 @@ public class CircleFormation extends FormationPattern{ float radius = spacing / (float)Math.sin(180f / slots * Mathf.degRad); outLocation.set(Angles.trnsx(angle, radius), Angles.trnsy(angle, radius), angle); }else{ - outLocation.set(0, 0, 360f * slotNumber); + outLocation.set(0, spacing * 1.1f, 360f * slotNumber); } outLocation.z += angleOffset; diff --git a/core/src/mindustry/ai/types/BuilderAI.java b/core/src/mindustry/ai/types/BuilderAI.java index 90f0548c02..c3558ca58a 100644 --- a/core/src/mindustry/ai/types/BuilderAI.java +++ b/core/src/mindustry/ai/types/BuilderAI.java @@ -17,13 +17,17 @@ public class BuilderAI extends AIController{ @Nullable Builderc following; @Override - public void updateUnit(){ + public void updateMovement(){ Builderc builder = (Builderc)unit; if(builder.moving()){ builder.lookAt(builder.vel().angle()); } + if(target != null && shouldShoot()){ + unit.lookAt(target); + } + builder.updateBuilding(true); if(following != null){ @@ -67,17 +71,15 @@ public class BuilderAI extends AIController{ Units.nearby(unit.team, unit.x, unit.y, buildRadius, u -> { if(found) return; - if(u instanceof Builderc && u != unit && ((Builderc)u).activelyBuilding()){ - Builderc b = (Builderc)u; + if(u instanceof Builderc b && u != unit && ((Builderc)u).activelyBuilding()){ BuildPlan plan = b.buildPlan(); Building build = world.build(plan.x, plan.y); - if(build instanceof ConstructBuild){ - ConstructBuild cons = (ConstructBuild)build; + if(build instanceof ConstructBuild cons){ float dist = Math.min(cons.dst(unit) - buildingRange, 0); //make sure you can reach the request in time - if(dist / unit.type().speed < cons.buildCost * 0.9f){ + if(dist / unit.type.speed < cons.buildCost * 0.9f){ following = b; found = true; } @@ -97,13 +99,29 @@ public class BuilderAI extends AIController{ }else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid. //add build request. builder.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config)); + //shift build plan to tail so next unit builds something else. + blocks.addLast(blocks.removeFirst()); }else{ //shift head of queue to tail, try something else next time blocks.removeFirst(); blocks.addLast(block); } } - } } + + @Override + public AIController fallback(){ + return unit.type.flying ? new FlyingAI() : new GroundAI(); + } + + @Override + public boolean useFallback(){ + return state.rules.waves && unit.team == state.rules.waveTeam && !unit.team.rules().ai; + } + + @Override + public boolean shouldShoot(){ + return !((Builderc)unit).isBuilding(); + } } diff --git a/core/src/mindustry/ai/types/FlyingAI.java b/core/src/mindustry/ai/types/FlyingAI.java index 0758f9016a..7262ae216a 100644 --- a/core/src/mindustry/ai/types/FlyingAI.java +++ b/core/src/mindustry/ai/types/FlyingAI.java @@ -12,11 +12,11 @@ public class FlyingAI extends AIController{ @Override public void updateMovement(){ if(target != null && unit.hasWeapons() && command() == UnitCommand.attack){ - if(unit.type().weapons.first().rotate){ + if(unit.type.weapons.first().rotate){ moveTo(target, unit.range() * 0.8f); unit.lookAt(target); }else{ - attack(100f); + attack(120f); } } @@ -34,17 +34,15 @@ public class FlyingAI extends AIController{ Teamc result = target(x, y, range, air, ground); if(result != null) return result; - if(ground) result = targetFlag(x, y, BlockFlag.producer, true); + if(ground) result = targetFlag(x, y, BlockFlag.generator, true); if(result != null) return result; - if(ground) result = targetFlag(x, y, BlockFlag.turret, true); + if(ground) result = targetFlag(x, y, BlockFlag.core, true); if(result != null) return result; return null; } - //TODO clean up - protected void attack(float circleLength){ vec.set(target).sub(unit); @@ -57,7 +55,7 @@ public class FlyingAI extends AIController{ vec.setAngle(Mathf.slerpDelta(unit.vel().angle(), vec.angle(), 0.6f)); } - vec.setLength(unit.type().speed); + vec.setLength(unit.type.speed); unit.moveAt(vec); } diff --git a/core/src/mindustry/ai/types/FormationAI.java b/core/src/mindustry/ai/types/FormationAI.java index e988294e1d..3c5a2b99b4 100644 --- a/core/src/mindustry/ai/types/FormationAI.java +++ b/core/src/mindustry/ai/types/FormationAI.java @@ -7,6 +7,7 @@ import mindustry.ai.formations.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.type.*; +import mindustry.world.blocks.storage.CoreBlock.*; public class FormationAI extends AIController implements FormationMember{ public Unit leader; @@ -26,15 +27,15 @@ public class FormationAI extends AIController implements FormationMember{ @Override public void updateUnit(){ - UnitType type = unit.type(); + UnitType type = unit.type; if(leader.dead){ unit.resetController(); return; } - if(unit.type().canBoost && unit.canPassOn()){ - unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f); + if(unit.type.canBoost){ + unit.elevation = Mathf.approachDelta(unit.elevation, !unit.canPassOn() ? 1f : leader.type.canBoost ? leader.elevation : 0f, 0.08f); } unit.controlWeapons(true, leader.isShooting); @@ -42,7 +43,7 @@ public class FormationAI extends AIController implements FormationMember{ unit.aim(leader.aimX(), leader.aimY()); - if(unit.type().rotateShooting){ + if(unit.type.rotateShooting){ unit.lookAt(leader.aimX(), leader.aimY()); }else if(unit.moving()){ unit.lookAt(unit.vel.angle()); @@ -52,10 +53,36 @@ public class FormationAI extends AIController implements FormationMember{ float margin = 3f; + float speed = unit.realSpeed(); + if(unit.dst(realtarget) <= margin){ - unit.vel.approachDelta(Vec2.ZERO, type.speed * type.accel / 2f); + unit.vel.approachDelta(Vec2.ZERO, speed * type.accel / 2f); }else{ - unit.moveAt(realtarget.sub(unit).limit(type.speed)); + unit.moveAt(realtarget.sub(unit).limit(speed)); + } + + if(unit instanceof Minerc mine && leader instanceof Minerc com){ + if(mine.validMine(com.mineTile())){ + mine.mineTile(com.mineTile()); + + CoreBuild core = unit.team.core(); + + if(core != null && com.mineTile().drop() != null && unit.within(core, unit.type.range) && !unit.acceptsItem(com.mineTile().drop())){ + if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){ + Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core); + + unit.clearItem(); + } + } + }else{ + mine.mineTile(null); + } + + } + + if(unit instanceof Builderc build && leader instanceof Builderc com && com.activelyBuilding()){ + build.clearBuilding(); + build.addBuild(com.buildPlan()); } } @@ -69,11 +96,7 @@ public class FormationAI extends AIController implements FormationMember{ @Override public float formationSize(){ - if(unit instanceof Commanderc && ((Commanderc)unit).isCommanding()){ - //TODO return formation size - //eturn ((Commanderc)unit).formation(). - } - return unit.hitSize * 1f; + return unit.hitSize * 1.1f; } @Override diff --git a/core/src/mindustry/ai/types/GroundAI.java b/core/src/mindustry/ai/types/GroundAI.java index bd6b13a25c..2a711235c9 100644 --- a/core/src/mindustry/ai/types/GroundAI.java +++ b/core/src/mindustry/ai/types/GroundAI.java @@ -13,8 +13,6 @@ import java.util.*; import static mindustry.Vars.*; public class GroundAI extends AIController{ - //static final float commandCooldown = 60f * 10; - //float commandTimer = 60*3; @Override public void updateMovement(){ @@ -34,54 +32,28 @@ public class GroundAI extends AIController{ if(spawner != null && unit.within(spawner, state.rules.dropZoneRadius + 120f)) move = false; } - if(move) moveTo(Pathfinder.fieldCore); + if(move) pathfind(Pathfinder.fieldCore); } if(command() == UnitCommand.rally){ Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false); if(target != null && !unit.within(target, 70f)){ - moveTo(Pathfinder.fieldRally); + pathfind(Pathfinder.fieldRally); } } - if(unit.type().canBoost && unit.tileOn() != null && !unit.tileOn().solid()){ + if(unit.type.canBoost && !unit.onSolid()){ unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f); } - if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type().rotateShooting){ - if(unit.type().hasWeapons()){ - unit.lookAt(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed)); + if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type.rotateShooting){ + if(unit.type.hasWeapons()){ + unit.lookAt(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); } }else if(unit.moving()){ unit.lookAt(unit.vel().angle()); } - //auto-command works but it's very buggy - /* - if(unit instanceof Commanderc){ - Commanderc c = (Commanderc)unit; - //try to command when missing members - if(c.controlling().size <= unit.type().commandLimit/2){ - commandTimer -= Time.delta; - - if(commandTimer <= 0){ - c.commandNearby(new SquareFormation(), u -> !(u.controller() instanceof FormationAI) && !(u instanceof Commanderc)); - commandTimer = commandCooldown; - } - } - }*/ - } - - protected void moveTo(int pathTarget){ - int costType = unit.pathType(); - - Tile tile = unit.tileOn(); - if(tile == null) return; - Tile targetTile = pathfinder.getTargetTile(tile, pathfinder.getField(unit.team, costType, pathTarget)); - - if(tile == targetTile || (costType == Pathfinder.costWater && !targetTile.floor().isLiquid)) return; - - unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type().speed)); } } diff --git a/core/src/mindustry/ai/types/LogicAI.java b/core/src/mindustry/ai/types/LogicAI.java new file mode 100644 index 0000000000..1166c2ff96 --- /dev/null +++ b/core/src/mindustry/ai/types/LogicAI.java @@ -0,0 +1,144 @@ +package mindustry.ai.types; + +import arc.math.*; +import arc.struct.*; +import arc.util.*; +import mindustry.ai.*; +import mindustry.entities.units.*; +import mindustry.gen.*; +import mindustry.logic.*; +import mindustry.world.*; +import mindustry.world.meta.*; + +import static mindustry.Vars.*; + +public class LogicAI extends AIController{ + /** Minimum delay between item transfers. */ + public static final float transferDelay = 60f * 3f; + /** Time after which the unit resets its controlled and reverts to a normal unit. */ + public static final float logicControlTimeout = 10f * 60f; + + public LUnitControl control = LUnitControl.stop; + public float moveX, moveY, moveRad; + public float itemTimer, payTimer, controlTimer = logicControlTimeout, targetTimer; + @Nullable + public Building controller; + public BuildPlan plan = new BuildPlan(); + + //special cache for instruction to store data + public ObjectMap execCache = new ObjectMap<>(); + + //type of aiming to use + public LUnitControl aimControl = LUnitControl.stop; + + //whether to use the boost (certain units only) + public boolean boost; + //main target set for shootP + public Teamc mainTarget; + //whether to shoot at all + public boolean shoot; + //target shoot positions for manual aiming + public PosTeam posTarget = PosTeam.create(); + + private ObjectSet radars = new ObjectSet<>(); + + @Override + protected void updateMovement(){ + if(itemTimer > 0) itemTimer -= Time.delta; + if(payTimer > 0) payTimer -= Time.delta; + + if(targetTimer > 0f){ + targetTimer -= Time.delta; + }else{ + radars.clear(); + targetTimer = 40f; + } + + //timeout when not controlled by logic for a while + if(controlTimer > 0 && controller != null && controller.isValid()){ + controlTimer -= Time.delta; + }else{ + unit.resetController(); + return; + } + + switch(control){ + case move -> { + moveTo(Tmp.v1.set(moveX, moveY), 1f, 30f); + } + case approach -> { + moveTo(Tmp.v1.set(moveX, moveY), moveRad - 8f, 8f); + } + case pathfind -> { + Building core = unit.closestEnemyCore(); + + if((core == null || !unit.within(core, unit.range() * 0.5f)) && command() == UnitCommand.attack){ + boolean move = true; + + if(state.rules.waves && unit.team == state.rules.defaultTeam){ + Tile spawner = getClosestSpawner(); + if(spawner != null && unit.within(spawner, state.rules.dropZoneRadius + 120f)) move = false; + } + + if(move) pathfind(Pathfinder.fieldCore); + } + + if(command() == UnitCommand.rally){ + Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false); + + if(target != null && !unit.within(target, 70f)){ + pathfind(Pathfinder.fieldRally); + } + } + } + case stop -> { + if(unit instanceof Builderc build){ + build.clearBuilding(); + } + } + } + + if(unit.type.canBoost && !unit.type.flying){ + unit.elevation = Mathf.approachDelta(unit.elevation, Mathf.num(boost || unit.onSolid()), 0.08f); + } + + //look where moving if there's nothing to aim at + if(!shoot){ + if(unit.moving()){ + unit.lookAt(unit.vel().angle()); + } + }else if(unit.hasWeapons()){ //if there is, look at the object + unit.lookAt(unit.mounts[0].aimX, unit.mounts[0].aimY); + } + } + + public boolean checkTargetTimer(Object radar){ + return radars.add(radar); + } + + //always retarget + @Override + protected boolean retarget(){ + return true; + } + + @Override + protected boolean invalid(Teamc target){ + return false; + } + + @Override + protected boolean shouldShoot(){ + return shoot && !(unit.type.canBoost && boost); + } + + //always aim for the main target + @Override + protected Teamc target(float x, float y, float range, boolean air, boolean ground){ + return switch(aimControl){ + case target -> posTarget; + case targetp -> mainTarget; + default -> null; + }; + } +} diff --git a/core/src/mindustry/ai/types/MinerAI.java b/core/src/mindustry/ai/types/MinerAI.java index c4e654ce29..aa7d1403c5 100644 --- a/core/src/mindustry/ai/types/MinerAI.java +++ b/core/src/mindustry/ai/types/MinerAI.java @@ -17,16 +17,16 @@ public class MinerAI extends AIController{ protected void updateMovement(){ Building core = unit.closestCore(); - if(!(unit instanceof Minerc) || core == null) return; + if(!(unit instanceof Minerc miner) || core == null) return; - Minerc miner = (Minerc)unit; - - if(miner.mineTile() != null && !miner.mineTile().within(unit, unit.type().range)){ + if(miner.mineTile() != null && !miner.mineTile().within(unit, unit.type.range)){ miner.mineTile(null); } if(mining){ - targetItem = unit.team.data().mineItems.min(i -> indexer.hasOre(i) && miner.canMine(i), i -> core.items.get(i)); + if(timer.get(timerTarget2, 60 * 4) || targetItem == null){ + targetItem = unit.team.data().mineItems.min(i -> indexer.hasOre(i) && miner.canMine(i), i -> core.items.get(i)); + } //core full of the target item, do nothing if(targetItem != null && core.acceptStack(targetItem, 1, unit) == 0){ @@ -36,7 +36,7 @@ public class MinerAI extends AIController{ } //if inventory is full, drop it off. - if(unit.stack.amount >= unit.type().itemCapacity || (targetItem != null && !unit.acceptsItem(targetItem))){ + if(unit.stack.amount >= unit.type.itemCapacity || (targetItem != null && !unit.acceptsItem(targetItem))){ mining = false; }else{ if(retarget() && targetItem != null){ @@ -44,9 +44,9 @@ public class MinerAI extends AIController{ } if(ore != null){ - moveTo(ore, unit.type().range / 2f); + moveTo(ore, unit.type.range / 2f); - if(unit.within(ore, unit.type().range)){ + if(unit.within(ore, unit.type.range)){ miner.mineTile(ore); } @@ -63,7 +63,7 @@ public class MinerAI extends AIController{ return; } - if(unit.within(core, unit.type().range)){ + if(unit.within(core, unit.type.range)){ if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){ Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core); } @@ -72,7 +72,7 @@ public class MinerAI extends AIController{ mining = true; } - circle(core, unit.type().range / 1.8f); + circle(core, unit.type.range / 1.8f); } } diff --git a/core/src/mindustry/ai/types/RepairAI.java b/core/src/mindustry/ai/types/RepairAI.java index 84baf1c555..36504f908d 100644 --- a/core/src/mindustry/ai/types/RepairAI.java +++ b/core/src/mindustry/ai/types/RepairAI.java @@ -2,33 +2,46 @@ package mindustry.ai.types; import mindustry.entities.*; import mindustry.entities.units.*; +import mindustry.gen.*; import mindustry.world.blocks.ConstructBlock.*; -//note that repair AI doesn't attack anything even if it theoretically can public class RepairAI extends AIController{ @Override protected void updateMovement(){ - boolean shoot = false; + if(target instanceof Building){ + boolean shoot = false; - if(target != null){ - if(!target.within(unit, unit.type().range * 0.8f)){ - moveTo(target, unit.type().range * 0.8f); - } - - if(target.within(unit, unit.type().range)){ + if(target.within(unit, unit.type.range)){ unit.aim(target); shoot = true; } + + unit.controlWeapons(shoot); + }else if(target == null){ + unit.controlWeapons(false); } - unit.controlWeapons(shoot); + if(target != null){ + if(!target.within(unit, unit.type.range * 0.65f) && target instanceof Building){ + moveTo(target, unit.type.range * 0.65f); + } + + unit.lookAt(target); + } } @Override protected void updateTargeting(){ - target = Units.findDamagedTile(unit.team, unit.x, unit.y); + Building target = Units.findDamagedTile(unit.team, unit.x, unit.y); if(target instanceof ConstructBuild) target = null; + + if(target == null){ + super.updateTargeting(); + }else{ + this.target = target; + } } + } diff --git a/core/src/mindustry/ai/types/SuicideAI.java b/core/src/mindustry/ai/types/SuicideAI.java index 93ab98a7c0..0ef3ece228 100644 --- a/core/src/mindustry/ai/types/SuicideAI.java +++ b/core/src/mindustry/ai/types/SuicideAI.java @@ -6,6 +6,8 @@ import mindustry.entities.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.world.*; +import mindustry.world.blocks.distribution.*; +import mindustry.world.blocks.liquid.*; import mindustry.world.meta.*; public class SuicideAI extends GroundAI{ @@ -14,50 +16,57 @@ public class SuicideAI extends GroundAI{ @Override public void updateUnit(){ - if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){ + if(Units.invalidateTarget(target, unit.team, unit.x, unit.y, Float.MAX_VALUE)){ target = null; } if(retarget()){ - target = target(unit.x, unit.y, unit.range(), unit.type().targetAir, unit.type().targetGround); + target = target(unit.x, unit.y, unit.range(), unit.type.targetAir, unit.type.targetGround); } Building core = unit.closestEnemyCore(); boolean rotate = false, shoot = false, moveToTarget = false; - if(!Units.invalidateTarget(target, unit, unit.range())){ + if(!Units.invalidateTarget(target, unit, unit.range()) && unit.hasWeapons()){ rotate = true; - shoot = unit.within(target, unit.type().weapons.first().bullet.range() + + shoot = unit.within(target, unit.type.weapons.first().bullet.range() + (target instanceof Building ? ((Building)target).block.size * Vars.tilesize / 2f : ((Hitboxc)target).hitSize() / 2f)); - if(unit.type().hasWeapons()){ - unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed)); + if(unit.type.hasWeapons()){ + unit.aimLook(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); } - blockedByBlock = false; + //do not move toward walls or transport blocks + if(!(target instanceof Building build && ( + build.block.group == BlockGroup.walls || + build.block.group == BlockGroup.liquids || + build.block.group == BlockGroup.transportation + ))){ + blockedByBlock = false; - //raycast for target - boolean blocked = Vars.world.raycast(unit.tileX(), unit.tileY(), target.tileX(), target.tileY(), (x, y) -> { - Tile tile = Vars.world.tile(x, y); - if(tile != null && tile.build == target) return false; - if(tile != null && tile.build != null && tile.build.team != unit.team()){ - blockedByBlock = true; - return true; - }else{ - return tile == null || tile.solid(); + //raycast for target + boolean blocked = Vars.world.raycast(unit.tileX(), unit.tileY(), target.tileX(), target.tileY(), (x, y) -> { + Tile tile = Vars.world.tile(x, y); + if(tile != null && tile.build == target) return false; + if(tile != null && tile.build != null && tile.build.team != unit.team()){ + blockedByBlock = true; + return true; + }else{ + return tile == null || tile.solid(); + } + }); + + //shoot when there's an enemy block in the way + if(blockedByBlock){ + shoot = true; } - }); - //shoot when there's an enemy block in the way - if(blockedByBlock){ - shoot = true; - } - - if(!blocked){ - moveToTarget = true; - //move towards target directly - unit.moveAt(vec.set(target).sub(unit).limit(unit.type().speed)); + if(!blocked){ + moveToTarget = true; + //move towards target directly + unit.moveAt(vec.set(target).sub(unit).limit(unit.type.speed)); + } } } @@ -67,10 +76,10 @@ public class SuicideAI extends GroundAI{ Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false); if(target != null && !unit.within(target, 70f)){ - moveTo(Pathfinder.fieldRally); + pathfind(Pathfinder.fieldRally); } }else if(command() == UnitCommand.attack && core != null){ - moveTo(Pathfinder.fieldCore); + pathfind(Pathfinder.fieldCore); } if(unit.moving()) unit.lookAt(unit.vel().angle()); @@ -78,4 +87,10 @@ public class SuicideAI extends GroundAI{ unit.controlWeapons(rotate, shoot); } + + @Override + protected Teamc target(float x, float y, float range, boolean air, boolean ground){ + return Units.closestTarget(unit.team, x, y, range, u -> u.checkTarget(air, ground), t -> ground && + !(t.block instanceof Conveyor || t.block instanceof Conduit)); //do not target conveyors/conduits + } } diff --git a/core/src/mindustry/async/AsyncCore.java b/core/src/mindustry/async/AsyncCore.java index 764cd3dc4b..a9d4cdd90d 100644 --- a/core/src/mindustry/async/AsyncCore.java +++ b/core/src/mindustry/async/AsyncCore.java @@ -2,7 +2,6 @@ package mindustry.async; import arc.*; import arc.struct.*; -import mindustry.*; import mindustry.game.EventType.*; import java.util.concurrent.*; @@ -12,8 +11,7 @@ import static mindustry.Vars.*; public class AsyncCore{ //all processes to be executed each frame private final Seq processes = Seq.with( - new PhysicsProcess(), - Vars.teamIndex = new TeamIndexProcess() + new PhysicsProcess() ); //futures to be awaited diff --git a/core/src/mindustry/async/PhysicsProcess.java b/core/src/mindustry/async/PhysicsProcess.java index 07d44d4717..a60dab7f68 100644 --- a/core/src/mindustry/async/PhysicsProcess.java +++ b/core/src/mindustry/async/PhysicsProcess.java @@ -57,7 +57,7 @@ public class PhysicsProcess implements AsyncProcess{ PhysicRef ref = entity.physref(); ref.body.layer = - entity.type().allowLegStep ? layerLegs : + entity.type.allowLegStep ? layerLegs : entity.isGrounded() ? layerGround : layerFlying; ref.x = entity.x(); ref.y = entity.y(); diff --git a/core/src/mindustry/async/TeamIndexProcess.java b/core/src/mindustry/async/TeamIndexProcess.java deleted file mode 100644 index 86b5e16902..0000000000 --- a/core/src/mindustry/async/TeamIndexProcess.java +++ /dev/null @@ -1,82 +0,0 @@ -package mindustry.async; - -import arc.math.geom.*; -import mindustry.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.type.*; -import mindustry.world.blocks.payloads.*; - -import java.util.*; - -/** Creates quadtrees per unit team. */ -public class TeamIndexProcess implements AsyncProcess{ - private QuadTree[] trees = new QuadTree[Team.all.length]; - private int[] counts = new int[Team.all.length]; - private int[][] typeCounts = new int[Team.all.length][0]; - - public QuadTree tree(Team team){ - if(trees[team.id] == null) trees[team.id] = new QuadTree<>(Vars.world.getQuadBounds(new Rect())); - - return trees[team.id]; - } - - public int count(Team team){ - return counts[team.id]; - } - - public int countType(Team team, UnitType type){ - return typeCounts[team.id].length <= type.id ? 0 : typeCounts[team.id][type.id]; - } - - public void updateCount(Team team, UnitType type, int amount){ - counts[team.id] = Math.max(amount + counts[team.id], 0); - if(typeCounts[team.id].length <= type.id){ - typeCounts[team.id] = new int[Vars.content.units().size]; - } - typeCounts[team.id][type.id] = Math.max(amount + typeCounts[team.id][type.id], 0); - } - - private void count(Unit unit){ - updateCount(unit.team, unit.type(), 1); - - if(unit instanceof Payloadc){ - ((Payloadc)unit).payloads().each(p -> { - if(p instanceof UnitPayload){ - count(((UnitPayload)p).unit); - } - }); - } - } - - @Override - public void reset(){ - counts = new int[Team.all.length]; - trees = new QuadTree[Team.all.length]; - } - - @Override - public void begin(){ - - for(Team team : Team.all){ - if(trees[team.id] != null){ - trees[team.id].clear(); - } - - Arrays.fill(typeCounts[team.id], 0); - } - - Arrays.fill(counts, 0); - - for(Unit unit : Groups.unit){ - tree(unit.team).insert(unit); - - count(unit); - } - } - - @Override - public boolean shouldProcess(){ - return false; - } -} diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 2eee8353e2..291e8ff745 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -3,6 +3,7 @@ package mindustry.content; import arc.*; import arc.graphics.*; import arc.graphics.g2d.*; +import arc.struct.*; import mindustry.ctype.*; import mindustry.entities.bullet.*; import mindustry.gen.*; @@ -13,6 +14,8 @@ import mindustry.world.blocks.*; import mindustry.world.blocks.campaign.*; import mindustry.world.blocks.defense.*; import mindustry.world.blocks.defense.turrets.*; +import mindustry.world.blocks.defense.turrets.PointDefenseTurret; +import mindustry.world.blocks.defense.turrets.TractorBeamTurret; import mindustry.world.blocks.distribution.*; import mindustry.world.blocks.environment.*; import mindustry.world.blocks.experimental.*; @@ -34,10 +37,10 @@ public class Blocks implements ContentList{ public static Block //environment - air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, + air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, dacite, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster, - iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, grass, salt, - metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, boulder, snowBoulder, saltWall, + iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, grass, salt, + metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, pebbles, tendrils, @@ -99,6 +102,7 @@ public class Blocks implements ContentList{ { alwaysReplace = true; hasShadow = false; + useColor = false; } @Override public void drawBase(Tile tile){} @@ -118,6 +122,7 @@ public class Blocks implements ContentList{ spawn = new OverlayFloor("spawn"){ { variants = 0; + needsSurface = false; } @Override public void drawBase(Tile tile){} @@ -215,6 +220,13 @@ public class Blocks implements ContentList{ lightColor = Color.orange.cpy().a(0.38f); }}; + space = new Floor("space"){{ + cacheLayer = CacheLayer.space; + placeableOn = false; + solid = true; + variants = 0; + }}; + stone = new Floor("stone"); craters = new Floor("craters"){{ @@ -287,7 +299,7 @@ public class Blocks implements ContentList{ salt = new Floor("salt"){{ variants = 0; - attributes.set(Attribute.water, -0.25f); + attributes.set(Attribute.water, -0.3f); attributes.set(Attribute.oil, 0.3f); }}; @@ -307,6 +319,11 @@ public class Blocks implements ContentList{ attributes.set(Attribute.water, 0.3f); }}; + shale = new Floor("shale"){{ + variants = 3; + attributes.set(Attribute.oil, 1f); + }}; + stoneWall = new StaticWall("stone-wall"){{ variants = 2; }}; @@ -315,15 +332,6 @@ public class Blocks implements ContentList{ variants = 2; }}; - boulder = new Boulder("boulder"){{ - variants = 2; - }}; - - snowBoulder = new Boulder("snow-boulder"){{ - variants = 2; - snow.asFloor().decoration = ice.asFloor().decoration = iceSnow.asFloor().decoration = this; - }}; - dirtWall = new StaticWall("dirt-wall"){{ variants = 2; }}; @@ -353,6 +361,12 @@ public class Blocks implements ContentList{ saltWall = new StaticWall("salt-wall"); + shrubs = new StaticWall("shrubs"); + + shaleWall = new StaticWall("shale-wall"){{ + variants = 2; + }}; + sporePine = new StaticTree("spore-pine"){{ variants = 0; }}; @@ -365,8 +379,6 @@ public class Blocks implements ContentList{ variants = 0; }}; - shrubs = new StaticWall("shrubs"); - whiteTreeDead = new TreeBlock("white-tree-dead"); whiteTree = new TreeBlock("white-tree"); @@ -375,13 +387,13 @@ public class Blocks implements ContentList{ variants = 3; }}; - shale = new Floor("shale"){{ - variants = 3; - attributes.set(Attribute.oil, 1f); + boulder = new Boulder("boulder"){{ + variants = 2; }}; - shaleWall = new StaticWall("shale-wall"){{ + snowBoulder = new Boulder("snow-boulder"){{ variants = 2; + snow.asFloor().decoration = ice.asFloor().decoration = iceSnow.asFloor().decoration = salt.asFloor().decoration = this; }}; shaleBoulder = new Boulder("shale-boulder"){{ @@ -571,7 +583,7 @@ public class Blocks implements ContentList{ phaseWeaver = new GenericCrafter("phase-weaver"){{ requirements(Category.crafting, with(Items.silicon, 130, Items.lead, 120, Items.thorium, 75)); craftEffect = Fx.smeltsmoke; - outputItem = new ItemStack(Items.phasefabric, 1); + outputItem = new ItemStack(Items.phaseFabric, 1); craftTime = 120f; size = 2; hasPower = true; @@ -585,7 +597,7 @@ public class Blocks implements ContentList{ surgeSmelter = new GenericSmelter("alloy-smelter"){{ requirements(Category.crafting, with(Items.silicon, 80, Items.lead, 80, Items.thorium, 70)); craftEffect = Fx.smeltsmoke; - outputItem = new ItemStack(Items.surgealloy, 1); + outputItem = new ItemStack(Items.surgeAlloy, 1); craftTime = 75f; size = 3; hasPower = true; @@ -664,7 +676,7 @@ public class Blocks implements ContentList{ }}; disassembler = new Separator("disassembler"){{ - requirements(Category.crafting, with(Items.graphite, 140, Items.titanium, 100, Items.silicon, 150, Items.surgealloy, 70)); + requirements(Category.crafting, with(Items.graphite, 140, Items.titanium, 100, Items.silicon, 150, Items.surgeAlloy, 70)); results = with( Items.sand, 4, Items.graphite, 2, @@ -694,7 +706,7 @@ public class Blocks implements ContentList{ drawer = new DrawAnimation(); consumes.item(Items.sporePod, 1); - consumes.power(0.60f); + consumes.power(0.7f); }}; pulverizer = new GenericCrafter("pulverizer"){{ @@ -718,8 +730,8 @@ public class Blocks implements ContentList{ size = 2; hasPower = hasItems = hasLiquids = true; - consumes.liquid(Liquids.oil, 0.09f); - consumes.power(0.5f); + consumes.liquid(Liquids.oil, 0.1f); + consumes.power(0.7f); }}; incinerator = new Incinerator("incinerator"){{ @@ -782,20 +794,22 @@ public class Blocks implements ContentList{ }}; phaseWall = new Wall("phase-wall"){{ - requirements(Category.defense, with(Items.phasefabric, 6)); + requirements(Category.defense, with(Items.phaseFabric, 6)); health = 150 * wallHealthMultiplier; - flashHit = deflect = true; + chanceDeflect = 10f; + flashHit = true; }}; phaseWallLarge = new Wall("phase-wall-large"){{ requirements(Category.defense, ItemStack.mult(phaseWall.requirements, 4)); health = 150 * 4 * wallHealthMultiplier; size = 2; - flashHit = deflect = true; + chanceDeflect = 10f; + flashHit = true; }}; surgeWall = new Wall("surge-wall"){{ - requirements(Category.defense, with(Items.surgealloy, 6)); + requirements(Category.defense, with(Items.surgeAlloy, 6)); health = 230 * wallHealthMultiplier; lightningChance = 0.05f; }}; @@ -821,27 +835,27 @@ public class Blocks implements ContentList{ }}; scrapWall = new Wall("scrap-wall"){{ - requirements(Category.defense, BuildVisibility.sandboxOnly, with()); + requirements(Category.defense, BuildVisibility.sandboxOnly, with(Items.scrap, 6)); health = 60 * wallHealthMultiplier; variants = 5; }}; scrapWallLarge = new Wall("scrap-wall-large"){{ - requirements(Category.defense, BuildVisibility.sandboxOnly, with()); + requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.mult(scrapWall.requirements, 4)); health = 60 * 4 * wallHealthMultiplier; size = 2; variants = 4; }}; scrapWallHuge = new Wall("scrap-wall-huge"){{ - requirements(Category.defense, BuildVisibility.sandboxOnly, with()); + requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.mult(scrapWall.requirements, 9)); health = 60 * 9 * wallHealthMultiplier; size = 3; variants = 3; }}; scrapWallGigantic = new Wall("scrap-wall-gigantic"){{ - requirements(Category.defense, BuildVisibility.sandboxOnly, with()); + requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.mult(scrapWall.requirements, 16)); health = 60 * 16 * wallHealthMultiplier; size = 4; }}; @@ -873,25 +887,25 @@ public class Blocks implements ContentList{ healPercent = 11f; phaseBoost = 15f; health = 80 * size * size; - consumes.item(Items.phasefabric).boost(); + consumes.item(Items.phaseFabric).boost(); }}; overdriveProjector = new OverdriveProjector("overdrive-projector"){{ requirements(Category.effect, with(Items.lead, 100, Items.titanium, 75, Items.silicon, 75, Items.plastanium, 30)); consumes.power(3.50f); size = 2; - consumes.item(Items.phasefabric).boost(); + consumes.item(Items.phaseFabric).boost(); }}; overdriveDome = new OverdriveProjector("overdrive-dome"){{ - requirements(Category.effect, with(Items.lead, 200, Items.titanium, 130, Items.silicon, 130, Items.plastanium, 80, Items.surgealloy, 120)); + requirements(Category.effect, with(Items.lead, 200, Items.titanium, 130, Items.silicon, 130, Items.plastanium, 80, Items.surgeAlloy, 120)); consumes.power(10f); size = 3; range = 200f; speedBoost = 2.5f; useTime = 300f; hasBoost = false; - consumes.items(with(Items.phasefabric, 1, Items.silicon, 1)); + consumes.items(with(Items.phaseFabric, 1, Items.silicon, 1)); }}; forceProjector = new ForceProjector("force-projector"){{ @@ -904,15 +918,15 @@ public class Blocks implements ContentList{ cooldownLiquid = 1.2f; cooldownBrokenBase = 0.35f; - consumes.item(Items.phasefabric).boost(); + consumes.item(Items.phaseFabric).boost(); consumes.power(4f); }}; shockMine = new ShockMine("shock-mine"){{ requirements(Category.effect, with(Items.lead, 25, Items.silicon, 12)); hasShadow = false; - health = 40; - damage = 23; + health = 50; + damage = 25; tileDamage = 7f; length = 10; tendrils = 4; @@ -947,7 +961,7 @@ public class Blocks implements ContentList{ requirements(Category.distribution, with(Items.plastanium, 1, Items.thorium, 1, Items.metaglass, 1)); health = 180; speed = 0.08f; - displayedSpeed = 10f; + displayedSpeed = 11f; }}; junction = new Junction("junction"){{ @@ -966,7 +980,7 @@ public class Blocks implements ContentList{ }}; phaseConveyor = new ItemBridge("phase-conveyor"){{ - requirements(Category.distribution, with(Items.phasefabric, 5, Items.silicon, 7, Items.lead, 10, Items.graphite, 10)); + requirements(Category.distribution, with(Items.phaseFabric, 5, Items.silicon, 7, Items.lead, 10, Items.graphite, 10)); range = 12; canOverdrive = false; hasPower = true; @@ -986,7 +1000,7 @@ public class Blocks implements ContentList{ router = new Router("router"){{ requirements(Category.distribution, with(Items.copper, 3)); - buildCostMultiplier = 2f; + buildCostMultiplier = 4f; }}; distributor = new Router("distributor"){{ @@ -1092,7 +1106,7 @@ public class Blocks implements ContentList{ }}; phaseConduit = new LiquidBridge("phase-conduit"){{ - requirements(Category.liquid, with(Items.phasefabric, 5, Items.silicon, 7, Items.metaglass, 20, Items.titanium, 10)); + requirements(Category.liquid, with(Items.phaseFabric, 5, Items.silicon, 7, Items.metaglass, 20, Items.titanium, 10)); range = 12; hasPower = true; canOverdrive = false; @@ -1116,10 +1130,10 @@ public class Blocks implements ContentList{ }}; surgeTower = new PowerNode("surge-tower"){{ - requirements(Category.power, with(Items.titanium, 7, Items.lead, 10, Items.silicon, 15, Items.surgealloy, 15)); + requirements(Category.power, with(Items.titanium, 7, Items.lead, 10, Items.silicon, 15, Items.surgeAlloy, 15)); size = 2; maxNodes = 2; - laserRange = 30f; + laserRange = 40f; }}; diode = new PowerDiode("diode"){{ @@ -1173,10 +1187,10 @@ public class Blocks implements ContentList{ }}; rtgGenerator = new DecayGenerator("rtg-generator"){{ - requirements(Category.power, with(Items.lead, 100, Items.silicon, 75, Items.phasefabric, 25, Items.plastanium, 75, Items.thorium, 50)); + requirements(Category.power, with(Items.lead, 100, Items.silicon, 75, Items.phaseFabric, 25, Items.plastanium, 75, Items.thorium, 50)); size = 2; powerProduction = 4.5f; - itemDuration = 60 * 15f; + itemDuration = 60 * 18f; }}; solarPanel = new SolarGenerator("solar-panel"){{ @@ -1185,7 +1199,7 @@ public class Blocks implements ContentList{ }}; largeSolarPanel = new SolarGenerator("solar-panel-large"){{ - requirements(Category.power, with(Items.lead, 100, Items.silicon, 145, Items.phasefabric, 15)); + requirements(Category.power, with(Items.lead, 100, Items.silicon, 145, Items.phaseFabric, 15)); size = 3; powerProduction = 0.95f; }}; @@ -1202,7 +1216,7 @@ public class Blocks implements ContentList{ }}; impactReactor = new ImpactReactor("impact-reactor"){{ - requirements(Category.power, with(Items.lead, 500, Items.silicon, 300, Items.graphite, 400, Items.thorium, 100, Items.surgealloy, 250, Items.metaglass, 250)); + requirements(Category.power, with(Items.lead, 500, Items.silicon, 300, Items.graphite, 400, Items.thorium, 100, Items.surgeAlloy, 250, Items.metaglass, 250)); size = 4; health = 900; powerProduction = 130f; @@ -1279,7 +1293,7 @@ public class Blocks implements ContentList{ }}; cultivator = new Cultivator("cultivator"){{ - requirements(Category.production, with(Items.copper, 10, Items.lead, 25, Items.silicon, 10)); + requirements(Category.production, with(Items.copper, 25, Items.lead, 25, Items.silicon, 10)); outputItem = new ItemStack(Items.sporePod, 1); craftTime = 140; size = 2; @@ -1287,7 +1301,7 @@ public class Blocks implements ContentList{ hasPower = true; hasItems = true; - consumes.power(0.80f); + consumes.power(0.9f); consumes.liquid(Liquids.water, 0.2f); }}; @@ -1333,6 +1347,7 @@ public class Blocks implements ContentList{ size = 4; unitCapModifier = 14; + researchCostMultiplier = 0.04f; }}; coreNucleus = new CoreBlock("core-nucleus"){{ @@ -1344,20 +1359,21 @@ public class Blocks implements ContentList{ size = 5; unitCapModifier = 20; + researchCostMultiplier = 0.05f; }}; vault = new StorageBlock("vault"){{ requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125)); size = 3; itemCapacity = 1000; - group = BlockGroup.storage; + flags = EnumSet.of(BlockFlag.storage); }}; container = new StorageBlock("container"){{ requirements(Category.effect, with(Items.titanium, 100)); size = 2; itemCapacity = 300; - group = BlockGroup.storage; + flags = EnumSet.of(BlockFlag.storage); }}; unloader = new Unloader("unloader"){{ @@ -1526,9 +1542,9 @@ public class Blocks implements ContentList{ hasPower = true; size = 2; - force = 4.5f; + force = 5f; scaledForce = 5.5f; - range = 110f; + range = 160f; damage = 0.4f; health = 160 * size * size; rotateSpeed = 10; @@ -1541,7 +1557,7 @@ public class Blocks implements ContentList{ ammo( Items.blastCompound, Bullets.missileExplosive, Items.pyratite, Bullets.missileIncendiary, - Items.surgealloy, Bullets.missileSurge + Items.surgeAlloy, Bullets.missileSurge ); reloadTime = 30f; shots = 4; @@ -1580,7 +1596,7 @@ public class Blocks implements ContentList{ }}; segment = new PointDefenseTurret("segment"){{ - requirements(Category.turret, with(Items.silicon, 130, Items.thorium, 80, Items.phasefabric, 40)); + requirements(Category.turret, with(Items.silicon, 130, Items.thorium, 80, Items.phaseFabric, 40)); health = 250 * size * size; range = 160f; @@ -1634,11 +1650,20 @@ public class Blocks implements ContentList{ float brange = range + 10f; - ammo(Items.thorium, new ShrapnelBulletType(){{ + ammo( + Items.thorium, new ShrapnelBulletType(){{ length = brange; damage = 105f; - ammoMultiplier = 6f; - }}); + ammoMultiplier = 5f; + }}, + Items.titanium, new ShrapnelBulletType(){{ + length = brange; + damage = 66f; + ammoMultiplier = 4f; + width = 17f; + reloadMultiplier = 1.3f; + }} + ); }}; ripple = new ItemTurret("ripple"){{ @@ -1677,7 +1702,7 @@ public class Blocks implements ContentList{ Items.metaglass, Bullets.fragGlass, Items.blastCompound, Bullets.fragExplosive, Items.plastanium, Bullets.fragPlastic, - Items.surgealloy, Bullets.fragSurge + Items.surgeAlloy, Bullets.fragSurge ); xRand = 4f; reloadTime = 8f; @@ -1695,9 +1720,9 @@ public class Blocks implements ContentList{ foreshadow = new ItemTurret("foreshadow"){{ float brange = range = 500f; - requirements(Category.turret, with(Items.copper, 1000, Items.metaglass, 600, Items.surgealloy, 300, Items.plastanium, 200, Items.silicon, 600)); + requirements(Category.turret, with(Items.copper, 1000, Items.metaglass, 600, Items.surgeAlloy, 300, Items.plastanium, 200, Items.silicon, 600)); ammo( - Items.surgealloy, new PointBulletType(){{ + Items.surgeAlloy, new PointBulletType(){{ shootEffect = Fx.instShoot; hitEffect = Fx.instHit; smokeEffect = Fx.smokeCloud; @@ -1705,7 +1730,7 @@ public class Blocks implements ContentList{ despawnEffect = Fx.instBomb; trailSpacing = 20f; damage = 1350; - tileDamageMultiplier = 0.5f; + tileDamageMultiplier = 0.3f; speed = brange; hitShake = 6f; ammoMultiplier = 1f; @@ -1731,11 +1756,11 @@ public class Blocks implements ContentList{ health = 150 * size * size; consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 2f)).update(false).optional(true, true); - consumes.powerCond(10f, (TurretBuild entity) -> entity.target != null || (entity.logicControlled() && entity.logicShooting)); + consumes.powerCond(10f, TurretBuild::isActive); }}; spectre = new ItemTurret("spectre"){{ - requirements(Category.turret, with(Items.copper, 900, Items.graphite, 300, Items.surgealloy, 250, Items.plastanium, 175, Items.thorium, 250)); + requirements(Category.turret, with(Items.copper, 900, Items.graphite, 300, Items.surgeAlloy, 250, Items.plastanium, 175, Items.thorium, 250)); ammo( Items.graphite, Bullets.standardDenseBig, Items.pyratite, Bullets.standardIncendiaryBig, @@ -1761,7 +1786,7 @@ public class Blocks implements ContentList{ }}; meltdown = new LaserTurret("meltdown"){{ - requirements(Category.turret, with(Items.copper, 1200, Items.lead, 350, Items.graphite, 300, Items.surgealloy, 325, Items.silicon, 325)); + requirements(Category.turret, with(Items.copper, 1200, Items.lead, 350, Items.graphite, 300, Items.surgeAlloy, 325, Items.silicon, 325)); shootEffect = Fx.shootBigSmoke2; shootCone = 40f; recoilAmount = 4f; @@ -1801,30 +1826,30 @@ public class Blocks implements ContentList{ groundFactory = new UnitFactory("ground-factory"){{ requirements(Category.units, with(Items.copper, 50, Items.lead, 120, Items.silicon, 80)); - plans = new UnitPlan[]{ + plans = Seq.with( new UnitPlan(UnitTypes.dagger, 60f * 15, with(Items.silicon, 10, Items.lead, 10)), new UnitPlan(UnitTypes.crawler, 60f * 12, with(Items.silicon, 10, Items.coal, 20)), - new UnitPlan(UnitTypes.nova, 60f * 40, with(Items.silicon, 30, Items.lead, 20, Items.titanium, 20)), - }; + new UnitPlan(UnitTypes.nova, 60f * 40, with(Items.silicon, 30, Items.lead, 20, Items.titanium, 20)) + ); size = 3; consumes.power(1.2f); }}; airFactory = new UnitFactory("air-factory"){{ requirements(Category.units, with(Items.copper, 60, Items.lead, 70)); - plans = new UnitPlan[]{ + plans = Seq.with( new UnitPlan(UnitTypes.flare, 60f * 15, with(Items.silicon, 15)), - new UnitPlan(UnitTypes.mono, 60f * 35, with(Items.silicon, 30, Items.lead, 15)), - }; + new UnitPlan(UnitTypes.mono, 60f * 35, with(Items.silicon, 30, Items.lead, 15)) + ); size = 3; consumes.power(1.2f); }}; navalFactory = new UnitFactory("naval-factory"){{ requirements(Category.units, with(Items.copper, 150, Items.lead, 130, Items.metaglass, 120)); - plans = new UnitPlan[]{ - new UnitPlan(UnitTypes.risso, 60f * 45f, with(Items.silicon, 20, Items.metaglass, 35)), - }; + plans = Seq.with( + new UnitPlan(UnitTypes.risso, 60f * 45f, with(Items.silicon, 20, Items.metaglass, 35)) + ); size = 3; consumes.power(1.2f); floating = true; @@ -1839,14 +1864,14 @@ public class Blocks implements ContentList{ constructTime = 60f * 10f; - upgrades = new UnitType[][]{ - {UnitTypes.nova, UnitTypes.pulsar}, - {UnitTypes.dagger, UnitTypes.mace}, - {UnitTypes.crawler, UnitTypes.atrax}, - {UnitTypes.flare, UnitTypes.horizon}, - {UnitTypes.mono, UnitTypes.poly}, - {UnitTypes.risso, UnitTypes.minke}, - }; + upgrades.addAll( + new UnitType[]{UnitTypes.nova, UnitTypes.pulsar}, + new UnitType[]{UnitTypes.dagger, UnitTypes.mace}, + new UnitType[]{UnitTypes.crawler, UnitTypes.atrax}, + new UnitType[]{UnitTypes.flare, UnitTypes.horizon}, + new UnitType[]{UnitTypes.mono, UnitTypes.poly}, + new UnitType[]{UnitTypes.risso, UnitTypes.minke} + ); }}; multiplicativeReconstructor = new Reconstructor("multiplicative-reconstructor"){{ @@ -1858,18 +1883,18 @@ public class Blocks implements ContentList{ constructTime = 60f * 30f; - upgrades = new UnitType[][]{ - {UnitTypes.horizon, UnitTypes.zenith}, - {UnitTypes.mace, UnitTypes.fortress}, - {UnitTypes.poly, UnitTypes.mega}, - {UnitTypes.minke, UnitTypes.bryde}, - {UnitTypes.pulsar, UnitTypes.quasar}, - {UnitTypes.atrax, UnitTypes.spiroct}, - }; + upgrades.addAll( + new UnitType[]{UnitTypes.horizon, UnitTypes.zenith}, + new UnitType[]{UnitTypes.mace, UnitTypes.fortress}, + new UnitType[]{UnitTypes.poly, UnitTypes.mega}, + new UnitType[]{UnitTypes.minke, UnitTypes.bryde}, + new UnitType[]{UnitTypes.pulsar, UnitTypes.quasar}, + new UnitType[]{UnitTypes.atrax, UnitTypes.spiroct} + ); }}; exponentialReconstructor = new Reconstructor("exponential-reconstructor"){{ - requirements(Category.units, with(Items.lead, 2000, Items.silicon, 1000, Items.titanium, 2000, Items.thorium, 750, Items.plastanium, 450, Items.phasefabric, 600)); + requirements(Category.units, with(Items.lead, 2000, Items.silicon, 1000, Items.titanium, 2000, Items.thorium, 750, Items.plastanium, 450, Items.phaseFabric, 600)); size = 7; consumes.power(13f); @@ -1879,35 +1904,35 @@ public class Blocks implements ContentList{ constructTime = 60f * 60f * 1.5f; liquidCapacity = 60f; - upgrades = new UnitType[][]{ - {UnitTypes.zenith, UnitTypes.antumbra}, - {UnitTypes.spiroct, UnitTypes.arkyid}, - {UnitTypes.fortress, UnitTypes.scepter}, - {UnitTypes.bryde, UnitTypes.sei}, - {UnitTypes.mega, UnitTypes.quad}, - {UnitTypes.quasar, UnitTypes.vela}, - }; + upgrades.addAll( + new UnitType[]{UnitTypes.zenith, UnitTypes.antumbra}, + new UnitType[]{UnitTypes.spiroct, UnitTypes.arkyid}, + new UnitType[]{UnitTypes.fortress, UnitTypes.scepter}, + new UnitType[]{UnitTypes.bryde, UnitTypes.sei}, + new UnitType[]{UnitTypes.mega, UnitTypes.quad}, + new UnitType[]{UnitTypes.quasar, UnitTypes.vela} + ); }}; tetrativeReconstructor = new Reconstructor("tetrative-reconstructor"){{ - requirements(Category.units, with(Items.lead, 4000, Items.silicon, 3000, Items.thorium, 1000, Items.plastanium, 600, Items.phasefabric, 600, Items.surgealloy, 800)); + requirements(Category.units, with(Items.lead, 4000, Items.silicon, 3000, Items.thorium, 1000, Items.plastanium, 600, Items.phaseFabric, 600, Items.surgeAlloy, 800)); size = 9; consumes.power(25f); - consumes.items(with(Items.silicon, 1000, Items.plastanium, 600, Items.surgealloy, 500, Items.phasefabric, 350)); + consumes.items(with(Items.silicon, 1000, Items.plastanium, 600, Items.surgeAlloy, 500, Items.phaseFabric, 350)); consumes.liquid(Liquids.cryofluid, 3f); constructTime = 60f * 60f * 4; liquidCapacity = 180f; - upgrades = new UnitType[][]{ - {UnitTypes.antumbra, UnitTypes.eclipse}, - {UnitTypes.arkyid, UnitTypes.toxopid}, - {UnitTypes.scepter, UnitTypes.reign}, - {UnitTypes.sei, UnitTypes.omura}, - {UnitTypes.quad, UnitTypes.oct}, - {UnitTypes.vela, UnitTypes.corvus} - }; + upgrades.addAll( + new UnitType[]{UnitTypes.antumbra, UnitTypes.eclipse}, + new UnitType[]{UnitTypes.arkyid, UnitTypes.toxopid}, + new UnitType[]{UnitTypes.scepter, UnitTypes.reign}, + new UnitType[]{UnitTypes.sei, UnitTypes.omura}, + new UnitType[]{UnitTypes.quad, UnitTypes.oct}, + new UnitType[]{UnitTypes.vela, UnitTypes.corvus} + ); }}; repairPoint = new RepairPoint("repair-point"){{ @@ -2027,7 +2052,7 @@ public class Blocks implements ContentList{ }}; hyperProcessor = new LogicBlock("hyper-processor"){{ - requirements(Category.logic, with(Items.lead, 450, Items.silicon, 150, Items.thorium, 75, Items.surgealloy, 50)); + requirements(Category.logic, with(Items.lead, 450, Items.silicon, 150, Items.thorium, 75, Items.surgeAlloy, 50)); consumes.liquid(Liquids.cryofluid, 0.08f); hasLiquids = true; @@ -2046,7 +2071,7 @@ public class Blocks implements ContentList{ }}; memoryBank = new MemoryBlock("memory-bank"){{ - requirements(Category.logic, with(Items.graphite, 80, Items.silicon, 80, Items.phasefabric, 30)); + requirements(Category.logic, with(Items.graphite, 80, Items.silicon, 80, Items.phaseFabric, 30)); memoryCapacity = 512; size = 2; @@ -2061,7 +2086,7 @@ public class Blocks implements ContentList{ }}; largeLogicDisplay = new LogicDisplay("large-logic-display"){{ - requirements(Category.logic, with(Items.lead, 200, Items.silicon, 150, Items.metaglass, 100, Items.phasefabric, 75)); + requirements(Category.logic, with(Items.lead, 200, Items.silicon, 150, Items.metaglass, 100, Items.phaseFabric, 75)); displaySize = 176; diff --git a/core/src/mindustry/content/Bullets.java b/core/src/mindustry/content/Bullets.java index 9b7e5f8805..e2d42c0ef0 100644 --- a/core/src/mindustry/content/Bullets.java +++ b/core/src/mindustry/content/Bullets.java @@ -354,6 +354,8 @@ public class Bullets implements ContentList{ width = 16f; height = 23f; shootEffect = Fx.shootBig; + pierceCap = 2; + pierceBuilding = true; }}; standardIncendiaryBig = new BasicBulletType(7f, 60, "bullet"){{ @@ -363,6 +365,8 @@ public class Bullets implements ContentList{ backColor = Pal.lightOrange; status = StatusEffects.burning; shootEffect = Fx.shootBig; + pierceCap = 2; + pierceBuilding = true; }}; damageLightning = new BulletType(0.0001f, 0f){{ @@ -379,12 +383,18 @@ public class Bullets implements ContentList{ JsonIO.copy(damageLightning, damageLightningGround); damageLightningGround.collidesAir = false; - healBullet = new HealBulletType(5.2f, 13){{ + healBullet = new LaserBoltBulletType(5.2f, 13){{ healPercent = 3f; + collidesTeam = true; + backColor = Pal.heal; + frontColor = Color.white; }}; - healBulletBig = new HealBulletType(5.2f, 15){{ + healBulletBig = new LaserBoltBulletType(5.2f, 15){{ healPercent = 5.5f; + collidesTeam = true; + backColor = Pal.heal; + frontColor = Color.white; }}; fireball = new BulletType(1f, 4){ @@ -500,7 +510,7 @@ public class Bullets implements ContentList{ speed = 4f; knockback = 1.3f; puddleSize = 8f; - damage = 6f; + damage = 5f; drag = 0.001f; ammoMultiplier = 2f; statusDuration = 60f * 4f; diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 6ca6ccb24d..5d0c45348d 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -56,7 +56,7 @@ public class Fx{ mixcol(Pal.accent, 1f); alpha(e.fout()); - rect(block ? ((BlockUnitc)select).tile().block.icon(Cicon.full) : select.type().icon(Cicon.full), select.x, select.y, block ? 0f : select.rotation - 90f); + rect(block ? ((BlockUnitc)select).tile().block.icon(Cicon.full) : select.type.icon(Cicon.full), select.x, select.y, block ? 0f : select.rotation - 90f); alpha(1f); Lines.stroke(e.fslope() * 1f); Lines.square(select.x, select.y, e.fout() * select.hitSize * 2f, 45); @@ -66,7 +66,7 @@ public class Fx{ }), unitDespawn = new Effect(100f, e -> { - if(!(e.data instanceof Unit) || e.data().type() == null) return; + if(!(e.data instanceof Unit) || e.data().type == null) return; Unit select = e.data(); float scl = e.fout(Interp.pow2Out); @@ -74,7 +74,7 @@ public class Fx{ Draw.scl *= scl; mixcol(Pal.accent, 1f); - rect(select.type().icon(Cicon.full), select.x, select.y, select.rotation - 90f); + rect(select.type.icon(Cicon.full), select.x, select.y, select.rotation - 90f); reset(); Draw.scl = p; @@ -1293,6 +1293,14 @@ public class Fx{ }); }), + coreBurn = new Effect(23, e -> { + randLenVectors(e.id, 5, e.fin() * 9f, (x, y) -> { + float len = e.fout() * 4f; + color(Pal.accent, Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, len/2f); + }); + }), + plasticburn = new Effect(40, e -> { randLenVectors(e.id, 5, 3f + e.fin() * 5f, (x, y) -> { color(Color.valueOf("e9ead3"), Color.gray, e.fin()); diff --git a/core/src/mindustry/content/Items.java b/core/src/mindustry/content/Items.java index e16784a61b..6d3964fd2c 100644 --- a/core/src/mindustry/content/Items.java +++ b/core/src/mindustry/content/Items.java @@ -5,7 +5,7 @@ import mindustry.ctype.*; import mindustry.type.*; public class Items implements ContentList{ - public static Item scrap, copper, lead, graphite, coal, titanium, thorium, silicon, plastanium, phasefabric, surgealloy, + public static Item scrap, copper, lead, graphite, coal, titanium, thorium, silicon, plastanium, phaseFabric, surgeAlloy, sporePod, sand, blastCompound, pyratite, metaglass; @Override @@ -66,12 +66,12 @@ public class Items implements ContentList{ cost = 1.3f; }}; - phasefabric = new Item("phase-fabric", Color.valueOf("f4ba6e")){{ + phaseFabric = new Item("phase-fabric", Color.valueOf("f4ba6e")){{ cost = 1.3f; radioactivity = 0.6f; }}; - surgealloy = new Item("surge-alloy", Color.valueOf("f3e979")){{ + surgeAlloy = new Item("surge-alloy", Color.valueOf("f3e979")){{ }}; sporePod = new Item("spore-pod", Color.valueOf("7457ce")){{ diff --git a/core/src/mindustry/content/Planets.java b/core/src/mindustry/content/Planets.java index 873ba1c054..e07203313c 100644 --- a/core/src/mindustry/content/Planets.java +++ b/core/src/mindustry/content/Planets.java @@ -15,6 +15,7 @@ public class Planets implements ContentList{ public void load(){ sun = new Planet("sun", null, 0, 2){{ bloom = true; + accessible = false; //lightColor = Color.valueOf("f4ee8e"); diff --git a/core/src/mindustry/content/SectorPresets.java b/core/src/mindustry/content/SectorPresets.java index 3b76795c1d..e516bab740 100644 --- a/core/src/mindustry/content/SectorPresets.java +++ b/core/src/mindustry/content/SectorPresets.java @@ -18,47 +18,54 @@ public class SectorPresets implements ContentList{ groundZero = new SectorPreset("groundZero", serpulo, 15){{ alwaysUnlocked = true; captureWave = 10; + difficulty = 1; }}; saltFlats = new SectorPreset("saltFlats", serpulo, 101){{ - + difficulty = 5; }}; frozenForest = new SectorPreset("frozenForest", serpulo, 86){{ - captureWave = 40; + captureWave = 20; + difficulty = 2; }}; craters = new SectorPreset("craters", serpulo, 18){{ - captureWave = 40; + captureWave = 20; + difficulty = 2; }}; ruinousShores = new SectorPreset("ruinousShores", serpulo, 19){{ - captureWave = 40; + captureWave = 30; + difficulty = 3; }}; stainedMountains = new SectorPreset("stainedMountains", serpulo, 20){{ captureWave = 30; + difficulty = 3; }}; fungalPass = new SectorPreset("fungalPass", serpulo, 21){{ - + difficulty = 4; }}; overgrowth = new SectorPreset("overgrowth", serpulo, 22){{ - + difficulty = 5; }}; tarFields = new SectorPreset("tarFields", serpulo, 23){{ - captureWave = 40; + captureWave = 50; + difficulty = 5; }}; desolateRift = new SectorPreset("desolateRift", serpulo, 123){{ captureWave = 40; + difficulty = 8; }}; - nuclearComplex = new SectorPreset("nuclearComplex", serpulo, 130){{ captureWave = 60; + difficulty = 7; }}; } } diff --git a/core/src/mindustry/content/StatusEffects.java b/core/src/mindustry/content/StatusEffects.java index 6752cf68e6..4cdfadec76 100644 --- a/core/src/mindustry/content/StatusEffects.java +++ b/core/src/mindustry/content/StatusEffects.java @@ -33,7 +33,7 @@ public class StatusEffects implements ContentList{ freezing = new StatusEffect("freezing"){{ speedMultiplier = 0.6f; - armorMultiplier = 0.8f; + healthMultiplier = 0.8f; effect = Fx.freezing; init(() -> { @@ -81,7 +81,7 @@ public class StatusEffects implements ContentList{ melting = new StatusEffect("melting"){{ speedMultiplier = 0.8f; - armorMultiplier = 0.8f; + healthMultiplier = 0.8f; damage = 0.3f; effect = Fx.melting; @@ -93,7 +93,7 @@ public class StatusEffects implements ContentList{ sapped = new StatusEffect("sapped"){{ speedMultiplier = 0.7f; - armorMultiplier = 0.8f; + healthMultiplier = 0.8f; effect = Fx.sapped; effectChance = 0.1f; }}; @@ -115,7 +115,7 @@ public class StatusEffects implements ContentList{ }}; overdrive = new StatusEffect("overdrive"){{ - armorMultiplier = 0.95f; + healthMultiplier = 0.95f; speedMultiplier = 1.15f; damageMultiplier = 1.4f; damage = -0.01f; @@ -132,13 +132,13 @@ public class StatusEffects implements ContentList{ }}; shielded = new StatusEffect("shielded"){{ - armorMultiplier = 3f; + healthMultiplier = 3f; }}; boss = new StatusEffect("boss"){{ permanent = true; - damageMultiplier = 1.5f; - armorMultiplier = 1.5f; + damageMultiplier = 2f; + healthMultiplier = 2f; }}; shocked = new StatusEffect("shocked"); diff --git a/core/src/mindustry/content/TechTree.java b/core/src/mindustry/content/TechTree.java index fd025b2169..63eb9f2679 100644 --- a/core/src/mindustry/content/TechTree.java +++ b/core/src/mindustry/content/TechTree.java @@ -15,6 +15,7 @@ import static mindustry.type.ItemStack.*; public class TechTree implements ContentList{ static ObjectMap map = new ObjectMap<>(); + static TechNode context = null; public static Seq all; public static TechNode root; @@ -109,8 +110,6 @@ public class TechTree implements ContentList{ node(Items.coal, with(Items.lead, 3000), () -> { node(Items.graphite, with(Items.coal, 1000), () -> { - node(illuminator, () -> { - }); node(graphitePress, () -> { node(Items.titanium, with(Items.graphite, 6000, Items.copper, 10000, Items.lead, 10000), () -> { @@ -162,7 +161,7 @@ public class TechTree implements ContentList{ node(Items.plastanium, with(Items.titanium, 10000, Items.silicon, 10000), () -> { node(plastaniumCompressor, () -> { - node(Items.phasefabric, with(Items.thorium, 15000, Items.sand, 30000, Items.silicon, 5000), () -> { + node(Items.phaseFabric, with(Items.thorium, 15000, Items.sand, 30000, Items.silicon, 5000), () -> { node(phaseWeaver, () -> { }); @@ -178,7 +177,7 @@ public class TechTree implements ContentList{ node(Items.scrap, with(Items.copper, 20000, Items.sand, 10000), () -> { node(Liquids.slag, with(Items.scrap, 4000), () -> { node(melter, () -> { - node(Items.surgealloy, with(Items.thorium, 20000, Items.silicon, 30000, Items.lead, 40000), () -> { + node(Items.surgeAlloy, with(Items.thorium, 20000, Items.silicon, 30000, Items.lead, 40000), () -> { node(surgeSmelter, () -> { }); @@ -229,6 +228,9 @@ public class TechTree implements ContentList{ }); }); }); + + node(illuminator, () -> { + }); }); }); @@ -543,36 +545,46 @@ public class TechTree implements ContentList{ } public static void setup(){ - TechNode.context = null; + context = null; map = new ObjectMap<>(); all = new Seq<>(); } - public static TechNode node(UnlockableContent content, Runnable children){ + //all the "node" methods are hidden, because they are for internal context-dependent use only + //for custom research, just use the TechNode constructor + + static TechNode node(UnlockableContent content, Runnable children){ return node(content, content.researchRequirements(), children); } - public static TechNode node(UnlockableContent content, ItemStack[] requirements, Runnable children){ - return new TechNode(content, requirements, children); + static TechNode node(UnlockableContent content, ItemStack[] requirements, Runnable children){ + return node(content, requirements, null, children); } - public static TechNode node(UnlockableContent content, Seq objectives, Runnable children){ - TechNode node = new TechNode(content, content.researchRequirements(), children); - node.objectives = objectives; + static TechNode node(UnlockableContent content, ItemStack[] requirements, Seq objectives, Runnable children){ + TechNode node = new TechNode(context, content, requirements); + if(objectives != null){ + node.objectives = objectives; + } + + TechNode prev = context; + context = node; + children.run(); + context = prev; + return node; } - public static TechNode node(UnlockableContent block){ + static TechNode node(UnlockableContent content, Seq objectives, Runnable children){ + return node(content, content.researchRequirements(), objectives, children); + } + + static TechNode node(UnlockableContent block){ return node(block, () -> {}); } - public static TechNode create(UnlockableContent parent, UnlockableContent block){ - TechNode.context = all.find(t -> t.content == parent); - return node(block, () -> {}); - } - - public static @Nullable - TechNode get(UnlockableContent content){ + @Nullable + public static TechNode get(UnlockableContent content){ return map.get(content); } @@ -581,8 +593,6 @@ public class TechTree implements ContentList{ } public static class TechNode{ - static TechNode context; - /** Depth in tech tree. */ public int depth; /** Requirement node. */ @@ -595,19 +605,16 @@ public class TechTree implements ContentList{ public final ItemStack[] finishedRequirements; /** Extra objectives needed to research this. */ public Seq objectives = new Seq<>(); - /** Time required to research this content, in seconds. */ - public float time; /** Nodes that depend on this node. */ public final Seq children = new Seq<>(); - TechNode(@Nullable TechNode ccontext, UnlockableContent content, ItemStack[] requirements, Runnable children){ - if(ccontext != null) ccontext.children.add(this); + public TechNode(@Nullable TechNode parent, UnlockableContent content, ItemStack[] requirements){ + if(parent != null) parent.children.add(this); - this.parent = ccontext; + this.parent = parent; this.content = content; this.requirements = requirements; this.depth = parent == null ? 0 : parent.depth + 1; - this.time = Seq.with(requirements).mapFloat(i -> i.item.cost * i.amount).sum() * 10; this.finishedRequirements = new ItemStack[requirements.length]; //load up the requirements that have been finished if settings are available @@ -619,14 +626,23 @@ public class TechTree implements ContentList{ content.getDependencies(d -> objectives.add(new Research(d))); map.put(content, this); - context = this; - children.run(); - context = ccontext; all.add(this); } - TechNode(UnlockableContent content, ItemStack[] requirements, Runnable children){ - this(context, content, requirements, children); + /** Resets finished requirements and saves. */ + public void reset(){ + for(ItemStack stack : finishedRequirements){ + stack.amount = 0; + } + save(); + } + + /** Removes this node from the tech tree. */ + public void remove(){ + all.remove(this); + if(parent != null){ + parent.children.remove(this); + } } /** Flushes research progress to settings. */ diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index d301b52652..549a31769f 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -10,6 +10,7 @@ import mindustry.entities.bullet.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -19,17 +20,14 @@ public class UnitTypes implements ContentList{ //mech public static @EntityDef({Unitc.class, Mechc.class}) UnitType mace, dagger, crawler, fortress, scepter, reign; - //mech + builder + miner + commander - public static @EntityDef({Unitc.class, Mechc.class, Builderc.class, Minerc.class, Commanderc.class}) UnitType nova, pulsar, quasar; + //mech + builder + miner + public static @EntityDef({Unitc.class, Mechc.class, Builderc.class, Minerc.class}) UnitType nova, pulsar, quasar; - //mech + commander - public static @EntityDef({Unitc.class, Mechc.class, Commanderc.class}) UnitType vela; - - //legs + commander - public static @EntityDef({Unitc.class, Legsc.class, Commanderc.class}) UnitType corvus; + //mech + public static @EntityDef({Unitc.class, Mechc.class}) UnitType vela; //legs - public static @EntityDef({Unitc.class, Legsc.class}) UnitType atrax; + public static @EntityDef({Unitc.class, Legsc.class}) UnitType corvus, atrax; //legs + building public static @EntityDef({Unitc.class, Legsc.class, Builderc.class}) UnitType spiroct, arkyid, toxopid; @@ -49,14 +47,14 @@ public class UnitTypes implements ContentList{ //air + building + payload public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class}) UnitType quad; - //air + building + payload + command - public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class, Commanderc.class, AmmoDistributec.class}) UnitType oct; + //air + building + payload + public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class, AmmoDistributec.class}) UnitType oct; //air + building + mining public static @EntityDef({Unitc.class, Builderc.class, Minerc.class}) UnitType alpha, beta, gamma; - //water + commander - public static @EntityDef({Unitc.class, WaterMovec.class, Commanderc.class}) UnitType risso, minke, bryde, sei, omura; + //water + public static @EntityDef({Unitc.class, WaterMovec.class}) UnitType risso, minke, bryde, sei, omura; //special block unit type public static @EntityDef({Unitc.class, BlockUnitc.class}) UnitType block; @@ -164,7 +162,7 @@ public class UnitTypes implements ContentList{ y = 1f; x = 16f; shootY = 8f; - reload = 50f; + reload = 45f; recoil = 5f; shake = 2f; ejectEffect = Fx.shellEjectBig; @@ -173,7 +171,7 @@ public class UnitTypes implements ContentList{ inaccuracy = 3f; shotDelay = 4f; - bullet = new BasicBulletType(7f, 45){{ + bullet = new BasicBulletType(7f, 50){{ width = 11f; height = 20f; lifetime = 25f; @@ -182,7 +180,7 @@ public class UnitTypes implements ContentList{ lightningLength = 6; lightningColor = Pal.surge; //standard bullet damage is far too much for lightning - lightningDamage = 25; + lightningDamage = 30; }}; }}, @@ -230,8 +228,9 @@ public class UnitTypes implements ContentList{ ejectEffect = Fx.shellEjectBig; shootSound = Sounds.artillery; - bullet = new BasicBulletType(13f, 55){{ + bullet = new BasicBulletType(13f, 60){{ pierce = true; + pierceCap = 10; width = 14f; height = 33f; lifetime = 15f; @@ -250,6 +249,8 @@ public class UnitTypes implements ContentList{ width = 10f; height = 10f; pierce = true; + pierceBuilding = true; + pierceCap = 3; lifetime = 20f; hitEffect = Fx.flakExplosion; @@ -266,7 +267,6 @@ public class UnitTypes implements ContentList{ //region ground support nova = new UnitType("nova"){{ - itemCapacity = 60; canBoost = true; boostMultiplier = 1.5f; speed = 0.55f; @@ -276,7 +276,7 @@ public class UnitTypes implements ContentList{ armor = 1f; commandLimit = 8; - abilities.add(new HealFieldAbility(10f, 60f * 4, 60f)); + abilities.add(new RepairFieldAbility(10f, 60f * 4, 60f)); ammoType = AmmoTypes.power; weapons.add(new Weapon("heal-weapon"){{ @@ -293,12 +293,11 @@ public class UnitTypes implements ContentList{ }}; pulsar = new UnitType("pulsar"){{ - itemCapacity = 60; canBoost = true; - boostMultiplier = 1.5f; - speed = 0.65f; + boostMultiplier = 1.6f; + speed = 0.7f; hitSize = 10f; - health = 320f; + health = 300f; buildSpeed = 0.9f; armor = 4f; @@ -306,7 +305,7 @@ public class UnitTypes implements ContentList{ mineSpeed = 5f; commandLimit = 8; - abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 5, 60f)); + abilities.add(new ShieldRegenFieldAbility(20f, 40f, 60f * 5, 60f)); ammoType = AmmoTypes.power; weapons.add(new Weapon("heal-shotgun-weapon"){{ @@ -337,10 +336,9 @@ public class UnitTypes implements ContentList{ }}; quasar = new UnitType("quasar"){{ - mineTier = 1; + mineTier = 3; hitSize = 12f; boostMultiplier = 2f; - itemCapacity = 80; health = 650f; buildSpeed = 1.7f; canBoost = true; @@ -354,8 +352,7 @@ public class UnitTypes implements ContentList{ speed = 0.4f; hitSize = 10f; - mineTier = 2; - mineSpeed = 7f; + mineSpeed = 6f; drawShields = false; abilities.add(new ForceFieldAbility(60f, 0.3f, 400f, 60f * 6)); @@ -397,7 +394,7 @@ public class UnitTypes implements ContentList{ engineSize = 6f; lowAltitude = true; - health = 6500f; + health = 7000f; armor = 7f; canBoost = true; landShake = 4f; @@ -445,7 +442,6 @@ public class UnitTypes implements ContentList{ corvus = new UnitType("corvus"){{ mineTier = 1; hitSize = 29f; - itemCapacity = 80; health = 18000f; buildSpeed = 1.7f; armor = 9f; @@ -519,7 +515,7 @@ public class UnitTypes implements ContentList{ crawler = new UnitType("crawler"){{ defaultController = SuicideAI::new; - speed = 0.9f; + speed = 1f; hitSize = 8f; health = 180; mechSideSway = 0.25f; @@ -534,9 +530,9 @@ public class UnitTypes implements ContentList{ hitEffect = Fx.pulverize; lifetime = 10f; speed = 1f; - splashDamageRadius = 55f; + splashDamageRadius = 70f; instantDisappear = true; - splashDamage = 60f; + splashDamage = 80f; killShooter = true; hittable = false; collidesAir = true; @@ -545,7 +541,6 @@ public class UnitTypes implements ContentList{ }}; atrax = new UnitType("atrax"){{ - itemCapacity = 80; speed = 0.5f; drag = 0.4f; hitSize = 10f; @@ -878,7 +873,6 @@ public class UnitTypes implements ContentList{ drag = 0.01f; flying = true; health = 75; - faceTarget = false; engineOffset = 5.5f; range = 140f; @@ -904,6 +898,7 @@ public class UnitTypes implements ContentList{ range = 140f; faceTarget = false; armor = 4f; + targetFlag = BlockFlag.factory; weapons.add(new Weapon(){{ minShootVelocity = 0.75f; @@ -984,6 +979,7 @@ public class UnitTypes implements ContentList{ engineOffset = 21; engineSize = 5.3f; hitSize = 56f; + targetFlag = BlockFlag.battery; BulletType missiles = new MissileBulletType(2.7f, 10){{ width = 8f; @@ -1058,6 +1054,7 @@ public class UnitTypes implements ContentList{ hitSize = 58f; destructibleWreck = false; armor = 13f; + targetFlag = BlockFlag.reactor; BulletType fragBullet = new FlakBulletType(4f, 5){{ shootEffect = Fx.shootBig; @@ -1134,7 +1131,6 @@ public class UnitTypes implements ContentList{ health = 100; engineSize = 1.8f; engineOffset = 5.7f; - itemCapacity = 30; range = 50f; isCounted = false; @@ -1149,24 +1145,22 @@ public class UnitTypes implements ContentList{ flying = true; drag = 0.05f; - speed = 1.9f; + speed = 2.6f; rotateSpeed = 15f; accel = 0.1f; - range = 70f; - itemCapacity = 70; + range = 130f; health = 400; buildSpeed = 0.5f; engineOffset = 6.5f; hitSize = 8f; lowAltitude = true; - isCounted = false; ammoType = AmmoTypes.power; mineTier = 2; mineSpeed = 3.5f; - abilities.add(new HealFieldAbility(5f, 60f * 5, 50f)); + abilities.add(new RepairFieldAbility(5f, 60f * 5, 50f)); weapons.add(new Weapon("heal-weapon-mount"){{ top = false; @@ -1189,8 +1183,11 @@ public class UnitTypes implements ContentList{ keepVelocity = false; shootEffect = Fx.shootHeal; smokeEffect = Fx.hitLaser; + hitEffect = despawnEffect = Fx.hitLaser; frontColor = Color.white; + healPercent = 5.5f; + collidesTeam = true; backColor = Pal.heal; trailColor = Pal.heal; }}; @@ -1200,11 +1197,10 @@ public class UnitTypes implements ContentList{ mega = new UnitType("mega"){{ defaultController = RepairAI::new; - mineTier = 2; + mineTier = 3; health = 500; - armor = 2f; armor = 5f; - speed = 1.8f; + speed = 2.3f; accel = 0.06f; drag = 0.017f; lowAltitude = true; @@ -1236,9 +1232,9 @@ public class UnitTypes implements ContentList{ }}; quad = new UnitType("quad"){{ - armor = 4f; + armor = 8f; health = 6000; - speed = 1.2f; + speed = 1.4f; rotateSpeed = 2f; accel = 0.05f; drag = 0.017f; @@ -1252,6 +1248,7 @@ public class UnitTypes implements ContentList{ buildSpeed = 2.5f; range = 140f; targetAir = false; + targetFlag = BlockFlag.battery; ammoType = AmmoTypes.powerHigh; @@ -1259,7 +1256,7 @@ public class UnitTypes implements ContentList{ new Weapon(){{ x = y = 0f; mirror = false; - reload = 60f; + reload = 55f; minShootVelocity = 0.01f; bullet = new BasicBulletType(){{ @@ -1292,8 +1289,9 @@ public class UnitTypes implements ContentList{ speed = 0.001f; collides = false; - splashDamage = 240f; - splashDamageRadius = 115f; + healPercent = 15f; + splashDamage = 320f; + splashDamageRadius = 120f; }}; }}); }}; @@ -1301,7 +1299,7 @@ public class UnitTypes implements ContentList{ oct = new UnitType("oct"){{ armor = 16f; health = 24000; - speed = 0.6f; + speed = 0.8f; rotateSpeed = 1f; accel = 0.04f; drag = 0.018f; @@ -1314,11 +1312,12 @@ public class UnitTypes implements ContentList{ buildSpeed = 4f; drawShields = false; commandLimit = 6; + lowAltitude = true; ammoCapacity = 1300; ammoResupplyAmount = 20; - abilities.add(new ForceFieldAbility(140f, 4f, 7000f, 60f * 8), new HealFieldAbility(130f, 60f * 2, 140f)); + abilities.add(new ForceFieldAbility(140f, 4f, 7000f, 60f * 8), new RepairFieldAbility(130f, 60f * 2, 140f)); }}; //endregion @@ -1430,7 +1429,7 @@ public class UnitTypes implements ContentList{ trailY = -9f; trailScl = 1.5f; - abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 4, 60f)); + abilities.add(new ShieldRegenFieldAbility(20f, 40f, 60f * 4, 60f)); weapons.add(new Weapon("large-artillery"){{ reload = 65f; @@ -1452,13 +1451,13 @@ public class UnitTypes implements ContentList{ trailMult = 0.8f; hitEffect = Fx.massiveExplosion; knockback = 1.5f; - lifetime = 140f; + lifetime = 100f; height = 15.5f; width = 15f; collidesTiles = false; ammoMultiplier = 4f; splashDamageRadius = 60f; - splashDamage = 85f; + splashDamage = 80f; backColor = Pal.missileYellowBack; frontColor = Pal.missileYellow; trailEffect = Fx.artilleryTrail; @@ -1547,7 +1546,7 @@ public class UnitTypes implements ContentList{ xRand = 8f; shotDelay = 1f; - bullet = new MissileBulletType(4.2f, 25){{ + bullet = new MissileBulletType(4.2f, 30){{ homingPower = 0.12f; width = 8f; height = 8f; @@ -1555,8 +1554,8 @@ public class UnitTypes implements ContentList{ drag = -0.003f; homingRange = 80f; keepVelocity = false; - splashDamageRadius = 25f; - splashDamage = 25f; + splashDamageRadius = 30f; + splashDamage = 35f; lifetime = 56f; trailColor = Pal.bulletYellowBack; backColor = Pal.bulletYellowBack; @@ -1654,13 +1653,14 @@ public class UnitTypes implements ContentList{ mineTier = 1; buildSpeed = 0.5f; drag = 0.05f; - speed = 2.8f; + speed = 3f; rotateSpeed = 15f; accel = 0.1f; itemCapacity = 30; - health = 120f; + health = 150f; engineOffset = 6f; hitSize = 8f; + commandLimit = 3; weapons.add(new Weapon("small-basic-weapon"){{ reload = 17f; @@ -1668,13 +1668,13 @@ public class UnitTypes implements ContentList{ y = 1f; top = false; - bullet = new BasicBulletType(2.5f, 9){{ + bullet = new BasicBulletType(2.5f, 10){{ width = 7f; height = 9f; lifetime = 60f; shootEffect = Fx.shootSmall; smokeEffect = Fx.shootSmallSmoke; - tileDamageMultiplier = 0.09f; + tileDamageMultiplier = 0.03f; }}; }}); }}; @@ -1688,15 +1688,16 @@ public class UnitTypes implements ContentList{ mineTier = 1; buildSpeed = 0.75f; drag = 0.05f; - speed = 3f; + speed = 3.3f; rotateSpeed = 17f; accel = 0.1f; itemCapacity = 50; - health = 150f; + health = 170f; engineOffset = 6f; hitSize = 9f; rotateShooting = false; lowAltitude = true; + commandLimit = 5; weapons.add(new Weapon("small-mount-weapon"){{ top = false; @@ -1708,13 +1709,13 @@ public class UnitTypes implements ContentList{ shotDelay = 4f; spacing = 0f; - bullet = new BasicBulletType(3f, 9){{ + bullet = new BasicBulletType(3f, 10){{ width = 7f; height = 9f; lifetime = 60f; shootEffect = Fx.shootSmall; smokeEffect = Fx.shootSmallSmoke; - tileDamageMultiplier = 0.1f; + tileDamageMultiplier = 0.03f; }}; }}); }}; @@ -1728,13 +1729,14 @@ public class UnitTypes implements ContentList{ mineTier = 2; buildSpeed = 1f; drag = 0.05f; - speed = 3.5f; + speed = 3.55f; rotateSpeed = 19f; accel = 0.11f; itemCapacity = 70; - health = 190f; + health = 220f; engineOffset = 6f; hitSize = 10f; + commandLimit = 7; weapons.add(new Weapon("small-mount-weapon"){{ top = false; @@ -1746,13 +1748,13 @@ public class UnitTypes implements ContentList{ inaccuracy = 3f; shotDelay = 3f; - bullet = new BasicBulletType(3.5f, 9){{ + bullet = new BasicBulletType(3.5f, 10){{ width = 6.5f; height = 11f; lifetime = 70f; shootEffect = Fx.shootSmall; smokeEffect = Fx.shootSmallSmoke; - tileDamageMultiplier = 0.1f; + tileDamageMultiplier = 0.03f; homingPower = 0.04f; }}; }}); diff --git a/core/src/mindustry/content/Weathers.java b/core/src/mindustry/content/Weathers.java index a2ffbb098f..b120b7ef2b 100644 --- a/core/src/mindustry/content/Weathers.java +++ b/core/src/mindustry/content/Weathers.java @@ -1,339 +1,89 @@ package mindustry.content; -import arc.*; import arc.graphics.*; -import arc.graphics.Texture.*; -import arc.graphics.g2d.*; -import arc.math.*; import arc.util.*; import mindustry.ctype.*; -import mindustry.gen.*; import mindustry.type.*; -import mindustry.world.*; +import mindustry.type.weather.*; import mindustry.world.meta.*; -import static mindustry.Vars.*; - public class Weathers implements ContentList{ public static Weather rain, snow, sandstorm, - sporestorm; + sporestorm, + fog; @Override public void load(){ - snow = new Weather("snow"){ - TextureRegion region; - float yspeed = 2f, xspeed = 0.25f, padding = 16f, size = 12f, density = 1200f; + snow = new ParticleWeather("snow"){{ + sizeMax = 13f; + sizeMin = 2.6f; + density = 1200f; + attrs.set(Attribute.light, -0.15f); + }}; - { - attrs.set(Attribute.light, -0.15f); - } + rain = new RainWeather("rain"){{ + attrs.set(Attribute.light, -0.2f); + attrs.set(Attribute.water, 0.2f); + status = StatusEffects.wet; + }}; - @Override - public void load(){ - super.load(); + sandstorm = new ParticleWeather("sandstorm"){{ + color = noiseColor = Color.valueOf("f7cba4"); + drawNoise = true; + useWindVector = true; + sizeMax = 140f; + sizeMin = 70f; + minAlpha = 0f; + maxAlpha = 0.2f; + density = 1500f; + baseSpeed = 6.1f; + attrs.set(Attribute.light, -0.1f); + attrs.set(Attribute.water, -0.1f); + opacityMultiplier = 0.8f; + force = 0.1f; + }}; - region = Core.atlas.find("circle-shadow"); - } + sporestorm = new ParticleWeather("sporestorm"){{ + color = noiseColor = Color.valueOf("7457ce"); + particleRegion = "circle"; + drawNoise = true; + statusGround = false; + useWindVector = true; + sizeMax = 5f; + sizeMin = 2.5f; + minAlpha = 0.1f; + maxAlpha = 0.8f; + density = 2000f; + baseSpeed = 4.3f; + attrs.set(Attribute.spores, 1f); + attrs.set(Attribute.light, -0.15f); + status = StatusEffects.sporeSlowed; + opacityMultiplier = 0.85f; + force = 0.1f; + }}; - @Override - public void drawOver(WeatherState state){ - rand.setSeed(0); - Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale()); - Tmp.r1.grow(padding); - Core.camera.bounds(Tmp.r2); - int total = (int)(Tmp.r1.area() / density * state.intensity()); - - for(int i = 0; i < total; i++){ - float scl = rand.random(0.5f, 1f); - float scl2 = rand.random(0.5f, 1f); - float sscl = rand.random(0.2f, 1f); - float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2); - float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl); - - x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f)); - - x -= Tmp.r1.x; - y -= Tmp.r1.y; - x = Mathf.mod(x, Tmp.r1.width); - y = Mathf.mod(y, Tmp.r1.height); - x += Tmp.r1.x; - y += Tmp.r1.y; - - if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){ - Draw.rect(region, x, y, size * sscl, size * sscl); - } - } - } - }; - - rain = new Weather("rain"){ - float yspeed = 5f, xspeed = 1.5f, padding = 16f, size = 40f, density = 1200f; - TextureRegion[] splashes = new TextureRegion[12]; - - { - attrs.set(Attribute.light, -0.2f); - attrs.set(Attribute.water, 0.2f); - status = StatusEffects.wet; - } - - @Override - public void load(){ - super.load(); - - for(int i = 0; i < splashes.length; i++){ - splashes[i] = Core.atlas.find("splash-" + i); - } - } - - @Override - public void drawOver(WeatherState state){ - Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale()); - Tmp.r1.grow(padding); - Core.camera.bounds(Tmp.r2); - int total = (int)(Tmp.r1.area() / density * state.intensity()); - Lines.stroke(0.75f); - float alpha = Draw.getColor().a; - Draw.color(Color.royal, Color.white, 0.3f); - - for(int i = 0; i < total; i++){ - float scl = rand.random(0.5f, 1f); - float scl2 = rand.random(0.5f, 1f); - float sscl = rand.random(0.2f, 1f); - float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2); - float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl); - float tint = rand.random(1f) * alpha; - - x -= Tmp.r1.x; - y -= Tmp.r1.y; - x = Mathf.mod(x, Tmp.r1.width); - y = Mathf.mod(y, Tmp.r1.height); - x += Tmp.r1.x; - y += Tmp.r1.y; - - if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){ - Draw.alpha(tint); - Lines.lineAngle(x, y, Angles.angle(xspeed * scl2, - yspeed * scl), size*sscl/2f); - } - } - } - - @Override - public void drawUnder(WeatherState state){ - Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale()); - Tmp.r1.grow(padding); - Core.camera.bounds(Tmp.r2); - int total = (int)(Tmp.r1.area() / density * state.intensity()) / 2; - Lines.stroke(0.75f); - - float t = Time.time() / 22f; - - for(int i = 0; i < total; i++){ - float offset = rand.random(0f, 1f); - float time = t + offset; - - int pos = (int)((time)); - float life = time % 1f; - float x = (rand.random(0f, world.unitWidth()) + pos*953); - float y = (rand.random(0f, world.unitHeight()) - pos*453); - - x -= Tmp.r1.x; - y -= Tmp.r1.y; - x = Mathf.mod(x, Tmp.r1.width); - y = Mathf.mod(y, Tmp.r1.height); - x += Tmp.r1.x; - y += Tmp.r1.y; - - if(Tmp.r3.setCentered(x, y, life * 4f).overlaps(Tmp.r2)){ - Tile tile = world.tileWorld(x, y); - - if(tile != null && tile.floor().liquidDrop == Liquids.water){ - Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.5f).a(state.opacity())); - Draw.rect(splashes[(int)(life * (splashes.length - 1))], x, y); - }else{ - Draw.color(Color.royal, Color.white, 0.3f); - Draw.alpha(Mathf.slope(life) * state.opacity()); - - float space = 45f; - for(int j : new int[]{-1, 1}){ - Tmp.v1.trns(90f + j*space, 1f + 5f * life); - Lines.lineAngle(x + Tmp.v1.x, y + Tmp.v1.y, 90f + j*space, 3f * (1f - life)); - } - } - } - } - } - }; - - sandstorm = new Weather("sandstorm"){ - TextureRegion region; - float size = 140f, padding = size, invDensity = 1500f, baseSpeed = 6.1f; - float force = 0.4f * 0; - Color color = Color.valueOf("f7cba4"); - Texture noise; - - { - attrs.set(Attribute.light, -0.1f); - opacityMultiplier = 0.8f; - } - - @Override - public void load(){ - region = Core.atlas.find("circle-shadow"); - noise = new Texture("sprites/noiseAlpha.png"); - noise.setWrap(TextureWrap.repeat); - noise.setFilter(TextureFilter.linear); - } - - @Override - public void dispose(){ - noise.dispose(); - } - - @Override - public void update(WeatherState state){ - float speed = force * state.intensity; - float windx = state.windVector.x * speed, windy = state.windVector.y * speed; - - for(Unit unit : Groups.unit){ - unit.impulse(windx, windy); - } - } - - @Override - public void drawOver(WeatherState state){ - Draw.tint(color); - float speed = baseSpeed * state.intensity; - float windx = state.windVector.x * speed, windy = state.windVector.y * speed; - - float scale = 1f / 2000f; - float scroll = Time.time() * scale; - Tmp.tr1.texture = noise; - Core.camera.bounds(Tmp.r1); - Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale); - Tmp.tr1.scroll(-windx * scroll, windy * scroll); - Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height); - - rand.setSeed(0); - Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale()); - Tmp.r1.grow(padding); - Core.camera.bounds(Tmp.r2); - int total = (int)(Tmp.r1.area() / invDensity * state.intensity()); - Draw.tint(color); - float baseAlpha = Draw.getColor().a; - - for(int i = 0; i < total; i++){ - float scl = rand.random(0.5f, 1f); - float scl2 = rand.random(0.5f, 1f); - float sscl = rand.random(0.5f, 1f); - float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2); - float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl); - float alpha = rand.random(0.2f); - - x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f)); - - x -= Tmp.r1.x; - y -= Tmp.r1.y; - x = Mathf.mod(x, Tmp.r1.width); - y = Mathf.mod(y, Tmp.r1.height); - x += Tmp.r1.x; - y += Tmp.r1.y; - - if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){ - Draw.alpha(alpha * baseAlpha); - Draw.rect(region, x, y, size * sscl, size * sscl); - } - } - } - }; - - sporestorm = new Weather("sporestorm"){ - TextureRegion region; - float size = 5f, padding = size, invDensity = 2000f, baseSpeed = 4.3f, force = 0.28f * 0; - Color color = Color.valueOf("7457ce"); - Texture noise; - - { - attrs.set(Attribute.spores, 1f); - attrs.set(Attribute.light, -0.15f); - status = StatusEffects.sporeSlowed; - statusGround = false; - opacityMultiplier = 0.85f; - } - - @Override - public void load(){ - region = Core.atlas.find("circle-shadow"); - noise = new Texture("sprites/noiseAlpha.png"); - noise.setWrap(TextureWrap.repeat); - noise.setFilter(TextureFilter.linear); - } - - @Override - public void update(WeatherState state){ - float speed = force * state.intensity; - float windx = state.windVector.x * speed, windy = state.windVector.y * speed; - - for(Unit unit : Groups.unit){ - unit.impulse(windx, windy); - } - } - - @Override - public void dispose(){ - noise.dispose(); - } - - @Override - public void drawOver(WeatherState state){ - Draw.alpha(state.opacity * 0.8f); - Draw.tint(color); - - float speed = baseSpeed * state.intensity; - float windx = state.windVector.x * speed, windy = state.windVector.y * speed; - - float scale = 1f / 2000f; - float scroll = Time.time() * scale; - Tmp.tr1.texture = noise; - Core.camera.bounds(Tmp.r1); - Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale); - Tmp.tr1.scroll(-windx * scroll, windy * scroll); - Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height); - - rand.setSeed(0); - Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale()); - Tmp.r1.grow(padding); - Core.camera.bounds(Tmp.r2); - int total = (int)(Tmp.r1.area() / invDensity * state.intensity()); - Draw.tint(color); - float baseAlpha = state.opacity; - Draw.alpha(baseAlpha); - - for(int i = 0; i < total; i++){ - float scl = rand.random(0.5f, 1f); - float scl2 = rand.random(0.5f, 1f); - float sscl = rand.random(0.5f, 1f); - float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2); - float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl); - float alpha = rand.random(0.1f, 0.8f); - - x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f)); - - x -= Tmp.r1.x; - y -= Tmp.r1.y; - x = Mathf.mod(x, Tmp.r1.width); - y = Mathf.mod(y, Tmp.r1.height); - x += Tmp.r1.x; - y += Tmp.r1.y; - - if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){ - Draw.alpha(alpha * baseAlpha); - Fill.circle(x, y, size * sscl / 2f); - } - } - } - }; + fog = new ParticleWeather("fog"){{ + duration = 15f * Time.toMinutes; + noiseLayers = 3; + noiseLayerSclM = 0.8f; + noiseLayerAlphaM = 0.7f; + noiseLayerSpeedM = 2f; + noiseLayerSclM = 0.6f; + baseSpeed = 0.05f; + color = noiseColor = Color.grays(0.4f); + noiseScale = 1100f; + noisePath = "fog"; + drawParticles = false; + drawNoise = true; + useWindVector = false; + xspeed = 1f; + yspeed = 0.01f; + attrs.set(Attribute.light, -0.3f); + attrs.set(Attribute.water, 0.05f); + opacityMultiplier = 0.47f; + }}; } } diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index 86cf82c797..3d904c1826 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -9,7 +9,6 @@ import arc.math.*; import arc.scene.ui.*; import arc.struct.*; import arc.util.*; -import mindustry.*; import mindustry.audio.*; import mindustry.content.*; import mindustry.core.GameState.*; @@ -25,7 +24,6 @@ import mindustry.maps.Map; import mindustry.type.*; import mindustry.ui.dialogs.*; import mindustry.world.*; -import mindustry.world.blocks.storage.CoreBlock.*; import java.io.*; import java.text.*; @@ -37,7 +35,7 @@ import static mindustry.Vars.*; /** * Control module. - * Handles all input, saving, keybinds and keybinds. + * Handles all input, saving and keybinds. * Should not handle any logic-critical state. * This class is not created in the headless server. */ @@ -160,9 +158,7 @@ public class Control implements ApplicationListener, Loadable{ //delete the save, it is gone. if(saves.getCurrent() != null && !state.rules.tutorial){ - Sector sector = state.getSector(); - sector.save = null; - saves.getCurrent().delete(); + saves.getCurrent().save(); } } }); @@ -252,19 +248,6 @@ public class Control implements ApplicationListener, Loadable{ }); } - //TODO move - public void handleLaunch(CoreBuild tile){ - LaunchCorec ent = LaunchCore.create(); - ent.set(tile); - ent.block(Blocks.coreShard); - ent.lifetime(Vars.launchDuration); - ent.add(); - - //remove schematic requirements from core - tile.items.remove(universe.getLastLoadout().requirements()); - tile.items.remove(universe.getLaunchResources()); - } - public void playSector(Sector sector){ playSector(sector, sector); } @@ -281,21 +264,29 @@ public class Control implements ApplicationListener, Loadable{ slot.load(); slot.setAutosave(true); state.rules.sector = sector; + state.secinfo = state.rules.sector.info; //if there is no base, simulate a new game and place the right loadout at the spawn position - //TODO this is broken? if(state.rules.defaultTeam.cores().isEmpty()){ - //kill all friendly units, since they should be dead anwyay - for(Unit unit : Groups.unit){ - if(unit.team() == state.rules.defaultTeam){ - unit.remove(); - } + //no spawn set -> delete the sector save + if(sector.info.spawnPosition == 0){ + //delete old save + sector.save = null; + slot.delete(); + //play again + playSector(origin, sector); + return; } - Tile spawn = world.tile(sector.getSpawnPosition()); - //TODO PLACE CORRECT LOADOUT - Schematics.placeLoadout(universe.getLastLoadout(), spawn.x, spawn.y); + //reset wave so things are more fair + state.wave = 1; + + //kill all units, since they should be dead anwyay + Groups.unit.clear(); + + Tile spawn = world.tile(sector.info.spawnPosition); + Schematics.placeLaunchLoadout(spawn.x, spawn.y); //set up camera/player locations player.set(spawn.x * tilesize, spawn.y * tilesize); diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java index 949e40d02d..41f14074c8 100644 --- a/core/src/mindustry/core/GameState.java +++ b/core/src/mindustry/core/GameState.java @@ -23,7 +23,7 @@ public class GameState{ /** The current game rules. */ public Rules rules = new Rules(); /** Statistics for this save/game. Displayed after game over. */ - public Stats stats = new Stats(); + public GameStats stats = new GameStats(); /** Global attributes of the environment, calculated by weather. */ public Attributes envAttrs = new Attributes(); /** Sector information. Only valid in the campaign. */ @@ -41,10 +41,17 @@ public class GameState{ } public void set(State astate){ + //cannot pause when in multiplayer + if(astate == State.paused && net.active()) return; + Events.fire(new StateChangeEvent(state, astate)); state = astate; } + public boolean hasSpawns(){ + return rules.waves && !(isCampaign() && rules.attackMode); + } + /** Note that being in a campaign does not necessarily mean having a sector. */ public boolean isCampaign(){ return rules.sector != null; @@ -68,7 +75,7 @@ public class GameState{ } public boolean isPlaying(){ - return state == State.playing; + return (state == State.playing) || (state == State.paused && !isPaused()); } /** @return whether the current state is *not* the menu. */ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index e03771843a..b8d736126b 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -5,6 +5,7 @@ import arc.math.*; import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.core.GameState.*; +import mindustry.ctype.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.game.Teams.*; @@ -13,9 +14,6 @@ import mindustry.maps.*; import mindustry.type.*; import mindustry.type.Weather.*; import mindustry.world.*; -import mindustry.world.blocks.*; -import mindustry.world.blocks.ConstructBlock.*; -import mindustry.world.blocks.storage.CoreBlock.*; import java.util.*; @@ -40,32 +38,7 @@ public class Logic implements ApplicationListener{ //skip null entities or un-rebuildables, for obvious reasons; also skip client since they can't modify these requests if(tile.build == null || !tile.block().rebuildable || net.client()) return; - if(block instanceof ConstructBlock){ - - ConstructBuild entity = tile.bc(); - - //update block to reflect the fact that something was being constructed - if(entity.cblock != null && entity.cblock.synthetic()){ - block = entity.cblock; - }else{ - //otherwise this was a deconstruction that was interrupted, don't want to rebuild that - return; - } - } - - TeamData data = state.teams.get(tile.team()); - - //remove existing blocks that have been placed here. - //painful O(n) iteration + copy - for(int i = 0; i < data.blocks.size; i++){ - BlockPlan b = data.blocks.get(i); - if(b.x == tile.x && b.y == tile.y){ - data.blocks.removeIndex(i); - break; - } - } - - data.blocks.addFirst(new BlockPlan(tile.x, tile.y, (short)tile.build.rotation, block.id, tile.build.config())); + tile.build.addPlan(true); }); Events.on(BlockBuildEndEvent.class, event -> { @@ -85,48 +58,61 @@ public class Logic implements ApplicationListener{ Events.on(LaunchItemEvent.class, e -> state.secinfo.handleItemExport(e.stack)); //when loading a 'damaged' sector, propagate the damage - Events.on(WorldLoadEvent.class, e -> { + Events.on(SaveLoadEvent.class, e -> { if(state.isCampaign()){ - long seconds = state.rules.sector.getSecondsPassed(); - CoreBuild core = state.rules.defaultTeam.core(); + state.secinfo.write(); - //apply fractional damage based on how many turns have passed for this sector - float turnsPassed = seconds / (turnDuration / 60f); + //how much wave time has passed + int wavesPassed = state.secinfo.wavesPassed; - if(state.rules.sector.hasWaves() && turnsPassed > 0 && state.rules.sector.hasBase()){ - SectorDamage.apply(turnsPassed / sectorDestructionTurns); + //wave has passed, remove all enemies, they are assumed to be dead + if(wavesPassed > 0){ + Groups.unit.each(u -> { + if(u.team == state.rules.waveTeam){ + u.remove(); + } + }); } - //add resources based on turns passed - if(state.rules.sector.save != null && core != null){ - //update correct storage capacity - state.rules.sector.save.meta.secinfo.storageCapacity = core.storageCapacity; + //simulate passing of waves + if(wavesPassed > 0){ + //simulate wave counter moving forward + state.wave += wavesPassed; + state.wavetime = state.rules.waveSpacing; - //add new items received - state.rules.sector.calculateReceivedItems().each((item, amount) -> core.items.add(item, amount)); - - //clear received items - state.rules.sector.setExtraItems(new ItemSeq()); - - //validation - for(Item item : content.items()){ - //ensure positive items - if(core.items.get(item) < 0) core.items.set(item, 0); - //cap the items - if(core.items.get(item) > core.storageCapacity) core.items.set(item, core.storageCapacity); - } + SectorDamage.applyCalculatedDamage(); } - state.rules.sector.setSecondsPassed(0); + //reset values + state.secinfo.damage = 0f; + state.secinfo.wavesPassed = 0; + state.secinfo.hasCore = true; + state.secinfo.secondsPassed = 0; + + state.rules.sector.saveInfo(); } + }); + Events.on(WorldLoadEvent.class, e -> { //enable infinite ammo for wave team by default state.rules.waveTeam.rules().infiniteAmmo = true; + if(state.isCampaign()){ + //enable building AI + state.rules.waveTeam.rules().ai = true; + state.rules.waveTeam.rules().infiniteResources = true; + } //save settings Core.settings.manualSave(); }); + //sync research + Events.on(ResearchEvent.class, e -> { + if(net.server()){ + Call.researched(e.content); + } + }); + } /** Adds starting items, resets wave time, and sets state to playing. */ @@ -166,11 +152,6 @@ public class Logic implements ApplicationListener{ } public void skipWave(){ - if(state.isCampaign()){ - //warp time spent forward because the wave was just skipped. - state.secinfo.internalTimeSpent += state.wavetime; - } - state.wavetime = 0; } @@ -198,9 +179,12 @@ public class Logic implements ApplicationListener{ } //if there's a "win" wave and no enemies are present, win automatically - if(state.rules.waves && state.enemies == 0 && state.rules.winWave > 0 && state.wave >= state.rules.winWave && !spawner.isSpawning()){ + if(state.rules.waves && (state.enemies == 0 && state.rules.winWave > 0 && state.wave >= state.rules.winWave && !spawner.isSpawning()) || + (state.rules.attackMode && state.rules.waveTeam.cores().isEmpty())){ //the sector has been conquered - waves get disabled state.rules.waves = false; + //disable attack mode + state.rules.attackMode = false; //fire capture event Events.fire(new SectorCaptureEvent(state.rules.sector)); @@ -215,19 +199,13 @@ public class Logic implements ApplicationListener{ state.gameOver = true; Events.fire(new GameOverEvent(state.rules.waveTeam)); }else if(state.rules.attackMode){ - Team alive = null; + //count # of teams alive + int countAlive = state.teams.getActive().count(TeamData::hasCore); - for(TeamData team : state.teams.getActive()){ - if(team.hasCore()){ - if(alive != null){ - return; - } - alive = team.team; - } - } - - if(alive != null && !state.gameOver){ - Events.fire(new GameOverEvent(alive)); + if((countAlive <= 1 || (!state.rules.pvp && state.rules.defaultTeam.core() == null)) && !state.gameOver){ + //find team that won + TeamData left = state.teams.getActive().find(TeamData::hasCore); + Events.fire(new GameOverEvent(left == null ? Team.derelict : left.team)); state.gameOver = true; } } @@ -262,6 +240,15 @@ public class Logic implements ApplicationListener{ netClient.setQuiet(); } + //called when the remote server researches something + @Remote + public static void researched(Content content){ + if(!(content instanceof UnlockableContent u)) return; + + state.rules.researched.add(u.name); + ui.hudfrag.showUnlock(u); + } + @Override public void dispose(){ //save the settings before quitting @@ -279,10 +266,12 @@ public class Logic implements ApplicationListener{ if(state.isGame()){ if(!net.client()){ - state.enemies = Groups.unit.count(u -> u.team() == state.rules.waveTeam && u.type().isCounted); + state.enemies = Groups.unit.count(u -> u.team() == state.rules.waveTeam && u.type.isCounted); } if(!state.isPaused()){ + state.teams.updateTeamStats(); + if(state.isCampaign()){ state.secinfo.update(); } diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index ae8c7d9a7c..3c6214fd85 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -194,14 +194,14 @@ public class NetClient implements ApplicationListener{ } //server console logging - Log.info("&y@: &lb@", player.name, message); + Log.info("&fi@: @", "&lc" + player.name, "&lw" + message); //invoke event for all clients but also locally //this is required so other clients get the correct name even if they don't know who's sending it yet Call.sendMessage(message, colorizeName(player.id(), player.name), player); }else{ //log command to console but with brackets - Log.info("<&y@: &lm@&lg>", player.name, message); + Log.info("<&fi@: @&fr>", "&lk" + player.name, "&lw" + message); //a command was sent, now get the output if(response.type != ResponseType.valid){ diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index f5a625fc32..00f0bc78e8 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -18,6 +18,7 @@ import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.game.Teams.*; import mindustry.gen.*; +import mindustry.graphics.*; import mindustry.net.*; import mindustry.net.Administration.*; import mindustry.net.Packets.*; @@ -249,8 +250,7 @@ public class NetServer implements ApplicationListener{ }catch(ValidateException e){ Log.debug("Validation failed for '@': @", e.player, e.getMessage()); }catch(RuntimeException e){ - if(e.getCause() instanceof ValidateException){ - ValidateException v = (ValidateException)e.getCause(); + if(e.getCause() instanceof ValidateException v){ Log.debug("Validation failed for '@': @", v.player, v.getMessage()); }else{ throw e; @@ -300,6 +300,15 @@ public class NetServer implements ApplicationListener{ } }); + clientCommands.register("a", "", "Send a message only to admins.", (args, player) -> { + if(!player.admin){ + player.sendMessage("[scarlet]You must be admin to use this command."); + return; + } + + Groups.player.each(Player::admin, a -> a.sendMessage(args[0], player, "[#" + Pal.adminChat.toString() + "]" + NetClient.colorizeName(player.id, player.name))); + }); + //duration of a a kick in seconds int kickDuration = 60 * 60; //voting round duration in seconds @@ -330,8 +339,8 @@ public class NetServer implements ApplicationListener{ votes += d; voted.addAll(player.uuid(), admins.getInfo(player.uuid()).lastIP); - Call.sendMessage(Strings.format("[lightgray]A player has voted on kicking[orange] @[].[accent] (@/@)\n[lightgray]Type[orange] /vote [] to agree.", - target.name, votes, votesRequired())); + Call.sendMessage(Strings.format("[lightgray]@[lightgray] has voted on kicking[orange] @[].[accent] (@/@)\n[lightgray]Type[orange] /vote [] to agree.", + player.name, target.name, votes, votesRequired())); checkPass(); } @@ -509,7 +518,8 @@ public class NetServer implements ApplicationListener{ Call.playerDisconnect(player.id()); } - if(Config.showConnectMessages.bool()) Log.info("&lm[@] &lc@ has disconnected. &lg&fi(@)", player.uuid(), player.name, reason); + String message = Strings.format("&lb@&fi&lk has disconnected. &fi&lk[&lb@&fi&lk] (@)", player.name, player.uuid(), reason); + if(Config.showConnectMessages.bool()) Log.info(message); } player.remove(); @@ -576,7 +586,7 @@ public class NetServer implements ApplicationListener{ shooting = false; } - if(!player.dead() && (player.unit().type().flying || !player.unit().type().canBoost)){ + if(!player.dead() && (player.unit().type.flying || !player.unit().type.canBoost)){ boosting = false; } @@ -630,7 +640,7 @@ public class NetServer implements ApplicationListener{ Unit unit = player.unit(); long elapsed = Time.timeSinceMillis(con.lastReceivedClientTime); - float maxSpeed = ((player.unit().type().canBoost && player.unit().isFlying()) ? player.unit().type().boostMultiplier : 1f) * player.unit().type().speed; + float maxSpeed = ((player.unit().type.canBoost && player.unit().isFlying()) ? player.unit().type.boostMultiplier : 1f) * player.unit().type.speed; if(unit.isGrounded()){ maxSpeed *= unit.floorSpeedMultiplier(); } @@ -737,7 +747,8 @@ public class NetServer implements ApplicationListener{ if(Config.showConnectMessages.bool()){ Call.sendMessage("[accent]" + player.name + "[accent] has connected."); - Log.info("&lm[@] &y@ has connected.", player.uuid(), player.name); + String message = Strings.format("&lb@&fi&lk has connected. &fi&lk[&lb@&fi&lk]", player.name, player.uuid()); + Log.info(message); } if(!Config.motd.string().equalsIgnoreCase("off")){ @@ -786,7 +797,7 @@ public class NetServer implements ApplicationListener{ public void openServer(){ try{ net.host(Config.port.num()); - info("&lcOpened a server on port @.", Config.port.num()); + info("Opened a server on port @.", Config.port.num()); }catch(BindException e){ Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network."); state.set(State.menu); diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 0e51d7f0f9..47b7500e10 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -63,7 +63,9 @@ public class Renderer implements ApplicationListener{ Color.white.set(1f, 1f, 1f, 1f); Gl.clear(Gl.stencilBufferBit); - camerascale = Mathf.lerpDelta(camerascale, targetscale, 0.1f); + float dest = Mathf.round(targetscale, 0.5f); + camerascale = Mathf.lerpDelta(camerascale, dest, 0.1f); + if(Mathf.within(camerascale, dest, 0.001f)) camerascale = dest; laserOpacity = Core.settings.getInt("lasersopacity") / 100f; if(landTime > 0){ @@ -303,6 +305,10 @@ public class Renderer implements ApplicationListener{ targetscale = Mathf.clamp(targetscale, minScale(), Math.round(s * 6)); } + public float getDisplayScale(){ + return camerascale; + } + public float minScale(){ return Scl.scl(1.5f); } diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 709b0bfb23..60beec266b 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -65,6 +65,11 @@ public class World{ return tile == null || tile.block().solid; } + public boolean wallSolidFull(int x, int y){ + Tile tile = tile(x, y); + return tile == null || (tile.block().solid && tile.block().fillsTile); + } + public boolean isAccessible(int x, int y){ return !wallSolid(x, y - 1) || !wallSolid(x, y + 1) || !wallSolid(x - 1, y) || !wallSolid(x + 1, y); } @@ -143,7 +148,17 @@ public class World{ return build(Math.round(x / tilesize), Math.round(y / tilesize)); } - public int toTile(float coord){ + /** Convert from world to logic tile coordinates. Whole numbers are at centers of tiles. */ + public static float conv(float coord){ + return coord / tilesize; + } + + /** Convert from tile to world coordinates. */ + public static float unconv(float coord){ + return coord * tilesize; + } + + public static int toTile(float coord){ return Math.round(coord / tilesize); } @@ -248,7 +263,7 @@ public class World{ setSectorRules(sector); if(state.rules.defaultTeam.core() != null){ - sector.setSpawnPosition(state.rules.defaultTeam.core().pos()); + sector.info.spawnPosition = state.rules.defaultTeam.core().pos(); } } @@ -262,8 +277,6 @@ public class World{ ObjectIntMap floorc = new ObjectIntMap<>(); ObjectSet content = new ObjectSet<>(); - float waterFloors = 0, totalFloors = 0; - for(Tile tile : world.tiles){ if(world.getDarkness(tile.x, tile.y) >= 3){ continue; @@ -275,10 +288,6 @@ public class World{ if(liquid != null) content.add(liquid); if(!tile.block().isStatic()){ - totalFloors ++; - if(liquid == Liquids.water){ - waterFloors += tile.floor().isDeep() ? 1f : 0.7f; - } floorc.increment(tile.floor()); if(tile.overlay() != Blocks.air){ floorc.increment(tile.overlay()); @@ -301,7 +310,7 @@ public class World{ //TODO bad code boolean hasSnow = floors[0].name.contains("ice") || floors[0].name.contains("snow"); - boolean hasRain = !hasSnow && floors[0].name.contains("water"); + boolean hasRain = !hasSnow && content.contains(Liquids.water) && !floors[0].name.contains("sand"); boolean hasDesert = !hasSnow && !hasRain && floors[0].name.contains("sand"); boolean hasSpores = floors[0].name.contains("spore") || floors[0].name.contains("moss") || floors[0].name.contains("tainted"); @@ -311,6 +320,7 @@ public class World{ if(hasRain){ state.rules.weather.add(new WeatherEntry(Weathers.rain)); + state.rules.weather.add(new WeatherEntry(Weathers.fog)); } if(hasDesert){ @@ -321,9 +331,9 @@ public class World{ state.rules.weather.add(new WeatherEntry(Weathers.sporestorm)); } - state.secinfo.resources = content.asArray(); - state.secinfo.resources.sort(Structs.comps(Structs.comparing(Content::getContentType), Structs.comparingInt(c -> c.id))); - + sector.info.resources = content.asArray(); + sector.info.resources.sort(Structs.comps(Structs.comparing(Content::getContentType), Structs.comparingInt(c -> c.id))); + sector.saveInfo(); } public Context filterContext(Map map){ diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java index 56e9c31146..cd2b6a21d5 100644 --- a/core/src/mindustry/ctype/UnlockableContent.java +++ b/core/src/mindustry/ctype/UnlockableContent.java @@ -10,11 +10,14 @@ import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.ui.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; /** Base interface for an unlockable content type. */ public abstract class UnlockableContent extends MappableContent{ + /** Stat storage for this content. Initialized on demand. */ + public Stats stats = new Stats(); /** Localized, formal name. Never null. Set to internal name if not found in bundle. */ public String localizedName; /** Localized description. May be null. */ @@ -22,7 +25,7 @@ public abstract class UnlockableContent extends MappableContent{ /** Whether this content is always unlocked in the tech tree. */ public boolean alwaysUnlocked = false; /** Icons by Cicon ID.*/ - protected TextureRegion[] cicons = new TextureRegion[mindustry.ui.Cicon.all.length]; + protected TextureRegion[] cicons = new TextureRegion[Cicon.all.length]; /** Unlock state. Loaded from settings. Do not modify outside of the constructor. */ protected boolean unlocked; @@ -38,6 +41,18 @@ public abstract class UnlockableContent extends MappableContent{ return minfo.mod == null ? description : description + "\n" + Core.bundle.format("mod.display", minfo.mod.meta.displayName()); } + /** Checks stat initialization state. Call before displaying stats. */ + public void checkStats(){ + if(!stats.intialized){ + setStats(); + stats.intialized = true; + } + } + + /** Intializes stats on demand. Should only be called once. Only called before something is displayed. */ + public void setStats(){ + } + /** Generate any special icons for this content. Called asynchronously.*/ @CallSuper public void createIcons(MultiPacker packer){ @@ -59,9 +74,11 @@ public abstract class UnlockableContent extends MappableContent{ cicons[icon.ordinal()] = Core.atlas.find(getContentType().name() + "-" + name + "-" + icon.name(), Core.atlas.find(getContentType().name() + "-" + name + "-full", + Core.atlas.find(name + "-" + icon.name(), + Core.atlas.find(name + "-full", Core.atlas.find(name, Core.atlas.find(getContentType().name() + "-" + name, - Core.atlas.find(name + "1"))))); + Core.atlas.find(name + "1"))))))); } return cicons[icon.ordinal()]; } @@ -73,7 +90,9 @@ public abstract class UnlockableContent extends MappableContent{ } /** This should show all necessary info about this content in the specified table. */ - public abstract void displayInfo(Table table); + public void display(Table table){ + + } /** Called when this content is unlocked. Use this to unlock other related content. */ public void onUnlock(){ @@ -95,16 +114,33 @@ public abstract class UnlockableContent extends MappableContent{ } } - public final boolean unlocked(){ + /** Unlocks this content, but does not fire any events. */ + public void quietUnlock(){ + if(!unlocked()){ + unlocked = true; + Core.settings.put(name + "-unlocked", true); + } + } + + public boolean unlocked(){ + if(net.client()) return state.rules.researched.contains(name); return unlocked || alwaysUnlocked; } - /** @return whether this content is unlocked, or the player is in a custom (non-campaign) game. */ - public final boolean unlockedNow(){ - return unlocked || alwaysUnlocked || !state.isCampaign(); + /** Locks this content again. */ + public void clearUnlock(){ + if(unlocked){ + unlocked = false; + Core.settings.put(name + "-unlocked", false); + } } - public final boolean locked(){ + /** @return whether this content is unlocked, or the player is in a custom (non-campaign) game. */ + public boolean unlockedNow(){ + return unlocked() || !state.isCampaign(); + } + + public boolean locked(){ return !unlocked(); } } diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index 3731cf3d99..f735bd790c 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -26,7 +26,7 @@ public class EditorTile extends Tile{ if(type instanceof OverlayFloor){ //don't place on liquids - if(!floor.isLiquid){ + if(floor.hasSurface() || !type.needsSurface){ setOverlayID(type.id); } return; @@ -75,7 +75,7 @@ public class EditorTile extends Tile{ return; } - if(floor.isLiquid) return; + if(!floor.hasSurface() && overlay.asFloor().needsSurface) return; if(overlay() == overlay) return; op(OpType.overlay, this.overlay.id); super.setOverlay(overlay); @@ -96,11 +96,18 @@ public class EditorTile extends Tile{ super.recache(); } } - + @Override - protected void changeEntity(Team team, Prov entityprov, int rotation){ + protected void changed(){ + if(state.isGame()){ + super.changed(); + } + } + + @Override + protected void changeBuild(Team team, Prov entityprov, int rotation){ if(skip()){ - super.changeEntity(team, entityprov, rotation); + super.changeBuild(team, entityprov, rotation); return; } diff --git a/core/src/mindustry/editor/EditorTool.java b/core/src/mindustry/editor/EditorTool.java index 2dff5e9f46..cd4b63935e 100644 --- a/core/src/mindustry/editor/EditorTool.java +++ b/core/src/mindustry/editor/EditorTool.java @@ -118,7 +118,7 @@ public enum EditorTool{ if(editor.drawBlock.isOverlay()){ Block dest = tile.overlay(); if(dest == editor.drawBlock) return; - tester = t -> t.overlay() == dest && !t.floor().isLiquid; + tester = t -> t.overlay() == dest && (t.floor().hasSurface() || !t.floor().needsSurface); setter = t -> t.setOverlay(editor.drawBlock); }else if(editor.drawBlock.isFloor()){ Block dest = tile.floor(); diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index 49d174779b..1c33964e08 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -4,6 +4,7 @@ import arc.files.*; import arc.func.*; import arc.graphics.*; import arc.math.*; +import arc.math.geom.*; import arc.struct.*; import mindustry.content.*; import mindustry.editor.DrawOperation.*; @@ -180,6 +181,52 @@ public class MapEditor{ return false; } + public void addCliffs(){ + for(Tile tile : world.tiles){ + if(!tile.block().isStatic() || tile.block() == Blocks.cliff) continue; + + int rotation = 0; + for(int i = 0; i < 8; i++){ + Tile other = world.tiles.get(tile.x + Geometry.d8[i].x, tile.y + Geometry.d8[i].y); + if(other != null && !other.block().isStatic()){ + rotation |= (1 << i); + } + } + + if(rotation != 0){ + tile.setBlock(Blocks.cliff); + } + + tile.data = (byte)rotation; + } + + for(Tile tile : world.tiles){ + if(tile.block() != Blocks.cliff && tile.block().isStatic()){ + tile.setBlock(Blocks.air); + } + } + } + + public void addFloorCliffs(){ + for(Tile tile : world.tiles){ + if(!tile.floor().hasSurface() || tile.block() == Blocks.cliff) continue; + + int rotation = 0; + for(int i = 0; i < 8; i++){ + Tile other = world.tiles.get(tile.x + Geometry.d8[i].x, tile.y + Geometry.d8[i].y); + if(other != null && !other.floor().hasSurface()){ + rotation |= (1 << i); + } + } + + if(rotation != 0){ + tile.setBlock(Blocks.cliff); + } + + tile.data = (byte)rotation; + } + } + public void drawCircle(int x, int y, Cons drawer){ for(int rx = -brushSize; rx <= brushSize; rx++){ for(int ry = -brushSize; ry <= brushSize; ry++){ diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 6ff8546b19..dfb49099ec 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -258,6 +258,11 @@ public class MapEditorDialog extends Dialog implements Disposable{ Groups.unit.clear(); Groups.build.clear(); logic.play(); + + if(player.team().core() == null){ + player.set(world.width() * tilesize/2f, world.height() * tilesize/2f); + player.unit(UnitTypes.alpha.spawn(player.team(), player.x, player.y)); + } }); } @@ -385,7 +390,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ } public void build(){ - float size = 60f; + float size = 58f; clearChildren(); table(cont -> { @@ -557,6 +562,21 @@ public class MapEditorDialog extends Dialog implements Disposable{ t.add(slider).width(size * 3f - 20).padTop(4f); }).padTop(5).growX().top(); + mid.row(); + + if(!mobile){ + mid.table(t -> { + t.button("@editor.center", Icon.move, Styles.cleart, view::center).growX().margin(9f); + }).growX().top(); + } + + if(addCliffButton){ + mid.row(); + + mid.table(t -> { + t.button("Cliffs", Icon.terrain, Styles.cleart, editor::addCliffs).growX().margin(9f); + }).growX().top(); + } }).margin(0).left().growY(); diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index a4a4c0c181..34275afcd1 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -29,7 +29,8 @@ public class MapGenerateDialog extends BaseDialog{ private final Prov[] filterTypes = new Prov[]{ NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new, RiverNoiseFilter::new, OreFilter::new, OreMedianFilter::new, MedianFilter::new, - BlendFilter::new, MirrorFilter::new, ClearFilter::new, CoreSpawnFilter::new, EnemySpawnFilter::new + BlendFilter::new, MirrorFilter::new, ClearFilter::new, CoreSpawnFilter::new, + EnemySpawnFilter::new, SpawnPathFilter::new }; private final MapEditor editor; private final boolean applied; @@ -44,14 +45,13 @@ public class MapGenerateDialog extends BaseDialog{ private AsyncExecutor executor = new AsyncExecutor(1); private AsyncResult result; boolean generating; - private GenTile returnTile = new GenTile(); - private GenTile[][] buffer1, buffer2; + private long[] buffer1, buffer2; private Cons> applier; CachedTile ctile = new CachedTile(){ //nothing. @Override - protected void changeEntity(Team team, Prov entityprov, int rotation){ + protected void changeBuild(Team team, Prov entityprov, int rotation){ } }; @@ -65,7 +65,7 @@ public class MapGenerateDialog extends BaseDialog{ shown(this::setup); addCloseButton(); if(applied){ - buttons.button("@editor.apply", () -> { + buttons.button("@editor.apply", Icon.ok, () -> { ui.loadAnd(() -> { apply(); hide(); @@ -78,14 +78,14 @@ public class MapGenerateDialog extends BaseDialog{ update(); }).size(160f, 64f); } - buttons.button("@editor.randomize", () -> { + buttons.button("@editor.randomize", Icon.refresh, () -> { for(GenerateFilter filter : filters){ filter.randomize(); } update(); }).size(160f, 64f); - buttons.button("@add", Icon.add, this::showAdd).height(64f).width(140f); + buttons.button("@add", Icon.add, this::showAdd).height(64f).width(150f); if(!applied){ hidden(this::apply); @@ -107,38 +107,36 @@ public class MapGenerateDialog extends BaseDialog{ /** Applies the specified filters to the editor. */ public void applyToEditor(Seq filters){ //writeback buffer - GenTile[][] writeTiles = new GenTile[editor.width()][editor.height()]; - - for(int x = 0; x < editor.width(); x++){ - for(int y = 0; y < editor.height(); y++){ - writeTiles[x][y] = new GenTile(); - } - } + long[] writeTiles = new long[editor.width() * editor.height()]; for(GenerateFilter filter : filters){ input.begin(filter, editor.width(), editor.height(), editor::tile); + //write to buffer for(int x = 0; x < editor.width(); x++){ for(int y = 0; y < editor.height(); y++){ Tile tile = editor.tile(x, y); - input.apply(x, y, tile.floor(), tile.block(), tile.overlay()); + input.apply(x, y, tile.block(), tile.floor(), tile.overlay()); filter.apply(input); - writeTiles[x][y].set(input.floor, input.block, input.ore, tile.team()); + writeTiles[x + y*world.width()] = PackTile.get(input.block.id, input.floor.id, input.overlay.id); } } editor.load(() -> { //read from buffer back into tiles - for(int x = 0; x < editor.width(); x++){ - for(int y = 0; y < editor.height(); y++){ - Tile tile = editor.tile(x, y); - GenTile write = writeTiles[x][y]; + for(int i = 0; i < editor.width() * editor.height(); i++){ + Tile tile = world.tiles.geti(i); + long write = writeTiles[i]; - tile.setFloor((Floor)content.block(write.floor)); - tile.setBlock(content.block(write.block)); - tile.setTeam(Team.get(write.team)); - tile.setOverlay(content.block(write.ore)); + Block block = content.block(PackTile.block(write)), floor = content.block(PackTile.floor(write)), overlay = content.block(PackTile.overlay(write)); + + //don't mess up synthetic stuff. + if(!tile.synthetic() && !block.synthetic()){ + tile.setBlock(block); } + + tile.setFloor((Floor)floor); + tile.setOverlay(overlay); } }); } @@ -201,15 +199,8 @@ public class MapGenerateDialog extends BaseDialog{ rebuildFilters(); } - GenTile[][] create(){ - GenTile[][] out = new GenTile[editor.width() / scaling][editor.height() / scaling]; - - for(int x = 0; x < out.length; x++){ - for(int y = 0; y < out[0].length; y++){ - out[x][y] = new GenTile(); - } - } - return out; + long[] create(){ + return new long[(editor.width() / scaling) * (editor.height() / scaling)]; } void rebuildFilters(){ @@ -295,7 +286,7 @@ public class MapGenerateDialog extends BaseDialog{ for(Prov gen : filterTypes){ GenerateFilter filter = gen.get(); - if((!applied && filter.isBuffered()) || (filter.isPost() && applied)) continue; + if((filter.isPost() && applied)) continue; selection.cont.button(filter.name(), () -> { filters.add(filter); @@ -317,9 +308,15 @@ public class MapGenerateDialog extends BaseDialog{ selection.show(); } - GenTile dset(Tile tile){ - returnTile.set(tile); - return returnTile; + long pack(Tile tile){ + return PackTile.get(tile.blockID(), tile.floorID(), tile.overlayID()); + } + + Tile unpack(long tile){ + ctile.setFloor((Floor)content.block(PackTile.floor(tile))); + ctile.setBlock(content.block(PackTile.block(tile))); + ctile.setOverlay(content.block(PackTile.overlay(tile))); + return ctile; } void apply(){ @@ -350,6 +347,7 @@ public class MapGenerateDialog extends BaseDialog{ result = executor.submit(() -> { try{ + int w = pixmap.getWidth(); world.setGenerating(true); generating = true; @@ -357,24 +355,24 @@ public class MapGenerateDialog extends BaseDialog{ //write to buffer1 for reading for(int px = 0; px < pixmap.getWidth(); px++){ for(int py = 0; py < pixmap.getHeight(); py++){ - buffer1[px][py].set(editor.tile(px * scaling, py * scaling)); + buffer1[px + py*w] = pack(editor.tile(px * scaling, py * scaling)); } } } for(GenerateFilter filter : copy){ - input.begin(filter, editor.width(), editor.height(), (x, y) -> buffer1[Mathf.clamp(x / scaling, 0, pixmap.getWidth()-1)][Mathf.clamp(y / scaling, 0, pixmap.getHeight()-1)].tile()); + input.begin(filter, editor.width(), editor.height(), (x, y) -> unpack(buffer1[Mathf.clamp(x / scaling, 0, pixmap.getWidth()-1) + w* Mathf.clamp(y / scaling, 0, pixmap.getHeight()-1)])); //read from buffer1 and write to buffer2 pixmap.each((px, py) -> { int x = px * scaling, y = py * scaling; - GenTile tile = buffer1[px][py]; - input.apply(x, y, content.block(tile.floor), content.block(tile.block), content.block(tile.ore)); + long tile = buffer1[px + py * w]; + input.apply(x, y, content.block(PackTile.block(tile)), content.block(PackTile.floor(tile)), content.block(PackTile.overlay(tile))); filter.apply(input); - buffer2[px][py].set(input.floor, input.block, input.ore, Team.get(tile.team)); + buffer2[px + py * w] = PackTile.get(input.block.id, input.floor.id, input.overlay.id); }); - pixmap.each((px, py) -> buffer1[px][py].set(buffer2[px][py])); + pixmap.each((px, py) -> buffer1[px + py*w] = buffer2[px + py*w]); } for(int px = 0; px < pixmap.getWidth(); px++){ @@ -383,10 +381,10 @@ public class MapGenerateDialog extends BaseDialog{ //get result from buffer1 if there's filters left, otherwise get from editor directly if(filters.isEmpty()){ Tile tile = editor.tile(px * scaling, py * scaling); - color = MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), Team.derelict); + color = MapIO.colorFor(tile.block(), tile.floor(), tile.overlay(), Team.derelict); }else{ - GenTile tile = buffer1[px][py]; - color = MapIO.colorFor(content.block(tile.floor), content.block(tile.block), content.block(tile.ore), Team.derelict); + long tile = buffer1[px + py*w]; + color = MapIO.colorFor(content.block(PackTile.block(tile)), content.block(PackTile.floor(tile)), content.block(PackTile.overlay(tile)), Team.derelict); } pixmap.draw(px, pixmap.getHeight() - 1 - py, color); } @@ -406,39 +404,4 @@ public class MapGenerateDialog extends BaseDialog{ world.setGenerating(false); }); } - - private class GenTile{ - public byte team; - public short block, floor, ore; - - GenTile(){ - } - - public void set(Block floor, Block wall, Block ore, Team team){ - this.floor = floor.id; - this.block = wall.id; - this.ore = floor.asFloor().isLiquid ? 0 : ore.id; - this.team = (byte)team.id; - } - - public void set(GenTile other){ - this.floor = other.floor; - this.block = other.block; - this.ore = other.ore; - this.team = other.team; - } - - public GenTile set(Tile other){ - set(other.floor(), other.block(), other.overlay(), other.team()); - return this; - } - - Tile tile(){ - ctile.setFloor((Floor)content.block(floor)); - ctile.setBlock(content.block(block)); - ctile.setOverlay(content.block(ore)); - ctile.setTeam(Team.get(team)); - return ctile; - } - } } diff --git a/core/src/mindustry/editor/MapView.java b/core/src/mindustry/editor/MapView.java index 7ee088eec5..a54c0f49b8 100644 --- a/core/src/mindustry/editor/MapView.java +++ b/core/src/mindustry/editor/MapView.java @@ -171,6 +171,10 @@ public class MapView extends Element implements GestureListener{ this.grid = grid; } + public void center(){ + offsetx = offsety = 0; + } + @Override public void act(float delta){ super.act(delta); diff --git a/core/src/mindustry/editor/WaveGraph.java b/core/src/mindustry/editor/WaveGraph.java index 14b2416085..2436c62c2a 100644 --- a/core/src/mindustry/editor/WaveGraph.java +++ b/core/src/mindustry/editor/WaveGraph.java @@ -154,7 +154,7 @@ public class WaveGraph extends Table{ int sum = 0; for(SpawnGroup spawn : groups){ - int spawned = spawn.getUnitsSpawned(i); + int spawned = spawn.getSpawned(i); values[index][spawn.type.id] += spawned; if(spawned > 0){ used.add(spawn.type); diff --git a/core/src/mindustry/editor/WaveInfoDialog.java b/core/src/mindustry/editor/WaveInfoDialog.java index d5b957e143..ae5f985766 100644 --- a/core/src/mindustry/editor/WaveInfoDialog.java +++ b/core/src/mindustry/editor/WaveInfoDialog.java @@ -159,7 +159,7 @@ public class WaveInfoDialog extends BaseDialog{ t.margin(0).defaults().pad(3).padLeft(5f).growX().left(); t.button(b -> { b.left(); - b.image(group.type.icon(mindustry.ui.Cicon.medium)).size(32f).padRight(3); + b.image(group.type.icon(Cicon.medium)).size(32f).padRight(3).scaling(Scaling.fit); b.add(group.type.localizedName).color(Pal.accent); b.add().growX(); @@ -262,7 +262,7 @@ public class WaveInfoDialog extends BaseDialog{ if(type.isHidden()) continue; p.button(t -> { t.left(); - t.image(type.icon(Cicon.medium)).size(40f).padRight(2f); + t.image(type.icon(Cicon.medium)).size(8 * 4).scaling(Scaling.fit).padRight(2f); t.add(type.localizedName); }, () -> { lastType = type; diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index e22891eba5..b6c9abe807 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -9,6 +9,7 @@ import arc.struct.*; import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.gen.*; @@ -82,7 +83,7 @@ public class Damage{ furthest = null; - boolean found = world.raycast(b.tileX(), b.tileY(), world.toTile(b.x + Tmp.v1.x), world.toTile(b.y + Tmp.v1.y), + boolean found = world.raycast(b.tileX(), b.tileY(), World.toTile(b.x + Tmp.v1.x), World.toTile(b.y + Tmp.v1.y), (x, y) -> (furthest = world.tile(x, y)) != null && furthest.team() != b.team && furthest.block().absorbLasers); return found && furthest != null ? Math.max(6f, b.dst(furthest.worldx(), furthest.worldy())) : length; diff --git a/core/src/mindustry/entities/Effect.java b/core/src/mindustry/entities/Effect.java index 9d17cfcfc5..920729e608 100644 --- a/core/src/mindustry/entities/Effect.java +++ b/core/src/mindustry/entities/Effect.java @@ -146,7 +146,7 @@ public class Effect{ if(headless || region == null || !Core.atlas.isFound(region)) return; Tile tile = world.tileWorld(x, y); - if(tile == null || tile.floor().isLiquid) return; + if(tile == null || !tile.floor().hasSurface()) return; Decal decal = Decal.create(); decal.set(x, y); diff --git a/core/src/mindustry/entities/EntityCollisions.java b/core/src/mindustry/entities/EntityCollisions.java index 2d8402e92c..b4139991a4 100644 --- a/core/src/mindustry/entities/EntityCollisions.java +++ b/core/src/mindustry/entities/EntityCollisions.java @@ -127,7 +127,7 @@ public class EntityCollisions{ public static boolean legsSolid(int x, int y){ Tile tile = world.tile(x, y); - return tile == null || tile.staticDarkness() >= 2; + return tile == null || tile.staticDarkness() >= 2 || tile.floor().solid; } public static boolean waterSolid(int x, int y){ diff --git a/core/src/mindustry/entities/EntityGroup.java b/core/src/mindustry/entities/EntityGroup.java index bec27847c4..2135d9d6aa 100644 --- a/core/src/mindustry/entities/EntityGroup.java +++ b/core/src/mindustry/entities/EntityGroup.java @@ -57,8 +57,9 @@ public class EntityGroup implements Iterable{ each(Entityc::update); } - public void copy(Seq arr){ + public Seq copy(Seq arr){ arr.addAll(array); + return arr; } public void each(Cons cons){ diff --git a/core/src/mindustry/entities/Fires.java b/core/src/mindustry/entities/Fires.java index 2906b4e7d7..754a8766b9 100644 --- a/core/src/mindustry/entities/Fires.java +++ b/core/src/mindustry/entities/Fires.java @@ -23,14 +23,14 @@ public class Fires{ if(fire == null){ fire = Fire.create(); - fire.tile(tile); - fire.lifetime(baseLifetime); + fire.tile = tile; + fire.lifetime = baseLifetime; fire.set(tile.worldx(), tile.worldy()); fire.add(); map.put(tile.pos(), fire); }else{ - fire.lifetime(baseLifetime); - fire.time(0f); + fire.lifetime = baseLifetime; + fire.time = 0f; } } diff --git a/core/src/mindustry/entities/Lightning.java b/core/src/mindustry/entities/Lightning.java index 738bfa1f1e..2d647bfb1e 100644 --- a/core/src/mindustry/entities/Lightning.java +++ b/core/src/mindustry/entities/Lightning.java @@ -5,6 +5,7 @@ import arc.math.*; import arc.math.geom.*; import arc.struct.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.entities.bullet.*; import mindustry.game.*; import mindustry.gen.*; @@ -48,7 +49,7 @@ public class Lightning{ bhit = false; Vec2 from = lines.get(lines.size - 2); Vec2 to = lines.get(lines.size - 1); - world.raycastEach(world.toTile(from.getX()), world.toTile(from.getY()), world.toTile(to.getX()), world.toTile(to.getY()), (wx, wy) -> { + world.raycastEach(World.toTile(from.getX()), World.toTile(from.getY()), World.toTile(to.getX()), World.toTile(to.getY()), (wx, wy) -> { Tile tile = world.tile(wx, wy); if(tile != null && tile.block().insulated){ diff --git a/core/src/mindustry/entities/Puddles.java b/core/src/mindustry/entities/Puddles.java index 461e486001..0abdae4928 100644 --- a/core/src/mindustry/entities/Puddles.java +++ b/core/src/mindustry/entities/Puddles.java @@ -45,6 +45,10 @@ public class Puddles{ return; } + if(tile.floor().solid){ + return; + } + Puddle p = map.get(tile.pos()); if(p == null){ Puddle puddle = Puddle.create(); diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 85761795e5..e4591a0ed0 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -3,9 +3,11 @@ package mindustry.entities; import arc.*; import arc.func.*; import arc.math.geom.*; +import arc.struct.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; @@ -65,7 +67,7 @@ public class Units{ /** @return whether a new instance of a unit of this team can be created. */ public static boolean canCreate(Team team, UnitType type){ - return teamIndex.countType(team, type) < getCap(team); + return team.data().countType(type) < getCap(team); } public static int getCap(Team team){ @@ -124,7 +126,7 @@ public class Units{ nearby(x, y, width, height, unit -> { if(boolResult) return; - if((unit.isGrounded() && !unit.type().hovering) == ground){ + if((unit.isGrounded() && !unit.type.hovering) == ground){ unit.hitbox(hitrect); if(hitrect.overlaps(x, y, width, height)){ @@ -284,7 +286,7 @@ public class Units{ /** Iterates over all units in a rectangle. */ public static void nearby(Team team, float x, float y, float width, float height, Cons cons){ - teamIndex.tree(team).intersect(x, y, width, height, cons); + team.data().tree().intersect(x, y, width, height, cons); } /** Iterates over all units in a circle around this position. */ @@ -308,20 +310,12 @@ public class Units{ /** Iterates over all units that are enemies of this team. */ public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons cons){ - if(team.active()){ - for(Team enemy : state.teams.enemiesOf(team)){ - nearby(enemy, x, y, width, height, cons); - } - }else{ - //inactive teams have no cache, check everything - //TODO cache all teams with units OR blocks - for(Team other : Team.all){ - if(other != team && teamIndex.count(other) > 0){ - nearby(other, x, y, width, height, cons); - } + Seq data = state.teams.present; + for(int i = 0; i < data.size; i++){ + if(data.items[i].team != team){ + nearby(data.items[i].team, x, y, width, height, cons); } } - } /** Iterates over all units that are enemies of this team. */ diff --git a/core/src/mindustry/entities/abilities/Ability.java b/core/src/mindustry/entities/abilities/Ability.java index 466bfc1980..cb6e94547b 100644 --- a/core/src/mindustry/entities/abilities/Ability.java +++ b/core/src/mindustry/entities/abilities/Ability.java @@ -1,5 +1,6 @@ package mindustry.entities.abilities; +import arc.*; import mindustry.gen.*; public abstract class Ability implements Cloneable{ @@ -14,4 +15,9 @@ public abstract class Ability implements Cloneable{ throw new RuntimeException("java sucks", e); } } + + /** @return localized ability name; mods should override this. */ + public String localized(){ + return Core.bundle.get("ability." + getClass().getSimpleName().replace("Ability", "").toLowerCase()); + } } diff --git a/core/src/mindustry/entities/abilities/ForceFieldAbility.java b/core/src/mindustry/entities/abilities/ForceFieldAbility.java index fa9fa5e2c8..d341191a74 100644 --- a/core/src/mindustry/entities/abilities/ForceFieldAbility.java +++ b/core/src/mindustry/entities/abilities/ForceFieldAbility.java @@ -94,7 +94,7 @@ public class ForceFieldAbility extends Ability{ } } - private void checkRadius(Unit unit){ + public void checkRadius(Unit unit){ //timer2 is used to store radius scale as an effect realRad = radiusScale * radius; } diff --git a/core/src/mindustry/entities/abilities/HealFieldAbility.java b/core/src/mindustry/entities/abilities/RepairFieldAbility.java similarity index 86% rename from core/src/mindustry/entities/abilities/HealFieldAbility.java rename to core/src/mindustry/entities/abilities/RepairFieldAbility.java index 90f800ec84..8df0a96e2c 100644 --- a/core/src/mindustry/entities/abilities/HealFieldAbility.java +++ b/core/src/mindustry/entities/abilities/RepairFieldAbility.java @@ -5,7 +5,7 @@ import mindustry.content.*; import mindustry.entities.*; import mindustry.gen.*; -public class HealFieldAbility extends Ability{ +public class RepairFieldAbility extends Ability{ public float amount = 1, reload = 100, range = 60; public Effect healEffect = Fx.heal; public Effect activeEffect = Fx.healWaveDynamic; @@ -13,9 +13,9 @@ public class HealFieldAbility extends Ability{ protected float timer; protected boolean wasHealed = false; - HealFieldAbility(){} + RepairFieldAbility(){} - public HealFieldAbility(float amount, float reload, float range){ + public RepairFieldAbility(float amount, float reload, float range){ this.amount = amount; this.reload = reload; this.range = range; diff --git a/core/src/mindustry/entities/abilities/ShieldFieldAbility.java b/core/src/mindustry/entities/abilities/ShieldRegenFieldAbility.java similarity index 86% rename from core/src/mindustry/entities/abilities/ShieldFieldAbility.java rename to core/src/mindustry/entities/abilities/ShieldRegenFieldAbility.java index 739751f6c1..8af8d2390a 100644 --- a/core/src/mindustry/entities/abilities/ShieldFieldAbility.java +++ b/core/src/mindustry/entities/abilities/ShieldRegenFieldAbility.java @@ -5,7 +5,7 @@ import mindustry.content.*; import mindustry.entities.*; import mindustry.gen.*; -public class ShieldFieldAbility extends Ability{ +public class ShieldRegenFieldAbility extends Ability{ public float amount = 1, max = 100f, reload = 100, range = 60; public Effect applyEffect = Fx.shieldApply; public Effect activeEffect = Fx.shieldWave; @@ -13,9 +13,9 @@ public class ShieldFieldAbility extends Ability{ protected float timer; protected boolean applied = false; - ShieldFieldAbility(){} + ShieldRegenFieldAbility(){} - public ShieldFieldAbility(float amount, float max, float reload, float range){ + public ShieldRegenFieldAbility(float amount, float max, float reload, float range){ this.amount = amount; this.max = max; this.reload = reload; diff --git a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java index 74140114d9..95eb3bcf5b 100644 --- a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java +++ b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java @@ -1,5 +1,6 @@ package mindustry.entities.abilities; +import arc.*; import arc.graphics.g2d.*; import arc.math.*; import arc.util.*; @@ -56,4 +57,9 @@ public class UnitSpawnAbility extends Ability{ }); } } + + @Override + public String localized(){ + return Core.bundle.format("ability.unitspawn", type.localizedName); + } } diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index 238a09f75c..8e06cf466e 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -13,6 +13,7 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.*; import static mindustry.Vars.*; @@ -24,6 +25,7 @@ public abstract class BulletType extends Content{ public float drawSize = 40f; public float drag = 0f; public boolean pierce, pierceBuilding; + public int pierceCap = -1; public Effect hitEffect, despawnEffect; /** Effect created when shooting. */ @@ -77,6 +79,8 @@ public abstract class BulletType extends Content{ public boolean backMove = true; /** Bullet range override. */ public float range = -1f; + /** Heal Bullet Percent **/ + public float healPercent = 0f; //additional effects @@ -100,6 +104,8 @@ public abstract class BulletType extends Content{ public float incendChance = 1f; public float homingPower = 0f; public float homingRange = 50f; + /** Use a negative value to disable homing delay. */ + public float homingDelay = -1f; public Color lightningColor = Pal.surge; public int lightning; @@ -133,17 +139,34 @@ public abstract class BulletType extends Content{ this(1f, 1f); } + /** @return estimated damage per shot. this can be very inaccurate. */ + public float estimateDPS(){ + float sum = damage + splashDamage*0.75f; + if(fragBullet != null && fragBullet != this){ + sum += fragBullet.estimateDPS() * fragBullets / 2f; + } + return sum; + } + /** Returns maximum distance the bullet this bullet type has can travel. */ public float range(){ return Math.max(speed * lifetime * (1f - drag), range); } public boolean collides(Bullet bullet, Building tile){ - return true; + return healPercent <= 0.001f || tile.team != bullet.team || tile.healthf() < 1f; } public void hitTile(Bullet b, Building tile, float initialHealth){ + if(status == StatusEffects.burning) { + Fires.create(tile.tile); + } hit(b); + + if(healPercent > 0f && tile.team == b.team && !(tile.block instanceof ConstructBlock)){ + Fx.healBlockFull.at(tile.x, tile.y, tile.block.size, Pal.heal); + tile.heal(healPercent / 100f * tile.maxHealth()); + } } public void hitEntity(Bullet b, Hitboxc other, float initialHealth){ @@ -185,6 +208,19 @@ public abstract class BulletType extends Content{ if(status != StatusEffects.none){ Damage.status(b.team, x, y, splashDamageRadius, status, statusDuration, collidesAir, collidesGround); } + + if(healPercent > 0f) { + indexer.eachBlock(b.team, x, y, splashDamageRadius, other -> other.damaged(), other -> { + Fx.healBlockFull.at(other.x, other.y, other.block.size, Pal.heal); + other.heal(healPercent / 100f * other.maxHealth()); + }); + } + + if(status == StatusEffects.burning) { + indexer.eachBlock(null, x, y, splashDamageRadius, other -> other.team != b.team, other -> { + Fires.create(other.tile); + }); + } } for(int i = 0; i < lightning; i++){ @@ -211,6 +247,11 @@ public abstract class BulletType extends Content{ } public void init(Bullet b){ + if(pierceCap >= 1) { + pierce = true; + //pierceBuilding is not enabled by default, because a bullet may want to *not* pierce buildings + } + if(killShooter && b.owner() instanceof Healthc){ ((Healthc)b.owner()).kill(); } @@ -221,7 +262,7 @@ public abstract class BulletType extends Content{ } public void update(Bullet b){ - if(homingPower > 0.0001f){ + if(homingPower > 0.0001f && b.time >= homingDelay){ Teamc target = Units.closestTarget(b.team, b.x, b.y, homingRange, e -> (e.isGrounded() && collidesGround) || (e.isFlying() && collidesAir), t -> collidesGround); if(target != null){ b.vel.setAngle(Mathf.slerpDelta(b.rotation(), b.angleTo(target), homingPower)); @@ -287,7 +328,7 @@ public abstract class BulletType extends Content{ bullet.data = data; bullet.drag = drag; bullet.hitSize = hitSize; - bullet.damage = damage < 0 ? this.damage : damage; + bullet.damage = (damage < 0 ? this.damage : damage) * bullet.damageMultiplier(); bullet.add(); if(keepVelocity && owner instanceof Velc) bullet.vel.add(((Velc)owner).vel().x, ((Velc)owner).vel().y); diff --git a/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java b/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java index a862671040..4c52105b26 100644 --- a/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java +++ b/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java @@ -44,6 +44,12 @@ public class ContinuousLaserBulletType extends BulletType{ this(0); } + @Override + public float estimateDPS(){ + //assume firing duration is about 100 by default, may not be accurate there's no way of knowing in this method + return damage * 100f / 5f; + } + @Override public float range(){ return length; diff --git a/core/src/mindustry/entities/bullet/HealBulletType.java b/core/src/mindustry/entities/bullet/HealBulletType.java deleted file mode 100644 index b811790000..0000000000 --- a/core/src/mindustry/entities/bullet/HealBulletType.java +++ /dev/null @@ -1,55 +0,0 @@ -package mindustry.entities.bullet; - -import arc.graphics.*; -import arc.graphics.g2d.*; -import mindustry.content.*; -import mindustry.gen.*; -import mindustry.graphics.*; -import mindustry.world.blocks.*; - -public class HealBulletType extends BulletType{ - protected float healPercent = 3f; - protected float height = 7f, width = 2f; - protected Color backColor = Pal.heal, frontColor = Color.white; - - public HealBulletType(float speed, float damage){ - super(speed, damage); - - shootEffect = Fx.shootHeal; - smokeEffect = Fx.hitLaser; - hitEffect = Fx.hitLaser; - despawnEffect = Fx.hitLaser; - collidesTeam = true; - hittable = false; - reflectable = false; - } - - public HealBulletType(){ - this(1f, 1f); - } - - @Override - public boolean collides(Bullet b, Building tile){ - return tile.team != b.team || tile.healthf() < 1f; - } - - @Override - public void draw(Bullet b){ - Draw.color(backColor); - Lines.stroke(width); - Lines.lineAngleCenter(b.x, b.y, b.rotation(), height); - Draw.color(frontColor); - Lines.lineAngleCenter(b.x, b.y, b.rotation(), height / 2f); - Draw.reset(); - } - - @Override - public void hitTile(Bullet b, Building tile, float initialHealth){ - super.hit(b); - - if(tile.team == b.team && !(tile.block instanceof ConstructBlock)){ - Fx.healBlockFull.at(tile.x, tile.y, tile.block.size, Pal.heal); - tile.heal(healPercent / 100f * tile.maxHealth()); - } - } -} diff --git a/core/src/mindustry/entities/bullet/LaserBoltBulletType.java b/core/src/mindustry/entities/bullet/LaserBoltBulletType.java new file mode 100644 index 0000000000..bd1332443f --- /dev/null +++ b/core/src/mindustry/entities/bullet/LaserBoltBulletType.java @@ -0,0 +1,34 @@ +package mindustry.entities.bullet; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import mindustry.gen.*; +import mindustry.content.*; + +public class LaserBoltBulletType extends BasicBulletType{ + protected float height = 7f, width = 2f; + + public LaserBoltBulletType(float speed, float damage){ + super(speed, damage); + + smokeEffect = Fx.hitLaser; + hitEffect = Fx.hitLaser; + despawnEffect = Fx.hitLaser; + hittable = false; + reflectable = false; + } + + public LaserBoltBulletType(){ + this(1f, 1f); + } + + @Override + public void draw(Bullet b){ + Draw.color(backColor); + Lines.stroke(width); + Lines.lineAngleCenter(b.x, b.y, b.rotation(), height); + Draw.color(frontColor); + Lines.lineAngleCenter(b.x, b.y, b.rotation(), height / 2f); + Draw.reset(); + } +} diff --git a/core/src/mindustry/entities/bullet/LaserBulletType.java b/core/src/mindustry/entities/bullet/LaserBulletType.java index ad5965f3b8..6d43baf95c 100644 --- a/core/src/mindustry/entities/bullet/LaserBulletType.java +++ b/core/src/mindustry/entities/bullet/LaserBulletType.java @@ -39,6 +39,11 @@ public class LaserBulletType extends BulletType{ this(1f); } + @Override + public float estimateDPS(){ + return super.estimateDPS() * 2f; + } + @Override public void init(){ super.init(); diff --git a/core/src/mindustry/entities/bullet/LiquidBulletType.java b/core/src/mindustry/entities/bullet/LiquidBulletType.java index 2d3de79977..5da33f95e0 100644 --- a/core/src/mindustry/entities/bullet/LiquidBulletType.java +++ b/core/src/mindustry/entities/bullet/LiquidBulletType.java @@ -22,6 +22,8 @@ public class LiquidBulletType extends BulletType{ if(liquid != null){ this.liquid = liquid; this.status = liquid.effect; + lightColor = liquid.lightColor; + lightOpacity = liquid.lightColor.a; } ammoMultiplier = 1f; diff --git a/core/src/mindustry/entities/bullet/MassDriverBolt.java b/core/src/mindustry/entities/bullet/MassDriverBolt.java index 42135a2db4..91dae839a8 100644 --- a/core/src/mindustry/entities/bullet/MassDriverBolt.java +++ b/core/src/mindustry/entities/bullet/MassDriverBolt.java @@ -36,15 +36,13 @@ public class MassDriverBolt extends BulletType{ @Override public void update(Bullet b){ //data MUST be an instance of DriverBulletData - if(!(b.data() instanceof DriverBulletData)){ + if(!(b.data() instanceof DriverBulletData data)){ hit(b); return; } float hitDst = 7f; - DriverBulletData data = (DriverBulletData)b.data(); - //if the target is dead, just keep flying until the bullet explodes if(data.to.dead()){ return; @@ -83,9 +81,7 @@ public class MassDriverBolt extends BulletType{ public void despawned(Bullet b){ super.despawned(b); - if(!(b.data() instanceof DriverBulletData)) return; - - DriverBulletData data = (DriverBulletData)b.data(); + if(!(b.data() instanceof DriverBulletData data)) return; for(int i = 0; i < data.items.length; i++){ int amountDropped = Mathf.random(0, data.items[i]); diff --git a/core/src/mindustry/entities/bullet/SapBulletType.java b/core/src/mindustry/entities/bullet/SapBulletType.java index 549485c3e2..5eb1d1e294 100644 --- a/core/src/mindustry/entities/bullet/SapBulletType.java +++ b/core/src/mindustry/entities/bullet/SapBulletType.java @@ -29,8 +29,7 @@ public class SapBulletType extends BulletType{ @Override public void draw(Bullet b){ - if(b.data instanceof Position){ - Position data = (Position)b.data; + if(b.data instanceof Position data){ Tmp.v1.set(data).lerp(b, b.fin()); Draw.color(color); @@ -68,13 +67,11 @@ public class SapBulletType extends BulletType{ } } - if(target instanceof Hitboxc){ - Hitboxc hit = (Hitboxc)target; + if(target instanceof Hitboxc hit){ hit.collision(b, hit.x(), hit.y()); b.collision(hit, hit.x(), hit.y()); - }else if(target instanceof Building){ - Building tile = (Building)target; + }else if(target instanceof Building tile){ if(tile.collide(b)){ tile.collision(b); diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index ccc83e87d8..0ef4d8bed0 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -116,7 +116,6 @@ abstract class BuilderComp implements Unitc{ current.progress = entity.progress; } - /** Draw all current build requests. Does not draw the beam effect, only the positions. */ void drawBuildRequests(){ @@ -208,7 +207,8 @@ abstract class BuilderComp implements Unitc{ BuildPlan plan = buildPlan(); Tile tile = world.tile(plan.x, plan.y); - if(dst(tile) > buildingRange && !state.isEditor()){ + + if(tile == null || (!within(tile, buildingRange) && !state.isEditor())){ return; } diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 42358c9cf6..84b6160d25 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -17,16 +17,19 @@ import arc.util.io.*; import mindustry.annotations.Annotations.*; import mindustry.audio.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.ctype.*; import mindustry.entities.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.logic.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; +import mindustry.world.blocks.ConstructBlock.*; import mindustry.world.blocks.environment.*; import mindustry.world.blocks.payloads.*; import mindustry.world.blocks.power.*; @@ -46,17 +49,18 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, static final Seq tempTiles = new Seq<>(); static int sleepingEntities = 0; - @Import float x, y, health; + @Import float x, y, health, maxHealth; @Import Team team; transient Tile tile; transient Block block; transient Seq proximity = new Seq<>(8); transient boolean updateFlow; - transient byte dump; + transient byte cdump; transient int rotation; transient boolean enabled = true; transient float enabledControlTime; + transient String lastAccessed; PowerModule power; ItemModule items; @@ -190,6 +194,36 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, //endregion //region utility methods + public void addPlan(boolean checkPrevious){ + if(!block.rebuildable) return; + + if(self() instanceof ConstructBuild entity){ + //update block to reflect the fact that something was being constructed + if(entity.cblock != null && entity.cblock.synthetic()){ + block = entity.cblock; + }else{ + //otherwise this was a deconstruction that was interrupted, don't want to rebuild that + return; + } + } + + TeamData data = state.teams.get(team); + + if(checkPrevious){ + //remove existing blocks that have been placed here. + //painful O(n) iteration + copy + for(int i = 0; i < data.blocks.size; i++){ + BlockPlan b = data.blocks.get(i); + if(b.x == tile.x && b.y == tile.y){ + data.blocks.removeIndex(i); + break; + } + } + } + + data.blocks.addFirst(new BlockPlan(tile.x, tile.y, (short)rotation, block.id, config())); + } + /** Configure with the current, local player. */ public void configure(Object value){ //save last used config @@ -215,9 +249,12 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, return true; } - public void applyBoost(float intensity, float duration){ + public void applyBoost(float intensity, float duration){ + //do not refresh time scale when getting a weaker intensity + if(intensity >= this.timeScale){ + timeScaleDuration = Math.max(timeScaleDuration, duration); + } timeScale = Math.max(timeScale, intensity); - timeScaleDuration = Math.max(timeScaleDuration, duration); } public Building nearby(int dx, int dy){ @@ -345,6 +382,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, //endregion //region handler methods + /** Called when an unloader takes an item. */ + public void itemTaken(Item item){ + + } + /** Called when this block is dropped as a payload. */ public void dropped(){ @@ -422,7 +464,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, */ public boolean movePayload(Payload todump){ int trns = block.size/2 + 1; - Tile next = tile.getNearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns); + Tile next = tile.nearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns); if(next != null && next.build != null && next.build.team == team && next.build.acceptPayload(self(), todump)){ next.build.handlePayload(self(), todump); @@ -440,7 +482,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, public boolean dumpPayload(Payload todump){ if(proximity.size == 0) return false; - int dump = this.dump; + int dump = this.cdump; for(int i = 0; i < proximity.size; i++){ Building other = proximity.get((i + dump) % proximity.size); @@ -465,8 +507,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, return block.consumes.itemFilters.get(item.id) && items.get(item) < getMaximumAccepted(item); } - public boolean acceptLiquid(Building source, Liquid liquid, float amount){ - return block.hasLiquids && liquids.get(liquid) + amount < block.liquidCapacity && block.consumes.liquidfilters.get(liquid.id); + public boolean acceptLiquid(Building source, Liquid liquid){ + return block.hasLiquids && block.consumes.liquidfilters.get(liquid.id); } public void handleLiquid(Building source, Liquid liquid, float amount){ @@ -474,7 +516,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } public void dumpLiquid(Liquid liquid){ - int dump = this.dump; + int dump = this.cdump; for(int i = 0; i < proximity.size; i++){ incrementDump(proximity.size); @@ -496,23 +538,23 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } public void transferLiquid(Building next, float amount, Liquid liquid){ - float flow = Math.min(next.block.liquidCapacity - next.liquids.get(liquid) - 0.001f, amount); + float flow = Math.min(next.block.liquidCapacity - next.liquids.get(liquid), amount); - if(next.acceptLiquid(self(), liquid, flow)){ + if(next.acceptLiquid(self(), liquid)){ next.handleLiquid(self(), liquid, flow); liquids.remove(liquid, flow); } } - public float moveLiquidForward(float leakResistance, Liquid liquid){ - Tile next = tile.getNearby(rotation); + public float moveLiquidForward(boolean leaks, Liquid liquid){ + Tile next = tile.nearby(rotation); if(next == null) return 0; if(next.build != null){ return moveLiquid(next.build, liquid); - }else if(leakResistance != 100f && !next.block().solid && !next.block().hasLiquids){ - float leakAmount = liquids.get(liquid) / leakResistance; + }else if(leaks && !next.block().solid && !next.block().hasLiquids){ + float leakAmount = liquids.get(liquid) / 1.5f; Puddles.deposit(next, tile, liquid, leakAmount); liquids.remove(liquid, leakAmount); } @@ -528,9 +570,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, float ofract = next.liquids.get(liquid) / next.block.liquidCapacity; float fract = liquids.get(liquid) / block.liquidCapacity * block.liquidPressure; float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (block.liquidCapacity), liquids.get(liquid)); - flow = Math.min(flow, next.block.liquidCapacity - next.liquids.get(liquid) - 0.001f); + flow = Math.min(flow, next.block.liquidCapacity - next.liquids.get(liquid)); - if(flow > 0f && ofract <= fract && next.acceptLiquid(self(), liquid, flow)){ + if(flow > 0f && ofract <= fract && next.acceptLiquid(self(), liquid)){ next.handleLiquid(self(), liquid, flow); liquids.remove(liquid, flow); return flow; @@ -574,7 +616,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, * containers, it gets added to the block's inventory. */ public void offload(Item item){ - int dump = this.dump; + int dump = this.cdump; for(int i = 0; i < proximity.size; i++){ incrementDump(proximity.size); @@ -592,7 +634,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, * Tries to put this item into a nearby container. Returns success. Unlike #offload(), this method does not change the block inventory. */ public boolean put(Item item){ - int dump = this.dump; + int dump = this.cdump; for(int i = 0; i < proximity.size; i++){ incrementDump(proximity.size); @@ -618,7 +660,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, public boolean dump(Item todump){ if(!block.hasItems || items.total() == 0 || (todump != null && !items.has(todump))) return false; - int dump = this.dump; + int dump = this.cdump; if(proximity.size == 0) return false; @@ -653,7 +695,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } public void incrementDump(int prox){ - dump = (byte)((dump + 1) % prox); + cdump = (byte)((cdump + 1) % prox); } /** Used for dumping items. */ @@ -757,9 +799,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } public void drawCracks(){ - if(!damaged() || block.size > Block.maxCrackSize) return; + if(!damaged() || block.size > BlockRenderer.maxCrackSize) return; int id = pos(); - TextureRegion region = Block.cracks[block.size - 1][Mathf.clamp((int)((1f - healthf()) * Block.crackRegions), 0, Block.crackRegions-1)]; + TextureRegion region = renderer.blocks.cracks[block.size - 1][Mathf.clamp((int)((1f - healthf()) * BlockRenderer.crackRegions), 0, BlockRenderer.crackRegions-1)]; Draw.colorl(0.2f, 0.1f + (1f - healthf())* 0.6f); Draw.rect(region, x, y, (id%4)*90); Draw.color(); @@ -869,7 +911,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, /** Called when arbitrary configuration is applied to a tile. */ public void configured(@Nullable Unit builder, @Nullable Object value){ //null is of type void.class; anonymous classes use their superclass. - Class type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass(); + Class type = value == null ? void.class : value.getClass().isAnonymousClass() || value.getClass().getSimpleName().startsWith("adapter") ? value.getClass().getSuperclass() : value.getClass(); + + if(builder != null && builder.isPlayer()){ + lastAccessed = builder.getPlayer().name; + } if(block.configurations.containsKey(type)){ block.configurations.get(type).get(this, value); @@ -1035,6 +1081,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } } + if(net.active() && lastAccessed != null){ + table.row(); + table.add(Core.bundle.format("lastaccessed", lastAccessed)).growX().wrap().left(); + } + table.marginBottom(-5); } } @@ -1162,10 +1213,6 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, proximity.add(tile); } - for(Building other : tmpTiles){ - other.onProximityUpdate(); - } - onProximityAdded(); onProximityUpdate(); @@ -1220,24 +1267,25 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, @Override public double sense(LAccess sensor){ return switch(sensor){ - case x -> x; - case y -> y; + case x -> World.conv(x); + case y -> World.conv(y); case team -> team.id; case health -> health; - case maxHealth -> maxHealth(); + case maxHealth -> maxHealth; case efficiency -> efficiency(); case rotation -> rotation; case totalItems -> items == null ? 0 : items.total(); case totalLiquids -> liquids == null ? 0 : liquids.total(); case totalPower -> power == null || !block.consumes.hasPower() ? 0 : power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f); - case itemCapacity -> block.itemCapacity; - case liquidCapacity -> block.liquidCapacity; + case itemCapacity -> block.hasItems ? block.itemCapacity : 0; + case liquidCapacity -> block.hasLiquids ? block.liquidCapacity : 0; case powerCapacity -> block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f; case powerNetIn -> power == null ? 0 : power.graph.getLastScaledPowerIn() * 60; case powerNetOut -> power == null ? 0 : power.graph.getLastScaledPowerOut() * 60; case powerNetStored -> power == null ? 0 : power.graph.getLastPowerStored(); case powerNetCapacity -> power == null ? 0 : power.graph.getLastCapacity(); case enabled -> enabled ? 1 : 0; + case payloadCount -> getPayload() != null ? 1 : 0; default -> 0; }; } @@ -1246,6 +1294,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, public Object senseObject(LAccess sensor){ return switch(sensor){ case type -> block; + case firstItem -> items == null ? null : items.first(); + case config -> block.configurations.containsKey(Item.class) || block.configurations.containsKey(Liquid.class) ? config() : null; + case payloadType -> getPayload() instanceof UnitPayload p1 ? p1.unit.type : getPayload() instanceof BuildPayload p2 ? p2.block() : null; default -> noSensed; }; @@ -1266,6 +1317,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } } + @Override + public void control(LAccess type, Object p1, double p2, double p3, double p4){ + + } + @Override public void remove(){ if(sound != null){ diff --git a/core/src/mindustry/entities/comp/BulletComp.java b/core/src/mindustry/entities/comp/BulletComp.java index 5ef68ac2e1..5a08710762 100644 --- a/core/src/mindustry/entities/comp/BulletComp.java +++ b/core/src/mindustry/entities/comp/BulletComp.java @@ -7,8 +7,10 @@ import arc.math.geom.*; import arc.struct.*; import arc.util.*; import mindustry.annotations.Annotations.*; +import mindustry.core.*; import mindustry.entities.bullet.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.graphics.*; @@ -19,25 +21,19 @@ import static mindustry.Vars.*; abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Drawc, Shielderc, Ownerc, Velc, Bulletc, Timerc{ @Import Team team; @Import Entityc owner; - @Import float x,y; + @Import float x, y, damage; IntSeq collided = new IntSeq(6); Object data; BulletType type; - float damage; float fdata; @Override public void getCollisions(Cons consumer){ - if(team.active()){ - for(Team team : team.enemies()){ - consumer.get(teamIndex.tree(team)); - } - }else{ - for(Team other : Team.all){ - if(other != team && teamIndex.count(other) > 0){ - consumer.get(teamIndex.tree(other)); - } + Seq data = state.teams.present; + for(int i = 0; i < data.size; i++){ + if(data.items[i].team != team){ + consumer.get(data.items[i].tree()); } } } @@ -76,11 +72,6 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw return type.drawSize; } - @Override - public float damage(){ - return damage * damageMultiplier(); - } - @Replace @Override public boolean collides(Hitboxc other){ @@ -95,14 +86,12 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw type.hit(self(), x, y); float health = 0f; - if(other instanceof Healthc){ - Healthc h = (Healthc)other; + if(other instanceof Healthc h){ health = h.health(); h.damage(damage); } - if(other instanceof Unit){ - Unit unit = (Unit)other; + if(other instanceof Unit unit){ unit.impulse(Tmp.v3.set(unit).sub(this.x, this.y).nor().scl(type.knockback * 80f)); unit.apply(type.status, type.statusDuration); } @@ -122,7 +111,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw type.update(self()); if(type.collidesTiles && type.collides && type.collidesGround){ - world.raycastEach(world.toTile(lastX()), world.toTile(lastY()), tileX(), tileY(), (x, y) -> { + world.raycastEach(World.toTile(lastX()), World.toTile(lastY()), tileX(), tileY(), (x, y) -> { Building tile = world.build(x, y); if(tile == null || !isAdded()) return false; @@ -152,6 +141,10 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw return false; }); } + + if(type.pierceCap != -1 && collided.size >= type.pierceCap) { + remove(); + } } @Override diff --git a/core/src/mindustry/entities/comp/CommanderComp.java b/core/src/mindustry/entities/comp/CommanderComp.java index a74c8aaf51..2fe2bf83a0 100644 --- a/core/src/mindustry/entities/comp/CommanderComp.java +++ b/core/src/mindustry/entities/comp/CommanderComp.java @@ -9,41 +9,41 @@ import mindustry.ai.types.*; import mindustry.annotations.Annotations.*; import mindustry.entities.*; import mindustry.entities.units.*; +import mindustry.game.*; import mindustry.gen.*; +import mindustry.type.*; /** A unit that can command other units. */ @Component -abstract class CommanderComp implements Unitc{ +abstract class CommanderComp implements Entityc, Posc{ private static final Seq members = new Seq<>(); private static final Seq units = new Seq<>(); - @Import float x, y, rotation; + @Import float x, y, rotation, hitSize; + @Import Team team; + @Import UnitType type; transient @Nullable Formation formation; - transient Seq controlling = new Seq<>(); + transient Seq controlling = new Seq<>(10); /** minimum speed of any unit in the formation. */ transient float minFormationSpeed; - @Override public void update(){ if(formation != null){ - formation.anchor.set(x, y, /*rotation*/ 0); //TODO rotation set to 0 because rotating is pointless + formation.anchor.set(x, y, 0); formation.updateSlots(); } } - @Override public void remove(){ clearCommand(); } - @Override public void killed(){ clearCommand(); } //make sure to reset command state when the controller is switched - @Override public void controller(UnitController next){ clearCommand(); } @@ -58,14 +58,15 @@ abstract class CommanderComp implements Unitc{ units.clear(); - Units.nearby(team(), x, y, 200f, u -> { - if(u.isAI() && include.get(u) && u != self()){ + Units.nearby(team, x, y, 150f, u -> { + if(u.isAI() && include.get(u) && u != self() && u.type.flying == type.flying && u.hitSize <= hitSize * 1.1f){ units.add(u); } }); - units.sort(u -> u.dst2(this)); - units.truncate(type().commandLimit); + //sort by hitbox size, then by distance + units.sort(Structs.comps(Structs.comparingFloat(u -> -u.hitSize), Structs.comparingFloat(u -> u.dst2(this)))); + units.truncate(type.commandLimit); command(formation, units); } @@ -73,15 +74,15 @@ abstract class CommanderComp implements Unitc{ void command(Formation formation, Seq units){ clearCommand(); - float spacing = hitSize() * 0.65f; - minFormationSpeed = type().speed; + float spacing = hitSize * 0.8f; + minFormationSpeed = type.speed; controlling.addAll(units); for(Unit unit : units){ FormationAI ai; unit.controller(ai = new FormationAI(self(), formation)); spacing = Math.max(spacing, ai.formationSize()); - minFormationSpeed = Math.min(minFormationSpeed, unit.type().speed); + minFormationSpeed = Math.min(minFormationSpeed, unit.type.speed); } this.formation = formation; @@ -105,7 +106,7 @@ abstract class CommanderComp implements Unitc{ //reset controlled units for(Unit unit : controlling){ if(unit.controller().isBeingControlled(self())){ - unit.controller(unit.type().createController()); + unit.controller(unit.type.createController()); } } diff --git a/core/src/mindustry/entities/comp/DamageComp.java b/core/src/mindustry/entities/comp/DamageComp.java index e46a7ec87c..d9b6105352 100644 --- a/core/src/mindustry/entities/comp/DamageComp.java +++ b/core/src/mindustry/entities/comp/DamageComp.java @@ -4,5 +4,5 @@ import mindustry.annotations.Annotations.*; @Component abstract class DamageComp{ - abstract float damage(); + float damage; } diff --git a/core/src/mindustry/entities/comp/FireComp.java b/core/src/mindustry/entities/comp/FireComp.java index ea67ca9e19..84fcb6b3b5 100644 --- a/core/src/mindustry/entities/comp/FireComp.java +++ b/core/src/mindustry/entities/comp/FireComp.java @@ -16,7 +16,7 @@ import static mindustry.Vars.*; @EntityDef(value = {Firec.class}, pooled = true) @Component(base = true) abstract class FireComp implements Timedc, Posc, Firec, Syncc{ - private static final float spreadChance = 0.05f, fireballChance = 0.07f; + private static final float spreadChance = 0.04f, fireballChance = 0.06f; @Import float time, lifetime, x, y; diff --git a/core/src/mindustry/entities/comp/MinerComp.java b/core/src/mindustry/entities/comp/MinerComp.java index 6e11178252..764e6ed4d3 100644 --- a/core/src/mindustry/entities/comp/MinerComp.java +++ b/core/src/mindustry/entities/comp/MinerComp.java @@ -35,6 +35,11 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ return mineTile != null && !(((Object)this) instanceof Builderc && ((Builderc)(Object)this).activelyBuilding()); } + public boolean validMine(Tile tile){ + return !(tile == null || tile.block() != Blocks.air || !within(tile.worldx(), tile.worldy(), miningRange) + || tile.drop() == null || !canMine(tile.drop())); + } + @Override public void update(){ Building core = closestCore(); @@ -49,8 +54,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ } } - if(mineTile == null || core == null || mineTile.block() != Blocks.air || dst(mineTile.worldx(), mineTile.worldy()) > miningRange - || mineTile.drop() == null || !canMine(mineTile.drop())){ + if(!validMine(mineTile)){ mineTile = null; mineTimer = 0f; }else if(mining()){ @@ -62,10 +66,10 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ Fx.pulverizeSmall.at(mineTile.worldx() + Mathf.range(tilesize / 2f), mineTile.worldy() + Mathf.range(tilesize / 2f), 0f, item.color); } - if(mineTimer >= 50f + item.hardness*10f){ + if(mineTimer >= 50f + item.hardness*15f){ mineTimer = 0; - if(within(core, mineTransferRange) && core.acceptStack(item, 1, this) == 1 && offloadImmediately()){ + if(core != null && within(core, mineTransferRange) && core.acceptStack(item, 1, this) == 1 && offloadImmediately()){ Call.transferItemTo(item, 1, mineTile.worldx() + Mathf.range(tilesize / 2f), mineTile.worldy() + Mathf.range(tilesize / 2f), core); diff --git a/core/src/mindustry/entities/comp/PayloadComp.java b/core/src/mindustry/entities/comp/PayloadComp.java index 75bc07c21e..e2945d08f7 100644 --- a/core/src/mindustry/entities/comp/PayloadComp.java +++ b/core/src/mindustry/entities/comp/PayloadComp.java @@ -6,6 +6,7 @@ import arc.util.*; import mindustry.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.entities.*; import mindustry.gen.*; import mindustry.type.*; @@ -25,11 +26,11 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{ } boolean canPickup(Unit unit){ - return payloadUsed() + unit.hitSize * unit.hitSize <= type.payloadCapacity + 0.001f; + return payloadUsed() + unit.hitSize * unit.hitSize <= type.payloadCapacity + 0.001f && unit.team == team() && unit.isAI(); } boolean canPickup(Building build){ - return payloadUsed() + build.block.size * build.block.size * Vars.tilesize * Vars.tilesize <= type.payloadCapacity + 0.001f; + return payloadUsed() + build.block.size * build.block.size * Vars.tilesize * Vars.tilesize <= type.payloadCapacity + 0.001f && build.canPickup(); } boolean canPickupPayload(Payload pay){ @@ -55,7 +56,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{ void pickup(Building tile){ tile.tile.remove(); - payloads.add(new BlockPayload(tile)); + payloads.add(new BuildPayload(tile)); Fx.unitPickup.at(tile); } @@ -86,10 +87,10 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{ return true; } - if(payload instanceof BlockPayload){ - return dropBlock((BlockPayload)payload); - }else if(payload instanceof UnitPayload){ - return dropUnit((UnitPayload)payload); + if(payload instanceof BuildPayload b){ + return dropBlock(b); + }else if(payload instanceof UnitPayload p){ + return dropUnit(p); } return false; } @@ -118,14 +119,16 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{ } /** @return whether the tile has been successfully placed. */ - boolean dropBlock(BlockPayload payload){ - Building tile = payload.entity; - int tx = Vars.world.toTile(x - tile.block.offset), ty = Vars.world.toTile(y - tile.block.offset); + boolean dropBlock(BuildPayload payload){ + Building tile = payload.build; + int tx = World.toTile(x - tile.block.offset), ty = World.toTile(y - tile.block.offset); Tile on = Vars.world.tile(tx, ty); if(on != null && Build.validPlace(tile.block, tile.team, tx, ty, tile.rotation, false)){ int rot = (int)((rotation + 45f) / 90f) % 4; payload.place(on, rot); + if(isPlayer()) payload.build.lastAccessed = getPlayer().name; + Fx.unitDrop.at(tile); Fx.placeBlock.at(on.drawx(), on.drawy(), on.block().size); return true; diff --git a/core/src/mindustry/entities/comp/PlayerComp.java b/core/src/mindustry/entities/comp/PlayerComp.java index 1e4a88a640..736a1b68e5 100644 --- a/core/src/mindustry/entities/comp/PlayerComp.java +++ b/core/src/mindustry/entities/comp/PlayerComp.java @@ -79,7 +79,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra admin = typing = false; textFadeTime = 0f; if(!dead()){ - unit.controller(unit.type().createController()); + unit.controller(unit.type.createController()); unit = Nulls.unit; } } @@ -91,7 +91,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra @Replace public float clipSize(){ - return unit.isNull() ? 20 : unit.type().hitSize * 2f; + return unit.isNull() ? 20 : unit.type.hitSize * 2f; } @Override @@ -123,7 +123,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra deathTimer = 0; //update some basic state to sync things - if(unit.type().canBoost){ + if(unit.type.canBoost){ Tile tile = unit.tileOn(); unit.elevation = Mathf.approachDelta(unit.elevation, (tile != null && tile.solid()) || boosting ? 1f : 0f, 0.08f); } @@ -177,7 +177,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra if(this.unit != Nulls.unit){ //un-control the old unit - this.unit.controller(this.unit.type().createController()); + this.unit.controller(this.unit.type.createController()); } this.unit = unit; if(unit != Nulls.unit){ @@ -188,6 +188,11 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra if(unit.isRemote()){ unit.snapInterpolation(); } + + //reset selected block when switching units + if(!headless && isLocal()){ + control.input.block = null; + } } Events.fire(new UnitChangeEvent(self(), unit)); diff --git a/core/src/mindustry/entities/comp/PosComp.java b/core/src/mindustry/entities/comp/PosComp.java index 1c0540eb01..6446c0f91f 100644 --- a/core/src/mindustry/entities/comp/PosComp.java +++ b/core/src/mindustry/entities/comp/PosComp.java @@ -2,9 +2,9 @@ package mindustry.entities.comp; import arc.math.geom.*; import arc.util.*; -import mindustry.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.world.*; import mindustry.world.blocks.environment.*; @@ -32,11 +32,11 @@ abstract class PosComp implements Position{ } int tileX(){ - return Vars.world.toTile(x); + return World.toTile(x); } int tileY(){ - return Vars.world.toTile(y); + return World.toTile(y); } /** Returns air if this unit is on a non-air top block. */ @@ -52,7 +52,7 @@ abstract class PosComp implements Position{ boolean onSolid(){ Tile tile = tileOn(); - return tile != null && tile.solid(); + return tile == null || tile.solid(); } @Nullable diff --git a/core/src/mindustry/entities/comp/PosTeamDef.java b/core/src/mindustry/entities/comp/PosTeamDef.java new file mode 100644 index 0000000000..0157200d66 --- /dev/null +++ b/core/src/mindustry/entities/comp/PosTeamDef.java @@ -0,0 +1,9 @@ +package mindustry.entities.comp; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +//dummy target definition +@EntityDef(value = Teamc.class, genio = false, isFinal = false) +public class PosTeamDef{ +} diff --git a/core/src/mindustry/entities/comp/PuddleComp.java b/core/src/mindustry/entities/comp/PuddleComp.java index 669ee7e1f2..a447bd633a 100644 --- a/core/src/mindustry/entities/comp/PuddleComp.java +++ b/core/src/mindustry/entities/comp/PuddleComp.java @@ -74,7 +74,7 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{ unit.apply(liquid.effect, 60 * 2); if(unit.vel.len() > 0.1){ - Fx.ripple.at(unit.x, unit.y, unit.type().rippleScale, liquid.color); + Fx.ripple.at(unit.x, unit.y, unit.type.rippleScale, liquid.color); } } } @@ -98,7 +98,7 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{ boolean onLiquid = tile.floor().isLiquid; float f = Mathf.clamp(amount / (maxLiquid / 1.5f)); float smag = onLiquid ? 0.8f : 0f; - float sscl = 20f; + float sscl = 25f; Draw.color(tmp.set(liquid.color).shiftValue(-0.05f)); Fill.circle(x + Mathf.sin(Time.time() + seeds * 532, sscl, smag), y + Mathf.sin(Time.time() + seeds * 53, sscl, smag), f * 8f); diff --git a/core/src/mindustry/entities/comp/ShieldComp.java b/core/src/mindustry/entities/comp/ShieldComp.java index 359637414e..274286b801 100644 --- a/core/src/mindustry/entities/comp/ShieldComp.java +++ b/core/src/mindustry/entities/comp/ShieldComp.java @@ -9,7 +9,7 @@ import static mindustry.Vars.*; @Component abstract class ShieldComp implements Healthc, Posc{ - @Import float health, hitTime, x, y; + @Import float health, hitTime, x, y, healthMultiplier; @Import boolean dead; /** Absorbs health damage. */ @@ -22,6 +22,7 @@ abstract class ShieldComp implements Healthc, Posc{ @Replace @Override public void damage(float amount){ + amount /= healthMultiplier; //apply armor amount = Math.max(amount - armor, minArmorDamage * amount); diff --git a/core/src/mindustry/entities/comp/StatusComp.java b/core/src/mindustry/entities/comp/StatusComp.java index 3a31b13b95..fcce0d0a02 100644 --- a/core/src/mindustry/entities/comp/StatusComp.java +++ b/core/src/mindustry/entities/comp/StatusComp.java @@ -19,7 +19,7 @@ abstract class StatusComp implements Posc, Flyingc{ private Seq statuses = new Seq<>(); private transient Bits applied = new Bits(content.getBy(ContentType.status).size); - @ReadOnly transient float speedMultiplier = 1, damageMultiplier = 1, armorMultiplier = 1, reloadMultiplier = 1; + @ReadOnly transient float speedMultiplier = 1, damageMultiplier = 1, healthMultiplier = 1, reloadMultiplier = 1; @Import UnitType type; @@ -104,7 +104,7 @@ abstract class StatusComp implements Posc, Flyingc{ } applied.clear(); - speedMultiplier = damageMultiplier = armorMultiplier = reloadMultiplier = 1f; + speedMultiplier = damageMultiplier = healthMultiplier = reloadMultiplier = 1f; if(statuses.isEmpty()) return; @@ -122,7 +122,7 @@ abstract class StatusComp implements Posc, Flyingc{ statuses.remove(index); }else{ speedMultiplier *= entry.effect.speedMultiplier; - armorMultiplier *= entry.effect.armorMultiplier; + healthMultiplier *= entry.effect.healthMultiplier; damageMultiplier *= entry.effect.damageMultiplier; reloadMultiplier *= entry.effect.reloadMultiplier; entry.effect.update(self(), entry.time); diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 64cc23be20..11efcf9948 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -1,6 +1,7 @@ package mindustry.entities.comp; import arc.*; +import arc.func.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; @@ -10,6 +11,7 @@ import arc.util.*; import mindustry.ai.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.ctype.*; import mindustry.entities.*; import mindustry.entities.abilities.*; @@ -23,11 +25,12 @@ import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; import mindustry.world.blocks.environment.*; +import mindustry.world.blocks.payloads.*; import static mindustry.Vars.*; @Component(base = true) -abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable, Senseable{ +abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged{ @Import boolean hovering, dead; @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo; @@ -35,8 +38,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I @Import int id; private UnitController controller; - private UnitType type; + UnitType type; boolean spawnedByCore; + double flag; transient Seq abilities = new Seq<>(0); private transient float resupplyTime = Mathf.random(10f); @@ -63,6 +67,18 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I return type.hasWeapons(); } + /** @return speed with boost multipliers factored in. */ + public float realSpeed(){ + return Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, elevation) * type.speed; + } + + /** Iterates through this unit and everything it is controlling. */ + public void eachGroup(Cons cons){ + cons.get(self()); + controlling().each(cons); + } + + @Override public float range(){ return type.range; } @@ -76,15 +92,20 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I public double sense(LAccess sensor){ return switch(sensor){ case totalItems -> stack().amount; + case itemCapacity -> type.itemCapacity; case rotation -> rotation; case health -> health; case maxHealth -> maxHealth; - case x -> x; - case y -> y; + case ammo -> !state.rules.unitAmmo ? type.ammoCapacity : ammo; + case ammoCapacity -> type.ammoCapacity; + case x -> World.conv(x); + case y -> World.conv(y); case team -> team.id; case shooting -> isShooting() ? 1 : 0; - case shootX -> aimX(); - case shootY -> aimY(); + case shootX -> World.conv(aimX()); + case shootY -> World.conv(aimY()); + case flag -> flag; + case payloadCount -> self() instanceof Payloadc pay ? pay.payloads().size : 0; default -> 0; }; } @@ -93,6 +114,12 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I public Object senseObject(LAccess sensor){ return switch(sensor){ case type -> type; + case name -> controller instanceof Player p ? p.name : null; + case firstItem -> stack().amount == 0 ? null : item(); + case payloadType -> self() instanceof Payloadc pay ? + (pay.payloads().isEmpty() ? null : + pay.payloads().peek() instanceof UnitPayload p1 ? p1.unit.type : + pay.payloads().peek() instanceof BuildPayload p2 ? p2.block() : null) : null; default -> noSensed; }; @@ -144,22 +171,12 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I @Override public void set(UnitType def, UnitController controller){ - type(type); + if(this.type != def){ + setType(def); + } controller(controller); } - @Override - public void type(UnitType type){ - if(this.type == type) return; - - setStats(type); - } - - @Override - public UnitType type(){ - return type; - } - /** @return pathfinder path type for calculating costs */ public int pathType(){ return Pathfinder.costGround; @@ -182,14 +199,14 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I } public int count(){ - return teamIndex.countType(team, type); + return team.data().countType(type); } public int cap(){ return Units.getCap(team); } - public void setStats(UnitType type){ + public void setType(UnitType type){ this.type = type; this.maxHealth = type.health; this.drag = type.drag; @@ -207,7 +224,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I @Override public void afterSync(){ //set up type info after reading - setStats(this.type); + setType(this.type); controller.unit(self()); } @@ -224,13 +241,13 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I //check if over unit cap if(count() > cap() && !spawnedByCore && !dead){ Call.unitCapDeath(self()); - teamIndex.updateCount(team, type, -1); + team.data().updateCount(type, -1); } } @Override public void remove(){ - teamIndex.updateCount(team, type, -1); + team.data().updateCount(type, -1); controller.removed(self()); } @@ -267,7 +284,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I drag = type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f); //apply knockback based on spawns - if(team != state.rules.waveTeam){ + if(team != state.rules.waveTeam && state.hasSpawns()){ float relativeSize = state.rules.dropZoneRadius + hitSize/2f + 1f; for(Tile spawn : spawner.getSpawns()){ if(within(spawn.worldx(), spawn.worldy(), relativeSize)){ diff --git a/core/src/mindustry/entities/comp/WeaponsComp.java b/core/src/mindustry/entities/comp/WeaponsComp.java index d826ba555f..dec0105c14 100644 --- a/core/src/mindustry/entities/comp/WeaponsComp.java +++ b/core/src/mindustry/entities/comp/WeaponsComp.java @@ -111,7 +111,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{ //update continuous state if(weapon.continuous && mount.bullet != null){ - if(!mount.bullet.isAdded() || mount.bullet.time >= mount.bullet.lifetime){ + if(!mount.bullet.isAdded() || mount.bullet.time >= mount.bullet.lifetime || mount.bullet.type != weapon.bullet){ mount.bullet = null; }else{ mount.bullet.rotation(weaponRotation + 90); @@ -166,14 +166,15 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{ Weapon weapon = mount.weapon; float baseX = this.x, baseY = this.y; + boolean delay = weapon.firstShotDelay + weapon.shotDelay > 0f; - weapon.shootSound.at(x, y, Mathf.random(0.8f, 1.0f)); + (delay ? weapon.chargeSound : weapon.shootSound).at(x, y, Mathf.random(0.8f, 1.0f)); BulletType ammo = weapon.bullet; float lifeScl = ammo.scaleVelocity ? Mathf.clamp(Mathf.dst(x, y, aimX, aimY) / ammo.range()) : 1f; sequenceNum = 0; - if(weapon.shotDelay + weapon.firstShotDelay > 0.01f){ + if(delay){ Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> { Time.run(sequenceNum * weapon.shotDelay + weapon.firstShotDelay, () -> { if(!isAdded()) return; @@ -187,13 +188,14 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{ boolean parentize = ammo.keepVelocity; - if(weapon.firstShotDelay > 0){ + if(delay){ Time.run(weapon.firstShotDelay, () -> { if(!isAdded()) return; vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil)); Effect.shake(weapon.shake, weapon.shake, x, y); mount.heat = 1f; + weapon.shootSound.at(x, y, Mathf.random(0.8f, 1.0f)); }); }else{ vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil)); diff --git a/core/src/mindustry/entities/units/AIController.java b/core/src/mindustry/entities/units/AIController.java index d61da2a1ba..ca005fe25d 100644 --- a/core/src/mindustry/entities/units/AIController.java +++ b/core/src/mindustry/entities/units/AIController.java @@ -4,6 +4,7 @@ import arc.math.*; import arc.math.geom.*; import arc.util.*; import mindustry.*; +import mindustry.ai.*; import mindustry.entities.*; import mindustry.gen.*; import mindustry.type.*; @@ -20,6 +21,7 @@ public class AIController implements UnitController{ protected Unit unit; protected Interval timer = new Interval(4); + protected AIController fallback; /** main target that is being faced */ protected Teamc target; @@ -33,11 +35,27 @@ public class AIController implements UnitController{ @Override public void updateUnit(){ + //use fallback AI when possible + if(useFallback() && (fallback != null || (fallback = fallback()) != null)){ + if(fallback.unit != unit) fallback.unit(unit); + fallback.updateUnit(); + return; + } + updateVisuals(); updateTargeting(); updateMovement(); } + @Nullable + protected AIController fallback(){ + return null; + } + + protected boolean useFallback(){ + return false; + } + protected UnitCommand command(){ return unit.team.data().command; } @@ -63,6 +81,23 @@ public class AIController implements UnitController{ } } + protected boolean invalid(Teamc target){ + return Units.invalidateTarget(target, unit.team, unit.x, unit.y); + } + + + protected void pathfind(int pathTarget){ + int costType = unit.pathType(); + + Tile tile = unit.tileOn(); + if(tile == null) return; + Tile targetTile = pathfinder.getTargetTile(tile, pathfinder.getField(unit.team, costType, pathTarget)); + + if(tile == targetTile || (costType == Pathfinder.costWater && !targetTile.floor().isLiquid)) return; + + unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type.speed)); + } + protected void updateWeapons(){ if(targets.length != unit.mounts.length) targets = new Teamc[unit.mounts.length]; @@ -70,10 +105,10 @@ public class AIController implements UnitController{ boolean ret = retarget(); if(ret){ - target = findTarget(unit.x, unit.y, unit.range(), unit.type().targetAir, unit.type().targetGround); + target = findTarget(unit.x, unit.y, unit.range(), unit.type.targetAir, unit.type.targetGround); } - if(Units.invalidateTarget(target, unit.team, unit.x, unit.y)){ + if(invalid(target)){ target = null; } @@ -84,7 +119,7 @@ public class AIController implements UnitController{ float mountX = unit.x + Angles.trnsx(rotation, weapon.x, weapon.y), mountY = unit.y + Angles.trnsy(rotation, weapon.x, weapon.y); - if(unit.type().singleTarget){ + if(unit.type.singleTarget){ targets[i] = target; }else{ if(ret){ @@ -99,13 +134,11 @@ public class AIController implements UnitController{ boolean shoot = false; if(targets[i] != null){ - shoot = targets[i].within(mountX, mountY, weapon.bullet.range()); + shoot = targets[i].within(mountX, mountY, weapon.bullet.range()) && shouldShoot(); - if(shoot){ - Vec2 to = Predict.intercept(unit, targets[i], weapon.bullet.speed); - mount.aimX = to.x; - mount.aimY = to.y; - } + Vec2 to = Predict.intercept(unit, targets[i], weapon.bullet.speed); + mount.aimX = to.x; + mount.aimY = to.y; } mount.shoot = shoot; @@ -113,6 +146,10 @@ public class AIController implements UnitController{ } } + protected boolean shouldShoot(){ + return true; + } + protected Teamc targetFlag(float x, float y, BlockFlag flag, boolean enemy){ Tile target = Geometry.findClosest(x, y, enemy ? indexer.getEnemy(unit.team, flag) : indexer.getAllied(unit.team, flag)); return target == null ? null : target.build; @@ -139,7 +176,7 @@ public class AIController implements UnitController{ } protected void circle(Position target, float circleLength){ - circle(target, circleLength, unit.type().speed); + circle(target, circleLength, unit.type.speed); } protected void circle(Position target, float circleLength, float speed){ @@ -157,13 +194,17 @@ public class AIController implements UnitController{ } protected void moveTo(Position target, float circleLength){ + moveTo(target, circleLength, 100f); + } + + protected void moveTo(Position target, float circleLength, float smooth){ if(target == null) return; vec.set(target).sub(unit); - float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / 100f, -1f, 1f); + float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / smooth, -1f, 1f); - vec.setLength(unit.type().speed * length); + vec.setLength(unit.realSpeed() * length); if(length < -0.5f){ vec.rotate(180f); }else if(length < 0){ diff --git a/core/src/mindustry/game/DefaultWaves.java b/core/src/mindustry/game/DefaultWaves.java index a889f9d4ba..adc2107f84 100644 --- a/core/src/mindustry/game/DefaultWaves.java +++ b/core/src/mindustry/game/DefaultWaves.java @@ -1,5 +1,6 @@ package mindustry.game; +import arc.func.*; import arc.math.*; import arc.struct.*; import arc.util.*; @@ -17,6 +18,7 @@ public class DefaultWaves{ new SpawnGroup(dagger){{ end = 10; unitScaling = 2f; + max = 30; }}, new SpawnGroup(crawler){{ @@ -37,12 +39,14 @@ public class DefaultWaves{ unitScaling = 1.7f; spacing = 2; max = 4; + shieldScaling = 25f; }}, new SpawnGroup(pulsar){{ begin = 13; spacing = 3; unitScaling = 0.5f; + max = 25; }}, new SpawnGroup(mace){{ @@ -54,10 +58,12 @@ public class DefaultWaves{ }}, new SpawnGroup(dagger){{ - begin = 8; + begin = 12; unitScaling = 1; unitAmount = 4; spacing = 2; + shieldScaling = 20f; + max = 14; }}, new SpawnGroup(mace){{ @@ -65,16 +71,20 @@ public class DefaultWaves{ spacing = 3; unitScaling = 1; end = 40; + shieldScaling = 20f; }}, - new SpawnGroup(mace){{ + new SpawnGroup(spiroct){{ begin = 45; spacing = 3; - unitScaling = 2; + unitScaling = 1; + max = 10; + shieldScaling = 30f; + shields = 100; effect = StatusEffects.overdrive; }}, - new SpawnGroup(mace){{ + new SpawnGroup(pulsar){{ begin = 120; spacing = 2; unitScaling = 3; @@ -86,22 +96,26 @@ public class DefaultWaves{ begin = 16; unitScaling = 1; spacing = 2; + shieldScaling = 20f; + max = 20; }}, - new SpawnGroup(dagger){{ + new SpawnGroup(quasar){{ begin = 82; spacing = 3; unitAmount = 4; unitScaling = 3; + shieldScaling = 30f; effect = StatusEffects.overdrive; }}, - new SpawnGroup(dagger){{ + new SpawnGroup(pulsar){{ begin = 41; spacing = 5; unitAmount = 1; unitScaling = 3; effect = StatusEffects.shielded; + max = 25; }}, new SpawnGroup(fortress){{ @@ -110,9 +124,10 @@ public class DefaultWaves{ unitAmount = 2; unitScaling = 2; max = 20; + shieldScaling = 30; }}, - new SpawnGroup(dagger){{ + new SpawnGroup(nova){{ begin = 35; spacing = 3; unitAmount = 4; @@ -128,6 +143,7 @@ public class DefaultWaves{ effect = StatusEffects.overdrive; items = new ItemStack(Items.pyratite, 100); end = 130; + max = 30; }}, new SpawnGroup(horizon){{ @@ -135,6 +151,7 @@ public class DefaultWaves{ unitAmount = 2; spacing = 2; unitScaling = 2; + shieldScaling = 20; }}, new SpawnGroup(flare){{ @@ -142,7 +159,10 @@ public class DefaultWaves{ unitAmount = 4; unitScaling = 3; spacing = 5; + shields = 100f; + shieldScaling = 10f; effect = StatusEffects.overdrive; + max = 20; }}, new SpawnGroup(zenith){{ @@ -151,13 +171,15 @@ public class DefaultWaves{ unitScaling = 3; spacing = 5; max = 16; + shieldScaling = 30; }}, - new SpawnGroup(horizon){{ + new SpawnGroup(nova){{ begin = 53; unitAmount = 2; unitScaling = 3; spacing = 4; + shieldScaling = 30; }}, new SpawnGroup(atrax){{ @@ -165,6 +187,7 @@ public class DefaultWaves{ unitAmount = 4; unitScaling = 1; spacing = 3; + shieldScaling = 10f; }}, new SpawnGroup(scepter){{ @@ -172,6 +195,7 @@ public class DefaultWaves{ unitAmount = 1; unitScaling = 1; spacing = 30; + shieldScaling = 30f; }}, new SpawnGroup(reign){{ @@ -179,13 +203,32 @@ public class DefaultWaves{ unitAmount = 1; unitScaling = 1; spacing = 40; + shieldScaling = 30f; }}, new SpawnGroup(antumbra){{ - begin = 131; + begin = 120; unitAmount = 1; unitScaling = 1; spacing = 40; + shieldScaling = 30f; + }}, + + new SpawnGroup(vela){{ + begin = 100; + unitAmount = 1; + unitScaling = 1; + spacing = 30; + shieldScaling = 30f; + }}, + + new SpawnGroup(corvus){{ + begin = 145; + unitAmount = 1; + unitScaling = 1; + spacing = 35; + shieldScaling = 30f; + shields = 100; }}, new SpawnGroup(horizon){{ @@ -193,20 +236,34 @@ public class DefaultWaves{ unitAmount = 2; unitScaling = 3; spacing = 4; + shields = 40f; + shieldScaling = 30f; + }}, + + new SpawnGroup(toxopid){{ + begin = 210; + unitAmount = 1; + unitScaling = 1; + spacing = 35; + shields = 1000; + shieldScaling = 35f; }} ); } return spawns == null ? new Seq<>() : spawns; } - //TODO move elsewhere - public static Seq generate(){ + public static Seq generate(float difficulty){ + return generate(new Rand(), difficulty); + } + + public static Seq generate(Rand rand, float difficulty){ UnitType[][] species = { {dagger, mace, fortress, scepter, reign}, {nova, pulsar, quasar, vela, corvus}, {crawler, atrax, spiroct, arkyid, toxopid}, //{risso, minke, bryde, sei, omura}, //questionable choices - //{mono, poly, mega, quad, oct}, //do not attack + {flare, horizon, difficulty > 0.5 ? poly : zenith, quad, quad}, {flare, horizon, zenith, antumbra, eclipse} }; @@ -216,57 +273,130 @@ public class DefaultWaves{ Seq out = new Seq<>(); //max reasonable wave, after which everything gets boring - int cap = 400; + int cap = 150; - //main sequence - float shieldStart = 30, shieldsPerWave = 12; - UnitType[] curSpecies = Structs.random(species); - int curTier = 0; + float shieldStart = 30, shieldsPerWave = 20 + difficulty*30f; - for(int i = 0; i < cap;){ - int f = i; - int next = Mathf.random(15, 25); + Intc createProgression = start -> { + //main sequence + UnitType[] curSpecies = Structs.random(species); + int curTier = 0; - float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0); + for(int i = start; i < cap;){ + int f = i; + int next = rand.random(8, 16); - //main progression - out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{ - unitAmount = f == 0 ? 1 : 10; - begin = f; - end = f + next >= cap ? never : f + next; - max = 16; - unitScaling = Mathf.random(1f, 2f); - shields = shieldAmount; - shieldScaling = shieldsPerWave; - }}); + float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0); + int space = start == 0 ? 1 : rand.random(1, 2); - //extra progression that tails out, blends in - out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{ - unitAmount = 6; - begin = f + next; - end = f + next + Mathf.random(8, 12); - max = 10; - unitScaling = Mathf.random(2f); - spacing = Mathf.random(2, 3); - shields = shieldAmount; - shieldScaling = shieldsPerWave; - }}); + //main progression + out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{ + unitAmount = f == 0 ? 1 : 10; + begin = f; + end = f + next >= cap ? never : f + next; + max = 14; + unitScaling = rand.random(1f, 3f); + shields = shieldAmount; + shieldScaling = shieldsPerWave; + spacing = space; + }}); - i += next; - if(curTier < 3 || Mathf.chance(0.2)){ - curTier ++; + //extra progression that tails out, blends in + out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{ + unitAmount = 6; + begin = f + next; + end = f + next + rand.random(8, 12); + max = 11; + unitScaling = rand.random(2f); + spacing = rand.random(2, 3); + shields = shieldAmount; + shieldScaling = shieldsPerWave; + }}); + + i += next; + if(curTier < 3 || rand.chance(0.2)){ + curTier ++; + } + + //do not spawn bosses + curTier = Math.min(curTier, 3); + + //small chance to switch species + if(rand.chance(0.3)){ + curSpecies = Structs.random(species); + } } + }; - //do not spawn bosses - curTier = Math.min(curTier, 3); + createProgression.get(0); - //small chance to switch species - if(Mathf.chance(0.2)){ - curSpecies = Structs.random(species); - } + int step = 5 + rand.random(3); + + while(step <= cap){ + createProgression.get(step); + step += (int)(rand.random(13, 25) * Mathf.lerp(1f, 0.5f, difficulty)); } + int bossWave = (int)(rand.random(30, 60) * Mathf.lerp(1f, 0.7f, difficulty)); + int bossSpacing = (int)(rand.random(25, 40) * Mathf.lerp(1f, 0.6f, difficulty)); + //main boss progression + out.add(new SpawnGroup(Structs.random(species)[4]){{ + unitAmount = 1; + begin = bossWave; + spacing = bossSpacing; + end = never; + max = 16; + unitScaling = bossSpacing; + shieldScaling = shieldsPerWave; + effect = StatusEffects.boss; + }}); + + //alt boss progression + out.add(new SpawnGroup(Structs.random(species)[4]){{ + unitAmount = 1; + begin = bossWave + rand.random(3, 5) * bossSpacing; + spacing = bossSpacing; + end = never; + max = 16; + unitScaling = bossSpacing; + shieldScaling = shieldsPerWave; + effect = StatusEffects.boss; + }}); + + int finalBossStart = 120 + rand.random(30); + + //final boss waves + out.add(new SpawnGroup(Structs.random(species)[4]){{ + unitAmount = 1; + begin = finalBossStart; + spacing = bossSpacing/2; + end = never; + unitScaling = bossSpacing; + shields = 500; + shieldScaling = shieldsPerWave * 4; + effect = StatusEffects.boss; + }}); + + //final boss waves (alt) + out.add(new SpawnGroup(Structs.random(species)[4]){{ + unitAmount = 1; + begin = finalBossStart + 15; + spacing = bossSpacing/2; + end = never; + unitScaling = bossSpacing; + shields = 500; + shieldScaling = shieldsPerWave * 4; + effect = StatusEffects.boss; + }}); + + //shift back waves on higher difficulty for a harder start + int shift = Math.max((int)(difficulty * 15 - 5), 0); + + for(SpawnGroup group : out){ + group.begin -= shift; + group.end -= shift; + } return out; } diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index 272c26363f..1ab946c4ac 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -35,7 +35,13 @@ public class EventType{ preDraw, postDraw, uiDrawBegin, - uiDrawEnd + uiDrawEnd, + //before/after bloom used, skybox or planets drawn + universeDrawBegin, + //skybox drawn and bloom is enabled - use Vars.renderer.planets + universeDraw, + //planets drawn and bloom disabled + universeDrawEnd } public static class WinEvent{} @@ -73,6 +79,15 @@ public class EventType{ } } + /** Called when a sector is destroyed by waves when you're not there. */ + public static class SectorInvasionEvent{ + public final Sector sector; + + public SectorInvasionEvent(Sector sector){ + this.sector = sector; + } + } + public static class LaunchItemEvent{ public final ItemStack stack; @@ -214,8 +229,8 @@ public class EventType{ } /** - * Called when block building begins by placing down the BuildBlock. - * The tile's block will nearly always be a BuildBlock. + * Called when block building begins by placing down the ConstructBlock. + * The tile's block will nearly always be a ConstructBlock. */ public static class BlockBuildBeginEvent{ public final Tile tile; @@ -247,7 +262,7 @@ public class EventType{ /** * Called when a player or drone begins building something. - * This does not necessarily happen when a new BuildBlock is created. + * This does not necessarily happen when a new ConstructBlock is created. */ public static class BuildSelectEvent{ public final Tile tile; diff --git a/core/src/mindustry/game/Stats.java b/core/src/mindustry/game/GameStats.java similarity index 96% rename from core/src/mindustry/game/Stats.java rename to core/src/mindustry/game/GameStats.java index 1d175607ba..8108f2ddad 100644 --- a/core/src/mindustry/game/Stats.java +++ b/core/src/mindustry/game/GameStats.java @@ -6,7 +6,7 @@ import mindustry.type.*; //TODO more stats: //- units constructed -public class Stats{ +public class GameStats{ /** Total items delivered to global resoure counter. Campaign only. */ public ObjectIntMap itemsDelivered = new ObjectIntMap<>(); /** Enemy (red team) units destroyed. */ @@ -40,7 +40,7 @@ public class Stats{ //weigh used fractions float frac = 0f; - Seq obtainable = zone.save == null ? new Seq<>() : zone.save.meta.secinfo.resources.select(i -> i instanceof Item).as(); + Seq obtainable = zone.save == null ? new Seq<>() : zone.info.resources.select(i -> i instanceof Item).as(); for(Item item : obtainable){ frac += Mathf.clamp((float)itemsDelivered.get(item, 0) / capacity) / (float)obtainable.size; } diff --git a/core/src/mindustry/game/Gamemode.java b/core/src/mindustry/game/Gamemode.java index 9de5e71052..f2bb95130a 100644 --- a/core/src/mindustry/game/Gamemode.java +++ b/core/src/mindustry/game/Gamemode.java @@ -23,7 +23,6 @@ public enum Gamemode{ rules.waveTimer = true; rules.waveSpacing /= 2f; - rules.teams.get(rules.waveTeam).ai = true; rules.teams.get(rules.waveTeam).infiniteResources = true; }, map -> map.teams.contains(state.rules.waveTeam.id)), pvp(rules -> { diff --git a/core/src/mindustry/game/Objectives.java b/core/src/mindustry/game/Objectives.java index 535f1d3e13..7fc844a180 100644 --- a/core/src/mindustry/game/Objectives.java +++ b/core/src/mindustry/game/Objectives.java @@ -38,7 +38,7 @@ public class Objectives{ @Override public boolean complete(){ - return preset.sector.isCaptured(); + return preset.sector.save != null && preset.sector.save.meta.wave >= preset.captureWave; } @Override diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index a101fe8592..2a927cc59b 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -82,6 +82,8 @@ public class Rules{ public Seq weather = new Seq<>(1); /** Blocks that cannot be placed. */ public ObjectSet bannedBlocks = new ObjectSet<>(); + /** Unlocked content names. Only used in multiplayer when the campaign is enabled. */ + public ObjectSet researched = new ObjectSet<>(); /** Whether ambient lighting is enabled. */ public boolean lighting = false; /** Whether enemy lighting is visible. @@ -104,6 +106,8 @@ public class Rules{ public boolean ai; /** TODO Tier of blocks/designs that the AI uses for building. [0, 1]*/ public float aiTier = 0f; + /** Whether, when AI is enabled, ships should be spawned from the core. */ + public boolean aiCoreSpawn = true; /** If true, blocks don't require power or resources. */ public boolean cheat; /** If true, resources are not consumed when building. */ diff --git a/core/src/mindustry/game/Schematic.java b/core/src/mindustry/game/Schematic.java index 3aeb222d29..e539ae69a2 100644 --- a/core/src/mindustry/game/Schematic.java +++ b/core/src/mindustry/game/Schematic.java @@ -62,6 +62,10 @@ public class Schematic implements Publishable, Comparable{ return tags.get("name", "unknown"); } + public String description(){ + return tags.get("description", ""); + } + public void save(){ schematics.saveChanges(this); } @@ -90,7 +94,7 @@ public class Schematic implements Publishable, Comparable{ @Override public String steamDescription(){ - return null; + return description(); } @Override diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index 596a571d3a..20fe7c36c4 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -16,6 +16,7 @@ import arc.util.pooling.*; import arc.util.serialization.*; import mindustry.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.ctype.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; @@ -608,8 +609,8 @@ public class Schematics implements Loadable{ wx = wy; wy = -x; } - req.x = (short)(world.toTile(wx - req.block.offset) + ox); - req.y = (short)(world.toTile(wy - req.block.offset) + oy); + req.x = (short)(World.toTile(wx - req.block.offset) + ox); + req.y = (short)(World.toTile(wy - req.block.offset) + oy); req.rotation = (byte)Mathf.mod(req.rotation + direction, 4); }); diff --git a/core/src/mindustry/game/SectorInfo.java b/core/src/mindustry/game/SectorInfo.java index dc56902c60..3b2b4df3dd 100644 --- a/core/src/mindustry/game/SectorInfo.java +++ b/core/src/mindustry/game/SectorInfo.java @@ -5,11 +5,14 @@ import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.ctype.*; +import mindustry.maps.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.storage.CoreBlock.*; import mindustry.world.modules.*; +import java.util.*; + import static mindustry.Vars.*; public class SectorInfo{ @@ -23,9 +26,9 @@ public class SectorInfo{ /** Export statistics. */ public ObjectMap export = new ObjectMap<>(); /** Items stored in all cores. */ - public ItemSeq coreItems = new ItemSeq(); + public ItemSeq items = new ItemSeq(); /** The best available core type. */ - public Block bestCoreType = Blocks.air; + public Block bestCoreType = Blocks.coreShard; /** Max storage capacity. */ public int storageCapacity = 0; /** Whether a core is available here. */ @@ -36,13 +39,40 @@ public class SectorInfo{ public @Nullable Sector destination; /** Resources known to occur at this sector. */ public Seq resources = new Seq<>(); - /** Time spent at this sector. Do not use unless you know what you're doing. */ - public transient float internalTimeSpent; + /** Whether waves are enabled here. */ + public boolean waves = true; + /** Whether attack mode is enabled here. */ + public boolean attack = false; + /** Wave # from state */ + public int wave = 1, winWave = -1; + /** Time between waves. */ + public float waveSpacing = 60 * 60 * 2; + /** Damage dealt to sector. */ + public float damage; + /** How many waves have passed while the player was away. */ + public int wavesPassed; + /** Packed core spawn position. */ + public int spawnPosition; + /** How long the player has been playing elsewhere. */ + public float secondsPassed; + /** Display name. */ + public @Nullable String name; + + /** Special variables for simulation. */ + public float sumHealth, sumRps, sumDps, waveHealthBase, waveHealthSlope, waveDpsBase, waveDpsSlope; /** Counter refresh state. */ private transient Interval time = new Interval(); /** Core item storage to prevent spoofing. */ - private transient int[] lastCoreItems; + private transient int[] coreItemCounts; + + /** Handles core item changes. */ + public void handleCoreItem(Item item, int amount){ + if(coreItemCounts == null){ + coreItemCounts = new int[content.items().size]; + } + coreItemCounts[item.id] += amount; + } /** @return the real location items go when launched on this sector */ public Sector getRealDestination(){ @@ -69,26 +99,68 @@ public class SectorInfo{ return export.get(item, ExportStat::new).mean; } + /** Write contents of meta into main storage. */ + public void write(){ + //enable attack mode when there's a core. + if(state.rules.waveTeam.core() != null){ + attack = true; + winWave = 0; + } + + //if there are infinite waves and no win wave, add a win wave. + if(waves && winWave <= 0 && !attack){ + winWave = 30; + } + + state.wave = wave; + state.rules.waves = waves; + state.rules.waveSpacing = waveSpacing; + state.rules.winWave = winWave; + state.rules.attackMode = attack; + + CoreBuild entity = state.rules.defaultTeam.core(); + if(entity != null){ + entity.items.clear(); + entity.items.add(items); + //ensure capacity. + entity.items.each((i, a) -> entity.items.set(i, Math.min(a, entity.storageCapacity))); + } + } + /** Prepare data for writing to a save. */ public void prepare(){ //update core items - coreItems.clear(); + items.clear(); CoreBuild entity = state.rules.defaultTeam.core(); if(entity != null){ ItemModule items = entity.items; for(int i = 0; i < items.length(); i++){ - coreItems.set(content.item(i), items.get(i)); + this.items.set(content.item(i), items.get(i)); } + + spawnPosition = entity.pos(); } + waveSpacing = state.rules.waveSpacing; + wave = state.wave; + winWave = state.rules.winWave; + waves = state.rules.waves; + attack = state.rules.attackMode; hasCore = entity != null; bestCoreType = !hasCore ? Blocks.air : state.rules.defaultTeam.cores().max(e -> e.block.size).block; storageCapacity = entity != null ? entity.storageCapacity : 0; + secondsPassed = 0; + wavesPassed = 0; + damage = 0; - //update sector's internal time spent counter - state.rules.sector.setTimeSpent(internalTimeSpent); + if(state.rules.sector != null){ + state.rules.sector.info = this; + state.rules.sector.saveInfo(); + } + + SectorDamage.writeParameters(this); } /** Update averages of various stats, updates some special sector logic. @@ -97,20 +169,6 @@ public class SectorInfo{ //updating in multiplayer as a client doesn't make sense if(net.client()) return; - internalTimeSpent += Time.delta; - - //autorun turns - if(internalTimeSpent >= turnDuration){ - internalTimeSpent = 0; - universe.runTurn(); - } - - //create last stored core items - if(lastCoreItems == null){ - lastCoreItems = new int[content.items().size]; - updateCoreDeltas(); - } - CoreBuild ent = state.rules.defaultTeam.core(); //refresh throughput @@ -124,15 +182,16 @@ public class SectorInfo{ stat.loaded = true; } - //how the resources changed - only interested in negative deltas, since that's what happens during spoofing - int coreDelta = Math.min(ent == null ? 0 : ent.items.get(item) - lastCoreItems[item.id], 0); - //add counter, subtract how many items were taken from the core during this time - stat.means.add(Math.max(stat.counter + coreDelta, 0)); + stat.means.add(Math.max(stat.counter, 0)); stat.counter = 0; stat.mean = stat.means.rawMean(); }); + if(coreItemCounts == null){ + coreItemCounts = new int[content.items().size]; + } + //refresh core items for(Item item : content.items()){ ExportStat stat = production.get(item, ExportStat::new); @@ -143,21 +202,14 @@ public class SectorInfo{ //get item delta //TODO is preventing negative production a good idea? - int delta = Math.max((ent == null ? 0 : ent.items.get(item)) - lastCoreItems[item.id], 0); + int delta = Math.max(ent == null ? 0 : coreItemCounts[item.id], 0); //store means stat.means.add(delta); stat.mean = stat.means.rawMean(); } - updateCoreDeltas(); - } - } - - private void updateCoreDeltas(){ - CoreBuild ent = state.rules.defaultTeam.core(); - for(int i = 0; i < lastCoreItems.length; i++){ - lastCoreItems[i] = ent == null ? 0 : ent.items.get(i); + Arrays.fill(coreItemCounts, 0); } } diff --git a/core/src/mindustry/game/SpawnGroup.java b/core/src/mindustry/game/SpawnGroup.java index fda8514d48..86ba7b6324 100644 --- a/core/src/mindustry/game/SpawnGroup.java +++ b/core/src/mindustry/game/SpawnGroup.java @@ -1,5 +1,6 @@ package mindustry.game; +import arc.util.*; import arc.util.serialization.*; import arc.util.serialization.Json.*; import mindustry.content.*; @@ -8,6 +9,8 @@ import mindustry.gen.*; import mindustry.io.legacy.*; import mindustry.type.*; +import java.util.*; + import static mindustry.Vars.*; /** @@ -27,7 +30,7 @@ public class SpawnGroup implements Serializable{ /** The spacing, in waves, of spawns. For example, 2 = spawns every other wave */ public int spacing = 1; /** Maximum amount of units that spawn */ - public int max = 100; + public int max = 40; /** How many waves need to pass before the amount of units spawned increases by 1 */ public float unitScaling = never; /** Shield points that this unit has. */ @@ -37,8 +40,10 @@ public class SpawnGroup implements Serializable{ /** Amount of enemies spawned initially, with no scaling */ public int unitAmount = 1; /** Status effect applied to the spawned unit. Null to disable. */ + @Nullable public StatusEffect effect; /** Items this unit spawns with. Null to disable. */ + @Nullable public ItemStack items; public SpawnGroup(UnitType type){ @@ -49,14 +54,20 @@ public class SpawnGroup implements Serializable{ //serialization use only } - /** Returns the amount of units spawned on a specific wave. */ - public int getUnitsSpawned(int wave){ + /** @return amount of units spawned on a specific wave. */ + public int getSpawned(int wave){ + if(spacing == 0) spacing = 1; if(wave < begin || wave > end || (wave - begin) % spacing != 0){ return 0; } return Math.min(unitAmount + (int)(((wave - begin) / spacing) / unitScaling), max); } + /** @return amount of shields each unit has at a specific wave. */ + public float getShield(int wave){ + return Math.max(shields + shieldScaling*(wave - begin), 0); + } + /** * Creates a unit, and assigns correct values based on this group's data. * This method does not add() the unit. @@ -72,7 +83,7 @@ public class SpawnGroup implements Serializable{ unit.addItem(items.item, items.amount); } - unit.shield(Math.max(shields + shieldScaling*(wave - begin), 0)); + unit.shield = getShield(wave); return unit; } @@ -84,12 +95,12 @@ public class SpawnGroup implements Serializable{ if(begin != 0) json.writeValue("begin", begin); if(end != never) json.writeValue("end", end); if(spacing != 1) json.writeValue("spacing", spacing); - //if(max != 40) json.writeValue("max", max); + if(max != 40) json.writeValue("max", max); if(unitScaling != never) json.writeValue("scaling", unitScaling); if(shields != 0) json.writeValue("shields", shields); if(shieldScaling != 0) json.writeValue("shieldScaling", shieldScaling); if(unitAmount != 1) json.writeValue("amount", unitAmount); - if(effect != null) json.writeValue("effect", effect.id); + if(effect != null) json.writeValue("effect", effect.name); } @Override @@ -101,12 +112,18 @@ public class SpawnGroup implements Serializable{ begin = data.getInt("begin", 0); end = data.getInt("end", never); spacing = data.getInt("spacing", 1); - //max = data.getInt("max", 40); + max = data.getInt("max", 40); unitScaling = data.getFloat("scaling", never); shields = data.getFloat("shields", 0); shieldScaling = data.getFloat("shieldScaling", 0); unitAmount = data.getInt("amount", 1); - effect = content.getByID(ContentType.status, data.getInt("effect", -1)); + + //old boss effect ID + if(data.has("effect") && data.get("effect").isNumber() && data.getInt("effect", -1) == 8){ + effect = StatusEffects.boss; + }else{ + effect = content.getByName(ContentType.status, data.has("effect") && data.get("effect").isString() ? data.getString("effect", "none") : "none"); + } } @Override @@ -123,4 +140,20 @@ public class SpawnGroup implements Serializable{ ", items=" + items + '}'; } + + @Override + public boolean equals(Object o){ + if(this == o) return true; + if(o == null || getClass() != o.getClass()) return false; + SpawnGroup group = (SpawnGroup)o; + return end == group.end && begin == group.begin && spacing == group.spacing && max == group.max + && Float.compare(group.unitScaling, unitScaling) == 0 && Float.compare(group.shields, shields) == 0 + && Float.compare(group.shieldScaling, shieldScaling) == 0 && unitAmount == group.unitAmount && + type == group.type && effect == group.effect && Structs.eq(items, group.items); + } + + @Override + public int hashCode(){ + return Arrays.hashCode(new Object[]{type, end, begin, spacing, max, unitScaling, shields, shieldScaling, unitAmount, effect, items}); + } } diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index 1ab345dc10..cbed06f4e7 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -31,9 +31,9 @@ public class Team implements Comparable{ Color.valueOf("ffd37f"), Color.valueOf("eab678"), Color.valueOf("d4816b")), crux = new Team(2, "crux", Color.valueOf("f25555"), Color.valueOf("fc8e6c"), Color.valueOf("f25555"), Color.valueOf("a04553")), - green = new Team(3, "green", Color.valueOf("4dd98b")), - purple = new Team(4, "purple", Color.valueOf("9a4bdf")), - blue = new Team(5, "blue", Color.royal.cpy()); + green = new Team(3, "green", Color.valueOf("54d67d")), + purple = new Team(4, "purple", Color.valueOf("995bb0")), + blue = new Team(5, "blue", Color.valueOf("5a4deb")); static{ Mathf.rand.setSeed(8); @@ -83,10 +83,6 @@ public class Team implements Comparable{ return state.rules.teams.get(this); } - public Team[] enemies(){ - return state.teams.enemiesOf(this); - } - public TeamData data(){ return state.teams.get(this); } diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index 60d36ee74e..6a2972f074 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -2,15 +2,20 @@ package mindustry.game; import arc.func.*; import arc.math.geom.*; +import arc.struct.Queue; import arc.struct.*; import arc.util.*; +import mindustry.*; import mindustry.ai.*; import mindustry.content.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.type.*; +import mindustry.world.blocks.payloads.*; import mindustry.world.blocks.storage.CoreBlock.*; +import java.util.*; + import static mindustry.Vars.*; /** Class for various team-based utilities. */ @@ -18,7 +23,9 @@ public class Teams{ /** Maps team IDs to team data. */ private TeamData[] map = new TeamData[256]; /** Active teams. */ - private Seq active = new Seq<>(); + public Seq active = new Seq<>(); + /** Teams with block or unit presence. */ + public Seq present = new Seq<>(TeamData.class); public Teams(){ active.add(get(Team.crux)); @@ -26,7 +33,7 @@ public class Teams{ @Nullable public CoreBuild closestEnemyCore(float x, float y, Team team){ - for(Team enemy : team.enemies()){ + for(Team enemy : team.data().coreEnemies){ CoreBuild tile = Geometry.findClosest(x, y, enemy.cores()); if(tile != null) return tile; } @@ -38,10 +45,6 @@ public class Teams{ return Geometry.findClosest(x, y, get(team).cores); } - public Team[] enemiesOf(Team team){ - return get(team).enemies; - } - public boolean eachEnemyCore(Team team, Boolf ret){ for(TeamData data : active){ if(areEnemies(team, data.team)){ @@ -67,9 +70,7 @@ public class Teams{ /** Returns team data by type. */ public TeamData get(Team team){ - if(map[team.id] == null){ - map[team.id] = new TeamData(team); - } + if(map[team.id] == null) map[team.id] = new TeamData(team); return map[team.id]; } @@ -129,6 +130,77 @@ public class Teams{ } } + private void count(Unit unit){ + unit.team.data().updateCount(unit.type, 1); + + if(unit instanceof Payloadc){ + ((Payloadc)unit).payloads().each(p -> { + if(p instanceof UnitPayload){ + count(((UnitPayload)p).unit); + } + }); + } + } + + public void updateTeamStats(){ + present.clear(); + + for(Team team : Team.all){ + TeamData data = team.data(); + + data.presentFlag = false; + data.unitCount = 0; + data.units.clear(); + if(data.tree != null){ + data.tree.clear(); + } + + if(data.typeCounts != null){ + Arrays.fill(data.typeCounts, 0); + } + + //clear old unit records + if(data.unitsByType != null){ + for(int i = 0; i < data.unitsByType.length; i++){ + if(data.unitsByType[i] != null){ + data.unitsByType[i].clear(); + } + } + } + } + + //update presence flag. + Groups.build.each( b -> b.team.data().presentFlag = true); + + for(Unit unit : Groups.unit){ + TeamData data = unit.team.data(); + data.tree().insert(unit); + data.units.add(unit); + data.presentFlag = true; + + if(data.unitsByType == null || data.unitsByType.length <= unit.type.id){ + data.unitsByType = new Seq[content.units().size]; + } + + if(data.unitsByType[unit.type.id] == null){ + data.unitsByType[unit.type.id] = new Seq<>(); + } + + data.unitsByType[unit.type.id].add(unit); + + count(unit); + } + + //update presence of each team. + for(Team team : Team.all){ + TeamData data = team.data(); + + if(data.presentFlag || data.active()){ + present.add(data); + } + } + } + private void updateEnemies(){ if(state.rules.waves && !active.contains(get(state.rules.waveTeam))){ active.add(get(state.rules.waveTeam)); @@ -143,16 +215,19 @@ public class Teams{ } } - data.enemies = enemies.toArray(Team.class); + data.coreEnemies = enemies.toArray(Team.class); } } - public class TeamData{ + public static class TeamData{ public final Seq cores = new Seq<>(); public final Team team; public final BaseAI ai; - public Team[] enemies = {}; + private boolean presentFlag; + + /** Enemies with cores or spawn points. */ + public Team[] coreEnemies = {}; /** Planned blocks for drones. This is usually only blocks that have been broken. */ public Queue blocks = new Queue<>(); /** The current command for units to follow. */ @@ -160,11 +235,48 @@ public class Teams{ /** Target items to mine. */ public Seq mineItems = Seq.with(Items.copper, Items.lead, Items.titanium, Items.thorium); + /** Total unit count. */ + public int unitCount; + /** Counts for each type of unit. Do not access directly. */ + @Nullable + public int[] typeCounts; + /** Quadtree for units of this type. Do not access directly. */ + @Nullable + public QuadTree tree; + /** Units of this team. Updated each frame. */ + public Seq units = new Seq<>(); + /** Units of this team by type. Updated each frame. */ + @Nullable + public Seq[] unitsByType; + public TeamData(Team team){ this.team = team; this.ai = new BaseAI(this); } + @Nullable + public Seq unitCache(UnitType type){ + if(unitsByType == null || unitsByType.length <= type.id || unitsByType[type.id] == null) return null; + return unitsByType[type.id]; + } + + public void updateCount(UnitType type, int amount){ + unitCount = Math.max(amount + unitCount, 0); + if(typeCounts == null || typeCounts.length <= type.id){ + typeCounts = new int[Vars.content.units().size]; + } + typeCounts [type.id] = Math.max(amount + typeCounts [type.id], 0); + } + + public QuadTree tree(){ + if(tree == null) tree = new QuadTree<>(Vars.world.getQuadBounds(new Rect())); + return tree; + } + + public int countType(UnitType type){ + return typeCounts == null || typeCounts.length <= type.id ? 0 : typeCounts[type.id]; + } + public boolean active(){ return (team == state.rules.waveTeam && state.rules.waves) || cores.size > 0; } diff --git a/core/src/mindustry/game/Universe.java b/core/src/mindustry/game/Universe.java index b2c9c7d039..9fa93eb840 100644 --- a/core/src/mindustry/game/Universe.java +++ b/core/src/mindustry/game/Universe.java @@ -6,6 +6,8 @@ import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.game.EventType.*; +import mindustry.io.legacy.*; +import mindustry.maps.*; import mindustry.type.*; import mindustry.world.blocks.storage.*; @@ -17,6 +19,7 @@ public class Universe{ private int netSeconds; private float secondCounter; private int turn; + private float turnCounter; private Schematic lastLoadout; private ItemSeq lastLaunchResources = new ItemSeq(); @@ -53,17 +56,19 @@ public class Universe{ } } - /** @return sectors attacked on the current planet, minus the ones that are being played on right now. */ - public Seq getAttacked(Planet planet){ - return planet.sectors.select(s -> s.hasWaves() && s.hasBase() && !s.isBeingPlayed() && s.getSecondsPassed() > 1); - } - /** Update planet rotations, global time and relevant state. */ public void update(){ //only update time when not in multiplayer if(!net.client()){ secondCounter += Time.delta / 60f; + turnCounter += Time.delta; + + //auto-run turns + if(turnCounter >= turnDuration){ + turnCounter = 0; + runTurn(); + } if(secondCounter >= 1){ seconds += (int)secondCounter; @@ -132,41 +137,81 @@ public class Universe{ //update relevant sectors for(Planet planet : content.planets()){ for(Sector sector : planet.sectors){ - if(sector.hasSave()){ - int spent = (int)(sector.getTimeSpent() / 60); - int actuallyPassed = Math.max(newSecondsPassed - spent, 0); + if(sector.hasSave() && sector.hasBase()){ //increment seconds passed for this sector by the time that just passed with this turn if(!sector.isBeingPlayed()){ - sector.setSecondsPassed(sector.getSecondsPassed() + actuallyPassed); + //increment time + sector.info.secondsPassed += turnDuration/60f; + + int wavesPassed = (int)(sector.info.secondsPassed*60f / sector.info.waveSpacing); + boolean attacked = sector.info.waves; + + if(attacked){ + sector.info.wavesPassed = wavesPassed; + } + + float damage = attacked ? SectorDamage.getDamage(sector.info) : 0f; + + //damage never goes down until the player visits the sector, so use max + sector.info.damage = Math.max(sector.info.damage, damage); //check if the sector has been attacked too many times... - if(sector.hasBase() && sector.hasWaves() && sector.getSecondsPassed() * 60f > turnDuration * sectorDestructionTurns){ + if(attacked && damage >= 0.999f){ //fire event for losing the sector Events.fire(new SectorLoseEvent(sector)); - //if so, just delete the save for now. it's lost. - //TODO don't delete it later maybe - sector.save.delete(); - //clear recieved - sector.setExtraItems(new ItemSeq()); - sector.save = null; + //sector is dead. + sector.info.items.clear(); + sector.info.damage = 1f; + sector.info.hasCore = false; + sector.info.production.clear(); + }else if(attacked && wavesPassed > 0 && sector.info.winWave > 1 && sector.info.wave + wavesPassed >= sector.info.winWave && !sector.hasEnemyBase()){ + //autocapture the sector + sector.info.waves = false; + + //fire the event + Events.fire(new SectorCaptureEvent(sector)); } + + float scl = sector.getProductionScale(); + + //export to another sector + if(sector.info.destination != null){ + Sector to = sector.info.destination; + if(to.hasBase()){ + ItemSeq items = new ItemSeq(); + //calculated exported items to this sector + sector.info.export.each((item, stat) -> items.add(item, (int)(stat.mean * newSecondsPassed * scl))); + to.addItems(items); + } + } + + //add production, making sure that it's capped + sector.info.production.each((item, stat) -> sector.info.items.add(item, Math.min((int)(stat.mean * newSecondsPassed * scl), sector.info.storageCapacity - sector.info.items.get(item)))); + + sector.saveInfo(); } - //export to another sector - if(sector.save != null && sector.save.meta != null && sector.save.meta.secinfo != null && sector.save.meta.secinfo.destination != null){ - Sector to = sector.save.meta.secinfo.destination; - if(to.save != null){ - ItemSeq items = to.getExtraItems(); - //calculated exported items to this sector - sector.save.meta.secinfo.export.each((item, stat) -> items.add(item, (int)(stat.mean * newSecondsPassed))); - to.setExtraItems(items); + //queue random invasions + if(!sector.isAttacked() && turn > invasionGracePeriod){ + //invasion chance depends on # of nearby bases + if(Mathf.chance(baseInvasionChance * sector.near().count(Sector::hasEnemyBase))){ + int waveMax = Math.max(sector.info.winWave, sector.isBeingPlayed() ? state.wave : 0) + Mathf.random(2, 5) * 5; + + //assign invasion-related things + if(sector.isBeingPlayed()){ + state.rules.winWave = waveMax; + state.rules.waves = true; + }else{ + sector.info.winWave = waveMax; + sector.info.waves = true; + sector.saveInfo(); + } + + Events.fire(new SectorInvasionEvent(sector)); } } - - //reset time spent to 0 - sector.setTimeSpent(0f); } } } @@ -183,7 +228,7 @@ public class Universe{ for(Planet planet : content.planets()){ for(Sector sector : planet.sectors){ if(sector.hasSave()){ - count.add(sector.calculateItems()); + count.add(sector.items()); } } } @@ -216,6 +261,10 @@ public class Universe{ private void load(){ seconds = Core.settings.getInt("utimei"); turn = Core.settings.getInt("turn"); + + if(Core.settings.has("unlocks")){ + LegacyIO.readResearch(); + } } } diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index a36230f0aa..7e90fba3ff 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -20,11 +20,14 @@ import static arc.Core.*; import static mindustry.Vars.*; public class BlockRenderer implements Disposable{ + public static final int crackRegions = 8, maxCrackSize = 9; + private static final int initialRequests = 32 * 32; private static final int expandr = 9; private static final Color shadowColor = new Color(0, 0, 0, 0.71f); public final FloorRenderer floor = new FloorRenderer(); + public TextureRegion[][] cracks; private Seq tileview = new Seq<>(false, initialRequests, Tile.class); private Seq lightview = new Seq<>(false, initialRequests, Tile.class); @@ -35,11 +38,20 @@ public class BlockRenderer implements Disposable{ private FrameBuffer dark = new FrameBuffer(); private Seq outArray2 = new Seq<>(); private Seq shadowEvents = new Seq<>(); - private IntSet processedEntities = new IntSet(), processedLinks = new IntSet(); + private IntSet procEntities = new IntSet(), procLinks = new IntSet(), procLights = new IntSet(); private boolean displayStatus = false; public BlockRenderer(){ + Events.on(ClientLoadEvent.class, e -> { + cracks = new TextureRegion[maxCrackSize][crackRegions]; + for(int size = 1; size <= maxCrackSize; size++){ + for(int i = 0; i < crackRegions; i++){ + cracks[size - 1][i] = Core.atlas.find("cracks-" + size + "-" + i); + } + } + }); + Events.on(WorldLoadEvent.class, event -> { shadowEvents.clear(); lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated @@ -179,8 +191,9 @@ public class BlockRenderer implements Disposable{ tileview.clear(); lightview.clear(); - processedEntities.clear(); - processedLinks.clear(); + procEntities.clear(); + procLinks.clear(); + procLights.clear(); int minx = Math.max(avgx - rangex - expandr, 0); int miny = Math.max(avgy - rangey - expandr, 0); @@ -197,25 +210,25 @@ public class BlockRenderer implements Disposable{ tile = tile.build.tile; } - if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !processedEntities.contains(tile.build.id))){ + if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !procEntities.contains(tile.build.id))){ if(block.expanded || !expanded){ - if(tile.build == null || processedLinks.add(tile.build.id)){ + if(tile.build == null || procLinks.add(tile.build.id)){ tileview.add(tile); if(tile.build != null){ - processedEntities.add(tile.build.id); - processedLinks.add(tile.build.id); + procEntities.add(tile.build.id); + procLinks.add(tile.build.id); } } } //lights are drawn even in the expanded range - if(tile.build != null || tile.block().emitLight){ + if(((tile.build != null && procLights.add(tile.build.pos())) || tile.block().emitLight)){ lightview.add(tile); } if(tile.build != null && tile.build.power != null && tile.build.power.links.size > 0){ for(Building other : tile.build.getPowerConnections(outArray2)){ - if(other.block instanceof PowerNode && processedLinks.add(other.id)){ //TODO need a generic way to render connections! + if(other.block instanceof PowerNode && procLinks.add(other.id)){ //TODO need a generic way to render connections! tileview.add(other.tile); } } @@ -223,7 +236,7 @@ public class BlockRenderer implements Disposable{ } //special case for floors - if(block == Blocks.air && tile.floor().emitLight){ + if((block == Blocks.air && tile.floor().emitLight) && procLights.add(tile.pos())){ lightview.add(tile); } } @@ -280,7 +293,7 @@ public class BlockRenderer implements Disposable{ entity.drawLight(); }else if(tile.block().emitLight){ tile.block().drawEnvironmentLight(tile); - }else if(tile.floor().emitLight){ + }else if(tile.floor().emitLight && !tile.block().solid && world.getDarkness(tile.x, tile.y) < 3){ //only draw floor light under non-solid blocks tile.floor().drawEnvironmentLight(tile); } } diff --git a/core/src/mindustry/graphics/CacheLayer.java b/core/src/mindustry/graphics/CacheLayer.java index 3174c5d2a4..b0273799e4 100644 --- a/core/src/mindustry/graphics/CacheLayer.java +++ b/core/src/mindustry/graphics/CacheLayer.java @@ -51,6 +51,17 @@ public enum CacheLayer{ endShader(Shaders.slag); } }, + space{ + @Override + public void begin(){ + beginShader(); + } + + @Override + public void end(){ + endShader(Shaders.space); + } + }, normal(5), walls(3); diff --git a/core/src/mindustry/graphics/LightRenderer.java b/core/src/mindustry/graphics/LightRenderer.java index 10ffa727b6..0a05c7409b 100644 --- a/core/src/mindustry/graphics/LightRenderer.java +++ b/core/src/mindustry/graphics/LightRenderer.java @@ -100,7 +100,6 @@ public class LightRenderer{ Draw.vert(ledge.texture, vertices, 0, vertices.length); - Vec2 v3 = Tmp.v2.trnsExact(rot, stroke); u = ledge.u; diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index cdb84e9044..b3c39bfa27 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -96,7 +96,7 @@ public class MinimapRenderer implements Disposable{ Draw.mixcol(unit.team().color, 1f); float scale = Scl.scl(1f) / 2f * scaling * 32f; - Draw.rect(unit.type().icon(Cicon.full), x + rx, y + ry, scale, scale, unit.rotation() - 90); + Draw.rect(unit.type.icon(Cicon.full), x + rx, y + ry, scale, scale, unit.rotation() - 90); Draw.reset(); //only disable player names in multiplayer @@ -158,7 +158,7 @@ public class MinimapRenderer implements Disposable{ private int colorFor(Tile tile){ if(tile == null) return 0; int bc = tile.block().minimapColor(tile); - Color color = Tmp.c1.set(bc == 0 ? MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), tile.team()) : bc); + Color color = Tmp.c1.set(bc == 0 ? MapIO.colorFor(tile.block(), tile.floor(), tile.overlay(), tile.team()) : bc); color.mul(1f - Mathf.clamp(world.getDarkness(tile.x, tile.y) / 4f)); return color.rgba(); diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index ea988e5e78..9bb3a95fa3 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -7,6 +7,7 @@ import arc.math.*; import arc.math.geom.*; import arc.util.*; import mindustry.*; +import mindustry.ai.types.*; import mindustry.gen.*; import mindustry.input.*; import mindustry.ui.*; @@ -84,7 +85,7 @@ public class OverlayRenderer{ //special selection for block "units" Fill.square(select.x, select.y, ((BlockUnitc)select).tile().block.size * tilesize/2f); }else{ - Draw.rect(select.type().icon(Cicon.full), select.x(), select.y(), select.rotation() - 90); + Draw.rect(select.type.icon(Cicon.full), select.x(), select.y(), select.rotation() - 90); } Lines.stroke(unitFade); @@ -120,10 +121,12 @@ public class OverlayRenderer{ Lines.stroke(2f); Draw.color(Color.gray, Color.lightGray, Mathf.absin(Time.time(), 8f, 1f)); - for(Tile tile : spawner.getSpawns()){ - if(tile.within(player.x, player.y, state.rules.dropZoneRadius + spawnerMargin)){ - Draw.alpha(Mathf.clamp(1f - (player.dst(tile) - state.rules.dropZoneRadius) / spawnerMargin)); - Lines.dashCircle(tile.worldx(), tile.worldy(), state.rules.dropZoneRadius); + if(state.hasSpawns()){ + for(Tile tile : spawner.getSpawns()){ + if(tile.within(player.x, player.y, state.rules.dropZoneRadius + spawnerMargin)){ + Draw.alpha(Mathf.clamp(1f - (player.dst(tile) - state.rules.dropZoneRadius) / spawnerMargin)); + Lines.dashCircle(tile.worldx(), tile.worldy(), state.rules.dropZoneRadius); + } } } @@ -151,6 +154,13 @@ public class OverlayRenderer{ input.drawOverSelect(); + if(ui.hudfrag.blockfrag.hover() instanceof Unit unit && unit.controller() instanceof LogicAI ai && ai.controller instanceof Building build){ + Drawf.square(build.x, build.y, build.block.size * tilesize/2f + 2f); + if(!unit.within(build, unit.hitSize * 2f)){ + Drawf.arrow(unit.x, unit.y, build.x, build.y, unit.hitSize *2f, 4f); + } + } + //draw selection overlay when dropping item if(input.isDroppingItem()){ Vec2 v = Core.input.mouseWorld(input.getMouseX(), input.getMouseY()); diff --git a/core/src/mindustry/graphics/Pal.java b/core/src/mindustry/graphics/Pal.java index 753bbbbbed..8bb3cd9e70 100644 --- a/core/src/mindustry/graphics/Pal.java +++ b/core/src/mindustry/graphics/Pal.java @@ -94,5 +94,7 @@ public class Pal{ redDust = Color.valueOf("ffa480"), redderDust = Color.valueOf("ff7b69"), - plasticSmoke = Color.valueOf("f1e479"); + plasticSmoke = Color.valueOf("f1e479"), + + adminChat = Color.valueOf("ff4000"); } diff --git a/core/src/mindustry/graphics/Shaders.java b/core/src/mindustry/graphics/Shaders.java index f1390b5884..cefb7b1bab 100644 --- a/core/src/mindustry/graphics/Shaders.java +++ b/core/src/mindustry/graphics/Shaders.java @@ -19,7 +19,7 @@ public class Shaders{ public static UnitBuild build; public static DarknessShader darkness; public static LightShader light; - public static SurfaceShader water, mud, tar, slag; + public static SurfaceShader water, mud, tar, slag, space; public static PlanetShader planet; public static PlanetGridShader planetGrid; public static AtmosphereShader atmosphere; @@ -44,6 +44,7 @@ public class Shaders{ mud = new SurfaceShader("mud"); tar = new SurfaceShader("tar"); slag = new SurfaceShader("slag"); + space = new SpaceShader("space"); planet = new PlanetShader(); planetGrid = new PlanetGridShader(); atmosphere = new AtmosphereShader(); @@ -196,6 +197,34 @@ public class Shaders{ } } + //seed: 8kmfuix03fw + public static class SpaceShader extends SurfaceShader{ + Texture texture; + + public SpaceShader(String frag){ + super(frag); + + Core.assets.load("sprites/space.png", Texture.class).loaded = t -> { + texture = (Texture)t; + texture.setFilter(TextureFilter.linear); + texture.setWrap(TextureWrap.mirroredRepeat); + }; + } + + @Override + public void apply(){ + setUniformf("u_campos", Core.camera.position.x, Core.camera.position.y); + setUniformf("u_ccampos", Core.camera.position); + setUniformf("u_resolution", Core.graphics.getWidth(), Core.graphics.getHeight()); + setUniformf("u_time", Time.time()); + + texture.bind(1); + renderer.effectBuffer.getTexture().bind(0); + + setUniformi("u_stars", 1); + } + } + public static class SurfaceShader extends LoadShader{ public SurfaceShader(String frag){ @@ -225,7 +254,7 @@ public class Shaders{ public static class LoadShader extends Shader{ public LoadShader(String frag, String vert){ - super(Core.files.internal("shaders/" + vert + ".vert").readString(), Core.files.internal("shaders/" + frag + ".frag").readString()); + super(Core.files.internal("shaders/" + vert + ".vert"), Core.files.internal("shaders/" + frag + ".frag")); } } } diff --git a/core/src/mindustry/graphics/g3d/PlanetGrid.java b/core/src/mindustry/graphics/g3d/PlanetGrid.java index e4972e3eb7..380f937658 100644 --- a/core/src/mindustry/graphics/g3d/PlanetGrid.java +++ b/core/src/mindustry/graphics/g3d/PlanetGrid.java @@ -22,15 +22,16 @@ public class PlanetGrid{ {5, 3, 10, 1, 4}, {2, 5, 4, 0, 11}, {3, 7, 6, 1, 8}, {7, 2, 9, 0, 6} }; - public final int size; - public final Ptile[] tiles; - public final Corner[] corners; - public final Edge[] edges; + public int size; + public Ptile[] tiles; + public Corner[] corners; + public Edge[] edges; - PlanetGrid(int size){ + //this is protected so if you want to make strange grids you should know what you're doing. + protected PlanetGrid(int size){ this.size = size; - tiles = new Ptile[Buildingount(size)]; + tiles = new Ptile[tileCount(size)]; for(int i = 0; i < tiles.length; i++){ tiles[i] = new Ptile(i, i < 12 ? 5 : 6); } @@ -67,7 +68,7 @@ public class PlanetGrid{ return result; } - static PlanetGrid initialGrid(){ + public static PlanetGrid initialGrid(){ PlanetGrid grid = new PlanetGrid(0); for(Ptile t : grid.tiles){ @@ -111,7 +112,7 @@ public class PlanetGrid{ return grid; } - static PlanetGrid subdividedGrid(PlanetGrid prev){ + public static PlanetGrid subdividedGrid(PlanetGrid prev){ PlanetGrid grid = new PlanetGrid(prev.size + 1); int prevTiles = prev.tiles.length; @@ -207,7 +208,7 @@ public class PlanetGrid{ return -1; } - static int Buildingount(int size){ + static int tileCount(int size){ return 10 * Mathf.pow(3, size) + 2; } @@ -220,12 +221,12 @@ public class PlanetGrid{ } public static class Ptile{ - public final int id; - public final int edgeCount; + public int id; + public int edgeCount; - public final Ptile[] tiles; - public final Corner[] corners; - public final Edge[] edges; + public Ptile[] tiles; + public Corner[] corners; + public Edge[] edges; public Vec3 v = new Vec3(); @@ -240,11 +241,11 @@ public class PlanetGrid{ } public static class Corner{ - public final int id; - public final Ptile[] tiles = new Ptile[3]; - public final Corner[] corners = new Corner[3]; - public final Edge[] edges = new Edge[3]; - public final Vec3 v = new Vec3(); + public int id; + public Ptile[] tiles = new Ptile[3]; + public Corner[] corners = new Corner[3]; + public Edge[] edges = new Edge[3]; + public Vec3 v = new Vec3(); public Corner(int id){ this.id = id; @@ -252,9 +253,9 @@ public class PlanetGrid{ } public static class Edge{ - public final int id; - public final Ptile[] tiles = new Ptile[2]; - public final Corner[] corners = new Corner[2]; + public int id; + public Ptile[] tiles = new Ptile[2]; + public Corner[] corners = new Corner[2]; public Edge(int id){ this.id = id; diff --git a/core/src/mindustry/graphics/g3d/PlanetRenderer.java b/core/src/mindustry/graphics/g3d/PlanetRenderer.java index e0e76c0cee..405d668333 100644 --- a/core/src/mindustry/graphics/g3d/PlanetRenderer.java +++ b/core/src/mindustry/graphics/g3d/PlanetRenderer.java @@ -10,6 +10,7 @@ import arc.math.geom.*; import arc.struct.*; import arc.util.*; import mindustry.content.*; +import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.graphics.g3d.PlanetGrid.*; import mindustry.type.*; @@ -23,10 +24,6 @@ public class PlanetRenderer implements Disposable{ shadowColor = new Color(0, 0, 0, 0.7f); private static final Seq points = new Seq<>(); - private static final PlanetInterfaceRenderer emptyRenderer = new PlanetInterfaceRenderer(){ - @Override public void renderSectors(Planet planet){} - @Override public void renderProjections(){} - }; /** Camera direction relative to the planet. Length is determined by zoom. */ public final Vec3 camPos = new Vec3(); @@ -42,19 +39,19 @@ public class PlanetRenderer implements Disposable{ public float zoom = 1f; private final Mesh[] outlines = new Mesh[10]; - private final PlaneBatch3D projector = new PlaneBatch3D(); - private final Mat3D mat = new Mat3D(); - private final FrameBuffer buffer = new FrameBuffer(2, 2, true); - private PlanetInterfaceRenderer irenderer; + public final PlaneBatch3D projector = new PlaneBatch3D(); + public final Mat3D mat = new Mat3D(); + public final FrameBuffer buffer = new FrameBuffer(2, 2, true); + public PlanetInterfaceRenderer irenderer; - private final Bloom bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false){{ + public final Bloom bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false){{ setThreshold(0.8f); blurPasses = 6; }}; - private final Mesh atmosphere = MeshBuilder.buildHex(Color.white, 2, false, 1.5f); + public final Mesh atmosphere = MeshBuilder.buildHex(Color.white, 2, false, 1.5f); //seed: 8kmfuix03fw - private final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/")); + public final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/")); public PlanetRenderer(){ camPos.set(0, 0f, camLength); @@ -86,14 +83,20 @@ public class PlanetRenderer implements Disposable{ projector.proj(cam.combined); batch.proj(cam.combined); + Events.fire(Trigger.universeDrawBegin); + beginBloom(); skybox.render(cam.combined); + Events.fire(Trigger.universeDraw); + renderPlanet(solarSystem); endBloom(); + Events.fire(Trigger.universeDrawEnd); + Gl.enable(Gl.blend); irenderer.renderProjections(); @@ -104,18 +107,21 @@ public class PlanetRenderer implements Disposable{ cam.update(); } - private void beginBloom(){ + public void beginBloom(){ bloom.resize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4); bloom.capture(); } - private void endBloom(){ + public void endBloom(){ bloom.render(); } - private void renderPlanet(Planet planet){ + + public void renderPlanet(Planet planet){ + if(!planet.visible()) return; + //render planet at offsetted position in the world - planet.mesh.render(cam.combined, planet.getTransform(mat)); + planet.draw(cam.combined, planet.getTransform(mat)); renderOrbit(planet); @@ -141,8 +147,8 @@ public class PlanetRenderer implements Disposable{ } } - private void renderOrbit(Planet planet){ - if(planet.parent == null) return; + public void renderOrbit(Planet planet){ + if(planet.parent == null || !planet.visible()) return; Vec3 center = planet.parent.position; float radius = planet.orbitRadius; @@ -151,7 +157,7 @@ public class PlanetRenderer implements Disposable{ batch.flush(Gl.lineLoop); } - private void renderSectors(Planet planet){ + public void renderSectors(Planet planet){ //apply transformed position batch.proj().mul(planet.getTransform(mat)); @@ -272,7 +278,7 @@ public class PlanetRenderer implements Disposable{ } } - private Mesh outline(int size){ + public Mesh outline(int size){ if(outlines[size] == null){ outlines[size] = MeshBuilder.buildHex(new HexMesher(){ @Override diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index 576e644ce6..049853c864 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -12,6 +12,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.*; +import mindustry.core.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.*; @@ -48,7 +49,7 @@ public class DesktopInput extends InputHandler{ public void buildUI(Group group){ group.fill(t -> { - t.visible(() -> Core.settings.getBool("hints") && ui.hudfrag.shown() && !player.dead() && !player.unit().spawnedByCore() && !(Core.settings.getBool("hints") && lastSchematic != null && !selectRequests.isEmpty())); + t.visible(() -> Core.settings.getBool("hints") && ui.hudfrag.shown && !player.dead() && !player.unit().spawnedByCore() && !(Core.settings.getBool("hints") && lastSchematic != null && !selectRequests.isEmpty())); t.bottom(); t.table(Styles.black6, b -> { b.defaults().left(); @@ -176,7 +177,7 @@ public class DesktopInput extends InputHandler{ public void update(){ super.update(); - if(net.active() && Core.input.keyTap(Binding.player_list) && (scene.getKeyboardFocus() == null || scene.getKeyboardFocus().isDescendantOf(ui.listfrag.content))){ + if(net.active() && Core.input.keyTap(Binding.player_list) && (scene.getKeyboardFocus() == null || scene.getKeyboardFocus().isDescendantOf(ui.listfrag.content) || scene.getKeyboardFocus().isDescendantOf(ui.minimapfrag.elem))){ ui.listfrag.toggle(); } @@ -352,9 +353,7 @@ public class DesktopInput extends InputHandler{ ui.planet.show(); }).visible(() -> state.isCampaign()).tooltip("@planetmap"); - table.button(Icon.up, Styles.clearPartiali, () -> { - ui.planet.showLaunch(state.getSector(), player.team().core()); - }).visible(() -> state.isCampaign()).tooltip("@launchcore").disabled(b -> player.team().core() == null); + table.add(); } void pollInput(){ @@ -363,7 +362,7 @@ public class DesktopInput extends InputHandler{ Tile selected = tileAt(Core.input.mouseX(), Core.input.mouseY()); int cursorX = tileX(Core.input.mouseX()); int cursorY = tileY(Core.input.mouseY()); - int rawCursorX = world.toTile(Core.input.mouseWorld().x), rawCursorY = world.toTile(Core.input.mouseWorld().y); + int rawCursorX = World.toTile(Core.input.mouseWorld().x), rawCursorY = World.toTile(Core.input.mouseWorld().y); // automatically pause building if the current build queue is empty if(Core.settings.getBool("buildautopause") && isBuilding && !player.builder().isBuilding()){ @@ -599,19 +598,19 @@ public class DesktopInput extends InputHandler{ } protected void updateMovement(Unit unit){ - boolean omni = unit.type().omniMovement; + boolean omni = unit.type.omniMovement; boolean ground = unit.isGrounded(); - float strafePenalty = ground ? 1f : Mathf.lerp(1f, unit.type().strafePenalty, Angles.angleDist(unit.vel().angle(), unit.rotation()) / 180f); - float baseSpeed = unit.type().speed; + float strafePenalty = ground ? 1f : Mathf.lerp(1f, unit.type.strafePenalty, Angles.angleDist(unit.vel().angle(), unit.rotation()) / 180f); + float baseSpeed = unit.type.speed; //limit speed to minimum formation speed to preserve formation - if(unit instanceof Commanderc && ((Commanderc)unit).isCommanding()){ + if(unit.isCommanding()){ //add a tiny multiplier to let units catch up just in case - baseSpeed = ((Commanderc)unit).minFormationSpeed() * 0.95f; + baseSpeed = unit.minFormationSpeed * 0.95f; } - float speed = baseSpeed * Mathf.lerp(1f, unit.type().canBoost ? unit.type().boostMultiplier : 1f, unit.elevation) * strafePenalty; + float speed = baseSpeed * Mathf.lerp(1f, unit.type.canBoost ? unit.type.boostMultiplier : 1f, unit.elevation) * strafePenalty; float xa = Core.input.axis(Binding.move_x); float ya = Core.input.axis(Binding.move_y); boolean boosted = (unit instanceof Mechc && unit.isFlying()); @@ -622,7 +621,7 @@ public class DesktopInput extends InputHandler{ } float mouseAngle = Angles.mouseAngle(unit.x, unit.y); - boolean aimCursor = omni && player.shooting && unit.type().hasWeapons() && unit.type().faceTarget && !boosted && unit.type().rotateShooting; + boolean aimCursor = omni && player.shooting && unit.type.hasWeapons() && unit.type.faceTarget && !boosted && unit.type.rotateShooting; if(aimCursor){ unit.lookAt(mouseAngle); @@ -637,11 +636,11 @@ public class DesktopInput extends InputHandler{ }else{ unit.moveAt(Tmp.v2.trns(unit.rotation, movement.len())); if(!movement.isZero() && ground){ - unit.vel.rotateTo(movement.angle(), unit.type().rotateSpeed); + unit.vel.rotateTo(movement.angle(), unit.type.rotateSpeed); } } - unit.aim(unit.type().faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation, Core.input.mouseWorld().dst(unit)).add(unit.x, unit.y)); + unit.aim(unit.type.faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation, Core.input.mouseWorld().dst(unit)).add(unit.x, unit.y)); unit.controlWeapons(true, player.shooting && !boosted); player.boosting = Core.input.keyDown(Binding.boost) && !movement.isZero(); @@ -660,11 +659,9 @@ public class DesktopInput extends InputHandler{ } } - //update commander inut - if(unit instanceof Commanderc){ - if(Core.input.keyTap(Binding.command)){ - Call.unitCommand(player); - } + //update commander unit + if(Core.input.keyTap(Binding.command)){ + Call.unitCommand(player); } } } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index d6e15127fc..adeb6d3c2b 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -16,6 +16,7 @@ import arc.util.*; import mindustry.ai.formations.patterns.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.entities.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; @@ -77,6 +78,19 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ createItemTransfer(item, 1, x, y, to, null); } + @Remote(called = Loc.server, unreliable = true) + public static void takeItems(Building build, Item item, int amount, Unit to){ + if(to == null || build == null) return; + + int removed = build.removeStack(item, Math.min(to.maxAccepted(item), amount)); + if(removed == 0) return; + + to.addItem(item, removed); + for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){ + Time.run(j * 3f, () -> Call.transferItemEffect(item, build.x, build.y, to)); + } + } + @Remote(called = Loc.server, unreliable = true) public static void transferItemToUnit(Item item, float x, float y, Itemsc to){ if(to == null) return; @@ -92,6 +106,16 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ build.items.add(item, amount); } + @Remote(called = Loc.server, unreliable = true) + public static void transferItemTo(Unit unit, Item item, int amount, float x, float y, Building build){ + if(build == null || build.items == null) return; + unit.stack.amount = Math.max(unit.stack.amount - amount, 0); + for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){ + Time.run(i * 3, () -> createItemTransfer(item, amount, x, y, build, () -> {})); + } + build.handleStack(item, amount, unit); + } + public static void createItemTransfer(Item item, int amount, float x, float y, Position to, Runnable done){ Fx.itemTransfer.at(x, y, amount, item.color, to); if(done != null){ @@ -99,6 +123,67 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } } + @Remote(called = Loc.server, targets = Loc.both, forward = true) + public static void requestItem(Player player, Building tile, Item item, int amount){ + if(player == null || tile == null || !tile.interactable(player.team()) || !player.within(tile, buildingRange) || player.dead()) return; + + if(net.server() && (!Units.canInteract(player, tile) || + !netServer.admins.allowAction(player, ActionType.withdrawItem, tile.tile(), action -> { + action.item = item; + action.itemAmount = amount; + }))) throw new ValidateException(player, "Player cannot request items."); + + //remove item for every controlling unit + player.unit().eachGroup(unit -> { + int removed = Math.min(unit.maxAccepted(item), tile.removeStack(item, amount)); + + unit.addItem(item, removed); + + for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){ + Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.x, tile.y, unit)); + } + + if(unit == player.unit()){ + Events.fire(new WithdrawEvent(tile, player, item, amount)); + } + }); + } + + @Remote(targets = Loc.both, forward = true, called = Loc.server) + public static void transferInventory(Player player, Building tile){ + if(player == null || tile == null || !player.within(tile, buildingRange) || tile.items == null || player.dead()) return; + + if(net.server() && (player.unit().stack.amount <= 0 || !Units.canInteract(player, tile) || + !netServer.admins.allowAction(player, ActionType.depositItem, tile.tile, action -> { + action.itemAmount = player.unit().stack.amount; + action.item = player.unit().item(); + }))){ + throw new ValidateException(player, "Player cannot transfer an item."); + } + + //deposit for every controlling unit + player.unit().eachGroup(unit -> { + Item item = unit.item(); + int accepted = tile.acceptStack(item, unit.stack.amount, unit); + unit.stack.amount -= accepted; + + tile.getStackOffset(item, stackTrns); + tile.handleStack(item, accepted, unit); + + createItemTransfer( + item, + accepted, + unit.x + Angles.trnsx(unit.rotation + 180f, backTrns), unit.y + Angles.trnsy(unit.rotation + 180f, backTrns), + new Vec2(tile.x + stackTrns.x, tile.y + stackTrns.y), + () -> {} + ); + + if(unit == player.unit()){ + Events.fire(new DepositEvent(tile, player, item, accepted)); + } + }); + } + @Remote(variants = Variant.one) public static void removeQueueBlock(int x, int y, boolean breaking){ player.builder().removeBuild(x, y, breaking); @@ -112,13 +197,13 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Payloadc pay = (Payloadc)unit; if(target.isAI() && target.isGrounded() && pay.canPickup(target) - && target.within(unit, unit.type().hitSize * 2f + target.type().hitSize * 2f)){ - Call.pickedUnitPayload(player, target); + && target.within(unit, unit.type.hitSize * 2f + target.type.hitSize * 2f)){ + Call.pickedUnitPayload(unit, target); } } @Remote(targets = Loc.both, called = Loc.server) - public static void requestBlockPayload(Player player, Building tile){ + public static void requestBuildPayload(Player player, Building tile){ if(player == null) return; Unit unit = player.unit(); @@ -128,57 +213,49 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ && unit.within(tile, tilesize * tile.block.size * 1.2f + tilesize * 5f)){ //pick up block directly if(tile.block.buildVisibility != BuildVisibility.hidden && tile.canPickup() && pay.canPickup(tile)){ - Call.pickedBlockPayload(player, tile, true); + Call.pickedBuildPayload(unit, tile, true); }else{ //pick up block payload Payload current = tile.getPayload(); if(current != null && pay.canPickupPayload(current)){ - Call.pickedBlockPayload(player, tile, false); + Call.pickedBuildPayload(unit, tile, false); } } } } @Remote(targets = Loc.server, called = Loc.server) - public static void pickedUnitPayload(Player player, Unit target){ - if(player == null || target == null || !(player.unit() instanceof Payloadc)){ - if(target != null){ - target.remove(); - } - return; + public static void pickedUnitPayload(Unit unit, Unit target){ + if(target != null && unit instanceof Payloadc pay){ + pay.pickup(target); + }else if(target != null){ + target.remove(); } - - ((Payloadc)player.unit()).pickup(target); } @Remote(targets = Loc.server, called = Loc.server) - public static void pickedBlockPayload(Player player, Building tile, boolean onGround){ - if(player == null || tile == null || !(player.unit() instanceof Payloadc)){ - if(tile != null && onGround){ - Fx.unitPickup.at(tile); - tile.tile.remove(); - } - return; - } - - Unit unit = player.unit(); - Payloadc pay = (Payloadc)unit; - - if(onGround){ - if(tile.block.buildVisibility != BuildVisibility.hidden && tile.canPickup() && pay.canPickup(tile)){ - pay.pickup(tile); - }else{ - Fx.unitPickup.at(tile); - tile.tile.remove(); - } - }else{ - Payload current = tile.getPayload(); - if(current != null && pay.canPickupPayload(current)){ - Payload taken = tile.takePayload(); - if(taken != null){ - pay.addPayload(taken); + public static void pickedBuildPayload(Unit unit, Building tile, boolean onGround){ + if(tile != null && unit instanceof Payloadc pay){ + if(onGround){ + if(tile.block.buildVisibility != BuildVisibility.hidden && tile.canPickup() && pay.canPickup(tile)){ + pay.pickup(tile); + }else{ Fx.unitPickup.at(tile); + tile.tile.remove(); + } + }else{ + Payload current = tile.getPayload(); + if(current != null && pay.canPickupPayload(current)){ + Payload taken = tile.takePayload(); + if(taken != null){ + pay.addPayload(taken); + Fx.unitPickup.at(tile); + } } } + + }else if(tile != null && onGround){ + Fx.unitPickup.at(tile); + tile.tile.remove(); } } @@ -192,19 +269,22 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Tmp.v1.set(x, y).sub(pay).limit(tilesize * 4f).add(pay); float cx = Tmp.v1.x, cy = Tmp.v1.y; - Call.payloadDropped(player, cx, cy); + Call.payloadDropped(player.unit(), cx, cy); } @Remote(called = Loc.server, targets = Loc.server) - public static void payloadDropped(Player player, float x, float y){ - if(player == null) return; - - Payloadc pay = (Payloadc)player.unit(); - - float prevx = pay.x(), prevy = pay.y(); - pay.set(x, y); - pay.dropLastPayload(); - pay.set(prevx, prevy); + public static void payloadDropped(Unit unit, float x, float y){ + if(unit instanceof Payloadc pay){ + float prevx = pay.x(), prevy = pay.y(); + pay.set(x, y); + pay.dropLastPayload(); + pay.set(prevx, prevy); + pay.controlling().each(u -> { + if(u instanceof Payloadc){ + Call.payloadDropped(u, u.x, u.y); + } + }); + } } @Remote(targets = Loc.client, called = Loc.server) @@ -220,7 +300,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } @Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true) - public static void rotateBlock(Player player, Building tile, boolean direction){ + public static void rotateBlock(@Nullable Player player, Building tile, boolean direction){ if(tile == null) return; if(net.server() && (!Units.canInteract(player, tile) || @@ -228,42 +308,12 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ throw new ValidateException(player, "Player cannot rotate a block."); } + if(player != null) tile.lastAccessed = player.name; tile.rotation = Mathf.mod(tile.rotation + Mathf.sign(direction), 4); tile.updateProximity(); tile.noSleep(); } - @Remote(targets = Loc.both, forward = true, called = Loc.server) - public static void transferInventory(Player player, Building tile){ - if(player == null || tile == null || !player.within(tile, buildingRange) || tile.items == null) return; - - if(net.server() && (player.unit().stack.amount <= 0 || !Units.canInteract(player, tile) || - !netServer.admins.allowAction(player, ActionType.depositItem, tile.tile, action -> { - action.itemAmount = player.unit().stack.amount; - action.item = player.unit().item(); - }))){ - throw new ValidateException(player, "Player cannot transfer an item."); - } - - Item item = player.unit().item(); - int amount = player.unit().stack.amount; - int accepted = tile.acceptStack(item, amount, player.unit()); - player.unit().stack.amount -= accepted; - - Core.app.post(() -> Events.fire(new DepositEvent(tile, player, item, accepted))); - - tile.getStackOffset(item, stackTrns); - tile.handleStack(item, accepted, player.unit()); - - createItemTransfer( - item, - amount, - player.x + Angles.trnsx(player.unit().rotation + 180f, backTrns), player.y + Angles.trnsy(player.unit().rotation + 180f, backTrns), - new Vec2(tile.x + stackTrns.x, tile.y + stackTrns.y), - () -> {} - ); - } - @Remote(targets = Loc.both, called = Loc.both, forward = true) public static void tileConfig(@Nullable Player player, Building tile, @Nullable Object value){ if(tile == null) return; @@ -324,13 +374,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ @Remote(targets = Loc.both, called = Loc.server, forward = true) public static void unitCommand(Player player){ - if(player == null || player.dead() || !(player.unit() instanceof Commanderc)) return; - - Commanderc commander = (Commanderc)player.unit(); + if(player == null || player.dead() || !(player.unit() instanceof Commanderc commander)) return; if(commander.isCommanding()){ commander.clearCommand(); - }else{ + }else if(player.unit().type.commandLimit > 0){ //TODO try out some other formations commander.commandNearby(new CircleFormation()); @@ -363,17 +411,17 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } if(player.shooting && !wasShooting && player.unit().hasWeapons() && state.rules.unitAmmo && player.unit().ammo <= 0){ - player.unit().type().weapons.first().noAmmoSound.at(player.unit()); + player.unit().type.weapons.first().noAmmoSound.at(player.unit()); } wasShooting = player.shooting; if(!player.dead()){ - controlledType = player.unit().type(); + controlledType = player.unit().type; } if(controlledType != null && player.dead()){ - Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type() == controlledType && !u.dead); + Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type == controlledType && !u.dead); if(unit != null){ Call.unitControl(player, unit); @@ -383,9 +431,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public void checkUnit(){ if(controlledType != null){ - Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type() == controlledType && !u.dead); + Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type == controlledType && !u.dead); if(unit == null && controlledType == UnitTypes.block){ - unit = world.buildWorld(player.x, player.y) instanceof ControlBlock ? ((ControlBlock)world.buildWorld(player.x, player.y)).unit() : null; + unit = world.buildWorld(player.x, player.y) instanceof ControlBlock cont && cont.canControl() ? cont.unit() : null; } if(unit != null){ @@ -400,17 +448,16 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public void tryPickupPayload(){ Unit unit = player.unit(); - if(!(unit instanceof Payloadc)) return; - Payloadc pay = (Payloadc)unit; + if(!(unit instanceof Payloadc pay)) return; - Unit target = Units.closest(player.team(), pay.x(), pay.y(), unit.type().hitSize * 2.5f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f)); + Unit target = Units.closest(player.team(), pay.x(), pay.y(), unit.type.hitSize * 2.5f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f)); if(target != null){ Call.requestUnitPayload(player, target); }else{ Building tile = world.buildWorld(pay.x(), pay.y()); if(tile != null && tile.team == unit.team){ - Call.requestBlockPayload(player, tile); + Call.requestBuildPayload(player, tile); } } } @@ -498,6 +545,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ }); }else{ lastSchematic.tags.put("name", text); + lastSchematic.tags.put("description", ""); schematics.add(lastSchematic); ui.showInfoFade("@schematic.saved"); ui.schematics.showInfo(lastSchematic); @@ -533,8 +581,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ wx = wy; wy = -x; } - req.x = world.toTile(wx - req.block.offset) + ox; - req.y = world.toTile(wy - req.block.offset) + oy; + req.x = World.toTile(wx - req.block.offset) + ox; + req.y = World.toTile(wy - req.block.offset) + oy; req.rotation = Mathf.mod(req.rotation + direction, 4); }); } @@ -899,11 +947,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } int rawTileX(){ - return world.toTile(Core.input.mouseWorld().x); + return World.toTile(Core.input.mouseWorld().x); } int rawTileY(){ - return world.toTile(Core.input.mouseWorld().y); + return World.toTile(Core.input.mouseWorld().y); } int tileX(float cursorX){ @@ -911,7 +959,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ if(selectedBlock()){ vec.sub(block.offset, block.offset); } - return world.toTile(vec.x); + return World.toTile(vec.x); } int tileY(float cursorY){ @@ -919,7 +967,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ if(selectedBlock()){ vec.sub(block.offset, block.offset); } - return world.toTile(vec.y); + return World.toTile(vec.y); } public boolean selectedBlock(){ @@ -949,8 +997,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } Building tile = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y); - if(tile instanceof ControlBlock && tile.team == player.team()){ - return ((ControlBlock)tile).unit(); + if(tile instanceof ControlBlock cont && cont.canControl() && tile.team == player.team()){ + return cont.unit(); } return null; diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 07b543c704..63df6c151b 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -14,6 +14,7 @@ import arc.struct.*; import arc.util.*; import mindustry.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.entities.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; @@ -23,6 +24,7 @@ import mindustry.graphics.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; +import mindustry.world.blocks.*; import static mindustry.Vars.*; import static mindustry.input.PlaceMode.*; @@ -60,10 +62,15 @@ public class MobileInput extends InputHandler implements GestureListener{ public Block lastBlock; /** Last placed request. Used for drawing block overlay. */ public BuildPlan lastPlaced; - /** Down tracking for panning.*/ + /** Down tracking for panning. */ public boolean down = false; + /** Whether manual shooting (point with finger) is enabled. */ + public boolean manualShooting = false; - public Teamc target, moveTarget; + /** Current thing being shot at. */ + public Teamc target; + /** Payload target being moved to. Can be a position (for dropping), or a unit/block. */ + public Position payloadTarget; //region utility methods @@ -80,7 +87,7 @@ public class MobileInput extends InputHandler implements GestureListener{ if(tile != null && player.team().isEnemy(tile.team)){ player.miner().mineTile(null); target = tile; - }else if(tile != null && player.unit().type().canHeal && tile.team == player.team() && tile.damaged()){ + }else if(tile != null && player.unit().type.canHeal && tile.team == player.team() && tile.damaged()){ player.miner().mineTile(null); target = tile; } @@ -360,7 +367,7 @@ public class MobileInput extends InputHandler implements GestureListener{ } //draw targeting crosshair - if(target != null && !state.isEditor()){ + if(target != null && !state.isEditor() && !manualShooting){ if(target != lastTarget){ crosshairScale = 0f; lastTarget = target; @@ -400,14 +407,14 @@ public class MobileInput extends InputHandler implements GestureListener{ protected int schemOriginX(){ Tmp.v1.setZero(); selectRequests.each(r -> Tmp.v1.add(r.drawx(), r.drawy())); - return world.toTile(Tmp.v1.scl(1f / selectRequests.size).x); + return World.toTile(Tmp.v1.scl(1f / selectRequests.size).x); } @Override protected int schemOriginY(){ Tmp.v1.setZero(); selectRequests.each(r -> Tmp.v1.add(r.drawx(), r.drawy())); - return world.toTile(Tmp.v1.scl(1f / selectRequests.size).y); + return World.toTile(Tmp.v1.scl(1f / selectRequests.size).y); } @Override @@ -474,6 +481,7 @@ public class MobileInput extends InputHandler implements GestureListener{ down = false; } + manualShooting = false; selecting = false; //place down a line if in line mode @@ -517,12 +525,31 @@ public class MobileInput extends InputHandler implements GestureListener{ //handle long tap when player isn't building if(mode == none){ + Vec2 pos = Core.input.mouseWorld(x, y); - //control a unit/block - Unit on = selectedUnit(); - if(on != null){ - Call.unitControl(player, on); + if(player.unit() instanceof Payloadc pay){ + Unit target = Units.closest(player.team(), pos.x, pos.y, 8f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(pos, u.hitSize + 8f)); + if(target != null){ + payloadTarget = target; + }else{ + Building build = world.buildWorld(pos.x, pos.y); + + if(build != null && build.team == player.team() && pay.canPickup(build)){ + payloadTarget = build; + }else if(pay.hasPayload()){ + //drop off at position + payloadTarget = new Vec2(pos); + }else{ + manualShooting = true; + this.target = null; + } + } + }else{ + manualShooting = true; + this.target = null; } + + if(!state.isPaused()) Fx.select.at(pos); }else{ //ignore off-screen taps @@ -581,17 +608,18 @@ public class MobileInput extends InputHandler implements GestureListener{ tryBeginMine(cursor); } - //apply command on double tap - if(count == 2 && Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize * 2f)){ - if(player.unit() instanceof Commanderc){ + //control units. + if(count == 2){ + //reset payload target + payloadTarget = null; + //apply command on double tap when own unit is tapped + if(Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize * 0.6f + 8f)){ Call.unitCommand(player); - } - - if(player.unit() instanceof Payloadc){ - if(((Payloadc)player.unit()).hasPayload()){ - tryDropPayload(); - }else{ - tryPickupPayload(); + }else{ + //control a unit/block + Unit on = selectedUnit(); + if(on != null){ + Call.unitControl(player, on); } } } @@ -608,10 +636,14 @@ public class MobileInput extends InputHandler implements GestureListener{ selectRequests.clear(); removals.clear(); mode = none; + manualShooting = false; + payloadTarget = null; } if(player.dead()){ mode = none; + manualShooting = false; + payloadTarget = null; } //zoom camera @@ -752,7 +784,8 @@ public class MobileInput extends InputHandler implements GestureListener{ return false; } - if(!down) return false; + //do not pan with manual shooting enabled + if(!down || manualShooting) return false; if(selecting){ //pan all requests shiftDeltaX += deltaX; @@ -803,11 +836,10 @@ public class MobileInput extends InputHandler implements GestureListener{ protected void updateMovement(Unit unit){ Rect rect = Tmp.r3; - UnitType type = unit.type(); + UnitType type = unit.type; if(type == null) return; - boolean flying = type.flying; - boolean omni = unit.type().omniMovement; + boolean omni = unit.type.omniMovement; boolean legs = unit.isGrounded(); boolean allowHealing = type.canHeal; boolean validHealTarget = allowHealing && target instanceof Building && ((Building)target).isValid() && target.team() == unit.team && @@ -825,12 +857,12 @@ public class MobileInput extends InputHandler implements GestureListener{ float attractDst = 15f; float strafePenalty = legs ? 1f : Mathf.lerp(1f, type.strafePenalty, Angles.angleDist(unit.vel.angle(), unit.rotation) / 180f); - float baseSpeed = unit.type().speed; + float baseSpeed = unit.type.speed; //limit speed to minimum formation speed to preserve formation - if(unit instanceof Commanderc && ((Commanderc)unit).isCommanding()){ + if(unit.isCommanding()){ //add a tiny multiplier to let units catch up just in case - baseSpeed = ((Commanderc)unit).minFormationSpeed() * 0.98f; + baseSpeed = unit.minFormationSpeed * 0.98f; } float speed = baseSpeed * Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, unit.elevation) * strafePenalty; @@ -847,14 +879,26 @@ public class MobileInput extends InputHandler implements GestureListener{ } } - if(moveTarget != null){ - targetPos.set(moveTarget); + if(payloadTarget != null && unit instanceof Payloadc pay){ + targetPos.set(payloadTarget); attractDst = 0f; - if(unit.within(moveTarget, 2f * Time.delta)){ - handleTapTarget(moveTarget); - moveTarget = null; + if(unit.within(payloadTarget, 3f * Time.delta)){ + if(payloadTarget instanceof Vec2 && pay.hasPayload()){ + //vec -> dropping something + tryDropPayload(); + }else if(payloadTarget instanceof Building build && pay.canPickup(build)){ + //building -> picking building up + Call.requestBuildPayload(player, build); + }else if(payloadTarget instanceof Unit other && pay.canPickup(other)){ + //unit -> picking unit up + Call.requestUnitPayload(player, other); + } + + payloadTarget = null; } + }else{ + payloadTarget = null; } movement.set(targetPos).sub(player).limit(speed); @@ -887,10 +931,13 @@ public class MobileInput extends InputHandler implements GestureListener{ //update shooting if not building + not mining if(!player.builder().isBuilding() && player.miner().mineTile() == null){ - //autofire - if(target == null){ + //autofire targeting + if(manualShooting){ + player.shooting = !boosted; + unit.aim(player.mouseX = Core.input.mouseWorldX(), player.mouseY = Core.input.mouseWorldY()); + }else if(target == null){ player.shooting = false; - if(Core.settings.getBool("autotarget")){ + if(Core.settings.getBool("autotarget") && !(player.unit() instanceof BlockUnitUnit u && u.tile() instanceof ControlBlock c && !c.shouldAutoTarget())){ target = Units.closestTarget(unit.team, unit.x, unit.y, range, u -> u.team != Team.derelict, u -> u.team != Team.derelict); if(allowHealing && target == null){ @@ -899,11 +946,9 @@ public class MobileInput extends InputHandler implements GestureListener{ target = null; } } - - if(target != null && player.isMiner()){ - player.miner().mineTile(null); - } } + + unit.aim(Tmp.v1.trns(unit.rotation, 1000f).add(unit)); }else{ Vec2 intercept = Predict.intercept(unit, target, bulletSpeed); @@ -913,16 +958,10 @@ public class MobileInput extends InputHandler implements GestureListener{ unit.aim(player.mouseX, player.mouseY); } - } unit.controlWeapons(player.shooting && !boosted); } - - protected void handleTapTarget(Teamc target){ - - } - //endregion } diff --git a/core/src/mindustry/io/JsonIO.java b/core/src/mindustry/io/JsonIO.java index 39c3a1a821..eb3815ba76 100644 --- a/core/src/mindustry/io/JsonIO.java +++ b/core/src/mindustry/io/JsonIO.java @@ -165,6 +165,18 @@ public class JsonIO{ } }); + json.setSerializer(UnitType.class, new Serializer<>(){ + @Override + public void write(Json json, UnitType object, Class knownType){ + json.writeValue(object.name); + } + + @Override + public UnitType read(Json json, JsonValue jsonData, Class type){ + return Vars.content.getByName(ContentType.unit, jsonData.asString()); + } + }); + json.setSerializer(ItemStack.class, new Serializer<>(){ @Override public void write(Json json, ItemStack object, Class knownType){ diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index f88ebf9a37..f964e2c933 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -80,7 +80,7 @@ public class MapIO{ @Override public void setBlock(Block type){ super.setBlock(type); - int c = colorFor(Blocks.air, block(), Blocks.air, team()); + int c = colorFor(block(), Blocks.air, Blocks.air, team()); if(c != black){ walls.draw(x, floors.getHeight() - 1 - y, c); floors.draw(x, floors.getHeight() - 1 - y + 1, shade); @@ -119,7 +119,7 @@ public class MapIO{ if(overlayID != 0){ floors.draw(x, floors.getHeight() - 1 - y, colorFor(Blocks.air, Blocks.air, content.block(overlayID), Team.derelict)); }else{ - floors.draw(x, floors.getHeight() - 1 - y, colorFor(content.block(floorID), Blocks.air, Blocks.air, Team.derelict)); + floors.draw(x, floors.getHeight() - 1 - y, colorFor(Blocks.air, content.block(floorID), Blocks.air, Team.derelict)); } if(content.block(overlayID) == Blocks.spawn){ map.spawns ++; @@ -141,17 +141,17 @@ public class MapIO{ for(int x = 0; x < pixmap.getWidth(); x++){ for(int y = 0; y < pixmap.getHeight(); y++){ Tile tile = tiles.getn(x, y); - pixmap.draw(x, pixmap.getHeight() - 1 - y, colorFor(tile.floor(), tile.block(), tile.overlay(), tile.team())); + pixmap.draw(x, pixmap.getHeight() - 1 - y, colorFor(tile.block(), tile.floor(), tile.overlay(), tile.team())); } } return pixmap; } - public static int colorFor(Block floor, Block wall, Block ore, Team team){ + public static int colorFor(Block wall, Block floor, Block overlay, Team team){ if(wall.synthetic()){ return team.color.rgba(); } - return (wall.solid ? wall.mapColor : ore == Blocks.air ? floor.mapColor : ore.mapColor).rgba(); + return (wall.solid ? wall.mapColor : !overlay.useColor ? floor.mapColor : overlay.mapColor).rgba(); } public static Pixmap writeImage(Tiles tiles){ diff --git a/core/src/mindustry/io/SaveMeta.java b/core/src/mindustry/io/SaveMeta.java index f2e039f634..c6133889bc 100644 --- a/core/src/mindustry/io/SaveMeta.java +++ b/core/src/mindustry/io/SaveMeta.java @@ -14,12 +14,10 @@ public class SaveMeta{ public Map map; public int wave; public Rules rules; - public SectorInfo secinfo; public StringMap tags; public String[] mods; - public boolean hasProduction; - public SaveMeta(int version, long timestamp, long timePlayed, int build, String map, int wave, Rules rules, SectorInfo secinfo, StringMap tags){ + public SaveMeta(int version, long timestamp, long timePlayed, int build, String map, int wave, Rules rules, StringMap tags){ this.version = version; this.build = build; this.timestamp = timestamp; @@ -29,8 +27,5 @@ public class SaveMeta{ this.rules = rules; this.tags = tags; this.mods = JsonIO.read(String[].class, tags.get("mods", "[]")); - this.secinfo = secinfo; - - secinfo.production.each((e, amount) -> hasProduction |= amount.mean > 0.001f); } } diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index cacac7700a..b76a5156e8 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -40,7 +40,6 @@ public abstract class SaveVersion extends SaveFileReader{ map.get("mapname"), map.getInt("wave"), JsonIO.read(Rules.class, map.get("rules", "{}")), - JsonIO.read(SectorInfo.class, map.get("secinfo", "{}")), map ); } @@ -74,6 +73,7 @@ public abstract class SaveVersion extends SaveFileReader{ //prepare campaign data for writing if(state.isCampaign()){ state.secinfo.prepare(); + state.rules.sector.saveInfo(); } //flush tech node progress @@ -89,7 +89,6 @@ public abstract class SaveVersion extends SaveFileReader{ "wave", state.wave, "wavetime", state.wavetime, "stats", JsonIO.write(state.stats), - "secinfo", state.isCampaign() ? JsonIO.write(state.secinfo) : "{}", "rules", JsonIO.write(state.rules), "mods", JsonIO.write(mods.getModStrings().toArray(String.class)), "width", world.width(), @@ -106,15 +105,14 @@ public abstract class SaveVersion extends SaveFileReader{ state.wave = map.getInt("wave"); state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing); - state.stats = JsonIO.read(Stats.class, map.get("stats", "{}")); - state.secinfo = JsonIO.read(SectorInfo.class, map.get("secinfo", "{}")); + state.stats = JsonIO.read(GameStats.class, map.get("stats", "{}")); state.rules = JsonIO.read(Rules.class, map.get("rules", "{}")); if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get(); lastReadBuild = map.getInt("build", -1); - //load time spent on sector into state + //load in sector info if(state.rules.sector != null){ - state.secinfo.internalTimeSpent = state.rules.sector.getStoredTimeSpent(); + state.secinfo = state.rules.sector.info; } if(!headless){ diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 1fcf1a232f..2c2c19dcfc 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -37,64 +37,61 @@ public class TypeIO{ public static void writeObject(Writes write, Object object){ if(object == null){ write.b((byte)0); - }else if(object instanceof Integer){ + }else if(object instanceof Integer i){ write.b((byte)1); - write.i((Integer)object); - }else if(object instanceof Long){ + write.i(i); + }else if(object instanceof Long l){ write.b((byte)2); - write.l((Long)object); - }else if(object instanceof Float){ + write.l(l); + }else if(object instanceof Float f){ write.b((byte)3); - write.f((Float)object); - }else if(object instanceof String){ + write.f(f); + }else if(object instanceof String s){ write.b((byte)4); - writeString(write, (String)object); - }else if(object instanceof Content){ - Content map = (Content)object; + writeString(write, s); + }else if(object instanceof Content map){ write.b((byte)5); write.b((byte)map.getContentType().ordinal()); write.s(map.id); - }else if(object instanceof IntSeq){ + }else if(object instanceof IntSeq arr){ write.b((byte)6); - IntSeq arr = (IntSeq)object; write.s((short)arr.size); for(int i = 0; i < arr.size; i++){ write.i(arr.items[i]); } - }else if(object instanceof Point2){ + }else if(object instanceof Point2 p){ write.b((byte)7); - write.i(((Point2)object).x); - write.i(((Point2)object).y); - }else if(object instanceof Point2[]){ + write.i(p.x); + write.i(p.y); + }else if(object instanceof Point2[] p){ write.b((byte)8); - write.b(((Point2[])object).length); - for(int i = 0; i < ((Point2[])object).length; i++){ - write.i(((Point2[])object)[i].pack()); + write.b(p.length); + for(Point2 point2 : p){ + write.i(point2.pack()); } - }else if(object instanceof TechNode){ - TechNode map = (TechNode)object; + }else if(object instanceof TechNode map){ write.b(9); write.b((byte)map.content.getContentType().ordinal()); write.s(map.content.id); - }else if(object instanceof Boolean){ + }else if(object instanceof Boolean b){ write.b((byte)10); - write.bool((Boolean)object); - }else if(object instanceof Double){ + write.bool(b); + }else if(object instanceof Double d){ write.b((byte)11); - write.d((Double)object); - }else if(object instanceof Building){ - write.b((byte)12); - write.i(((Building)object).pos()); - }else if(object instanceof LAccess){ + write.d(d); + }else if(object instanceof Building b){ + write.b(12); + write.i(b.pos()); + }else if(object instanceof LAccess l){ write.b((byte)13); - write.s(((LAccess)object).ordinal()); - }else if(object instanceof byte[]){ + write.s(l.ordinal()); + }else if(object instanceof byte[] b){ write.b((byte)14); - write.i(((byte[])object).length); - write.b((byte[])object); - }else if(object instanceof UnitCommand){ + write.i(b.length); + write.b(b); + }else if(object instanceof UnitCommand c){ write.b((byte)15); - write.b(((UnitCommand)object).ordinal()); + write.b(c.ordinal()); }else{ throw new IllegalArgumentException("Unknown object type: " + object.getClass()); } @@ -188,7 +185,7 @@ public class TypeIO{ return unit == null ? Nulls.unit : unit; }else if(type == 1){ //block Building tile = world.build(id); - return tile instanceof ControlBlock ? ((ControlBlock)tile).unit() : Nulls.unit; + return tile instanceof ControlBlock cont ? cont.unit() : Nulls.unit; } return Nulls.unit; } @@ -293,12 +290,15 @@ public class TypeIO{ public static void writeController(Writes write, UnitController control){ //no real unit controller state is written, only the type - if(control instanceof Player){ + if(control instanceof Player p){ write.b(0); - write.i(((Player)control).id); - }else if(control instanceof FormationAI){ + write.i(p.id); + }else if(control instanceof FormationAI form){ write.b(1); - write.i(((FormationAI)control).leader.id); + write.i(form.leader.id); + }else if(control instanceof LogicAI logic && logic.controller != null){ + write.b(3); + write.i(logic.controller.pos()); }else{ write.b(2); } @@ -315,6 +315,19 @@ public class TypeIO{ }else if(type == 1){ //formation controller int id = read.i(); return prev instanceof FormationAI ? prev : new FormationAI(Groups.unit.getByID(id), null); + }else if(type == 3){ + int pos = read.i(); + if(prev instanceof LogicAI pai){ + pai.controller = world.build(pos); + return pai; + }else{ + //create new AI for assignment + LogicAI out = new LogicAI(); + //instantly time out when updated. + out.controlTimer = LogicAI.logicControlTimeout; + out.controller = world.build(pos); + return out; + } }else{ //there are two cases here: //1: prev controller was not a player, carry on @@ -437,6 +450,16 @@ public class TypeIO{ return color.set(read.i()); } + public static void writeContent(Writes write, Content cont){ + write.b(cont.getContentType().ordinal()); + write.s(cont.id); + } + + public static Content readContent(Reads read){ + byte id = read.b(); + return content.getByID(ContentType.all[id], read.s()); + } + public static void writeLiquid(Writes write, Liquid liquid){ write.s(liquid == null ? -1 : liquid.id); } diff --git a/core/src/mindustry/io/legacy/LegacyIO.java b/core/src/mindustry/io/legacy/LegacyIO.java index 545487d8ca..15cb756081 100644 --- a/core/src/mindustry/io/legacy/LegacyIO.java +++ b/core/src/mindustry/io/legacy/LegacyIO.java @@ -2,6 +2,8 @@ package mindustry.io.legacy; import arc.*; import arc.struct.*; +import mindustry.*; +import mindustry.ctype.*; import mindustry.ui.dialogs.JoinDialog.*; import java.io.*; @@ -48,4 +50,35 @@ public class LegacyIO{ return arr; } + public static void readResearch(){ + try{ + byte[] bytes = Core.settings.getBytes("unlocks"); + DataInputStream stream = new DataInputStream(new ByteArrayInputStream(bytes)); + + int length = stream.readInt(); + if(length > 0){ + stream.readUTF(); //name of key type + stream.readUTF(); //name of value type + + //each element is an array list + for(int i = 0; i < length; i++){ + ContentType type = ContentType.all[stream.readInt()]; + int arrLength = stream.readInt(); + if(arrLength > 0){ + stream.readUTF(); //type of contents (String) + for(int j = 0; j < arrLength; j++){ + String name = stream.readUTF(); + Content out = Vars.content.getByName(type, name); + if(out instanceof UnlockableContent u){ + u.quietUnlock(); + } + } + } + } + } + }catch(Exception e){ + e.printStackTrace(); + } + } + } diff --git a/core/src/mindustry/logic/Controllable.java b/core/src/mindustry/logic/Controllable.java index 31baf31a1e..025559b4b9 100644 --- a/core/src/mindustry/logic/Controllable.java +++ b/core/src/mindustry/logic/Controllable.java @@ -1,6 +1,10 @@ package mindustry.logic; +import mindustry.game.*; + /** An object that can be controlled with logic. */ public interface Controllable{ void control(LAccess type, double p1, double p2, double p3, double p4); + void control(LAccess type, Object p1, double p2, double p3, double p4); + Team team(); } diff --git a/core/src/mindustry/logic/LAccess.java b/core/src/mindustry/logic/LAccess.java index 2b7f0b1908..0d678554d1 100644 --- a/core/src/mindustry/logic/LAccess.java +++ b/core/src/mindustry/logic/LAccess.java @@ -5,6 +5,7 @@ import arc.struct.*; /** Setter/getter enum for logic-controlled objects. */ public enum LAccess{ totalItems, + firstItem, totalLiquids, totalPower, itemCapacity, @@ -14,6 +15,8 @@ public enum LAccess{ powerNetCapacity, powerNetIn, powerNetOut, + ammo, + ammoCapacity, health, maxHealth, heat, @@ -26,21 +29,34 @@ public enum LAccess{ shooting, team, type, + flag, + name, + config, + payloadCount, + payloadType, //values with parameters are considered controllable enabled("to"), //"to" is standard for single parameter access shoot("x", "y", "shoot"), + shootp(true, "unit", "shoot") ; - public final String[] parameters; + public final String[] params; + public final boolean isObj; public static final LAccess[] all = values(), - senseable = Seq.select(all, t -> t.parameters.length <= 1).toArray(LAccess.class), - controls = Seq.select(all, t -> t.parameters.length > 0).toArray(LAccess.class); + senseable = Seq.select(all, t -> t.params.length <= 1).toArray(LAccess.class), + controls = Seq.select(all, t -> t.params.length > 0).toArray(LAccess.class); - LAccess(String... parameters){ - this.parameters = parameters; + LAccess(String... params){ + this.params = params; + isObj = false; + } + + LAccess(boolean obj, String... params){ + this.params = params; + isObj = obj; } } diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java index 10ccbfe1b9..57c2004320 100644 --- a/core/src/mindustry/logic/LAssembler.java +++ b/core/src/mindustry/logic/LAssembler.java @@ -4,6 +4,7 @@ import arc.func.*; import arc.struct.*; import arc.util.*; import mindustry.*; +import mindustry.content.*; import mindustry.gen.*; import mindustry.logic.LExecutor.*; import mindustry.logic.LStatements.*; @@ -21,8 +22,14 @@ public class LAssembler{ LInstruction[] instructions; public LAssembler(){ + //instruction counter putVar("@counter").value = 0; + //unix timestamp putConst("@time", 0); + //currently controlled unit + putConst("@unit", null); + //reference to self + putConst("@this", null); //add default constants putConst("false", 0); @@ -45,6 +52,15 @@ public class LAssembler{ } } + //used as a special value for any environmental solid block + putConst("@solid", Blocks.stoneWall); + + putConst("@air", Blocks.air); + + for(UnitType type : Vars.content.units()){ + putConst("@" + type.name, type); + } + //store sensor constants for(LAccess sensor : LAccess.all){ @@ -173,16 +189,28 @@ public class LAssembler{ return putConst("___" + symbol, symbol.substring(1, symbol.length() - 1).replace("\\n", "\n")).id; } + //remove spaces for non-strings + symbol = symbol.replace(' ', '_'); + try{ - double value = Double.parseDouble(symbol); + double value = parseDouble(symbol); + if(Double.isNaN(value) || Double.isInfinite(value)) value = 0; + //this creates a hidden const variable with the specified value - String key = "___" + value; - return putConst(key, value).id; + return putConst("___" + value, value).id; }catch(NumberFormatException e){ return putVar(symbol).id; } } + double parseDouble(String symbol) throws NumberFormatException{ + //parse hex/binary syntax + if(symbol.startsWith("0b")) return Long.parseLong(symbol.substring(2), 2); + if(symbol.startsWith("0x")) return Long.parseLong(symbol.substring(2), 16); + + return Double.parseDouble(symbol); + } + /** Adds a constant value by name. */ public BVar putConst(String name, Object value){ BVar var = putVar(name); diff --git a/core/src/mindustry/logic/LCanvas.java b/core/src/mindustry/logic/LCanvas.java index ed98bee8ff..e16aab6621 100644 --- a/core/src/mindustry/logic/LCanvas.java +++ b/core/src/mindustry/logic/LCanvas.java @@ -305,7 +305,7 @@ public class LCanvas extends Table{ statements.finishLayout(); } }); - }).growX(); + }).growX().height(38); row(); diff --git a/core/src/mindustry/logic/LCategory.java b/core/src/mindustry/logic/LCategory.java index b576261f74..849e2f64bd 100644 --- a/core/src/mindustry/logic/LCategory.java +++ b/core/src/mindustry/logic/LCategory.java @@ -7,7 +7,8 @@ public enum LCategory{ blocks(Pal.accentBack), control(Color.cyan.cpy().shiftSaturation(-0.6f).mul(0.7f)), operations(Pal.place.cpy().shiftSaturation(-0.5f).mul(0.7f)), - io(Pal.remove.cpy().shiftSaturation(-0.5f).mul(0.7f)); + io(Pal.remove.cpy().shiftSaturation(-0.5f).mul(0.7f)), + units(Pal.bulletYellowBack.cpy().shiftSaturation(-0.3f).mul(0.8f)); public final Color color; diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index ad5936a3d3..a10cd2d0b2 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -1,16 +1,25 @@ package mindustry.logic; +import arc.math.geom.*; import arc.struct.*; import arc.util.*; import arc.util.noise.*; import mindustry.*; +import mindustry.ai.types.*; +import mindustry.content.*; +import mindustry.core.*; import mindustry.ctype.*; import mindustry.entities.*; import mindustry.game.*; +import mindustry.game.Teams.*; import mindustry.gen.*; +import mindustry.type.*; +import mindustry.world.*; import mindustry.world.blocks.logic.LogicDisplay.*; import mindustry.world.blocks.logic.MemoryBlock.*; import mindustry.world.blocks.logic.MessageBlock.*; +import mindustry.world.blocks.payloads.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -23,7 +32,9 @@ public class LExecutor{ //special variables public static final int varCounter = 0, - varTime = 1; + varTime = 1, + varUnit = 2, + varThis = 3; public static final int maxGraphicsBuffer = 256, @@ -36,6 +47,8 @@ public class LExecutor{ public LongSeq graphicsBuffer = new LongSeq(); public StringBuilder textBuffer = new StringBuilder(); public Building[] links = {}; + public IntSet linkIds = new IntSet(); + public Team team = Team.derelict; public boolean initialized(){ return instructions != null && vars != null && instructions.length > 0; @@ -99,17 +112,26 @@ public class LExecutor{ public double num(int index){ Var v = vars[index]; - return v.isobj ? v.objval != null ? 1 : 0 : v.numval; + return v.isobj ? v.objval != null ? 1 : 0 : Double.isNaN(v.numval) || Double.isInfinite(v.numval) ? 0 : v.numval; + } + + public float numf(int index){ + Var v = vars[index]; + return v.isobj ? v.objval != null ? 1 : 0 : Double.isNaN(v.numval) || Double.isInfinite(v.numval) ? 0 : (float)v.numval; } public int numi(int index){ return (int)num(index); } + public void setbool(int index, boolean value){ + setnum(index, value ? 1 : 0); + } + public void setnum(int index, double value){ Var v = vars[index]; if(v.constant) return; - v.numval = value; + v.numval = Double.isNaN(value) || Double.isInfinite(value) ? 0 : value; v.objval = null; v.isobj = false; } @@ -121,6 +143,12 @@ public class LExecutor{ v.isobj = true; } + public void setconst(int index, Object value){ + Var v = vars[index]; + v.objval = value; + v.isobj = true; + } + //endregion public static class Var{ @@ -142,6 +170,329 @@ public class LExecutor{ void run(LExecutor exec); } + /** Binds the processor to a unit based on some filters. */ + public static class UnitBindI implements LInstruction{ + public int type; + + //iteration index + private int index; + + public UnitBindI(int type){ + this.type = type; + } + + public UnitBindI(){ + } + + @Override + public void run(LExecutor exec){ + + //binding to `null` was previously possible, but was too powerful and exploitable + if(exec.obj(type) instanceof UnitType type){ + Seq seq = exec.team.data().unitCache(type); + + if(seq != null && seq.any()){ + index %= seq.size; + if(index < seq.size){ + //bind to the next unit + exec.setconst(varUnit, seq.get(index)); + } + index ++; + }else{ + //no units of this type found + exec.setconst(varUnit, null); + } + }else{ + exec.setconst(varUnit, null); + } + } + } + + /** Uses a unit to find something that may not be in its range. */ + public static class UnitLocateI implements LInstruction{ + public LLocate locate = LLocate.building; + public BlockFlag flag = BlockFlag.core; + public int enemy, ore; + public int outX, outY, outFound, outBuild; + + public UnitLocateI(LLocate locate, BlockFlag flag, int enemy, int ore, int outX, int outY, int outFound, int outBuild){ + this.locate = locate; + this.flag = flag; + this.enemy = enemy; + this.ore = ore; + this.outX = outX; + this.outY = outY; + this.outFound = outFound; + } + + public UnitLocateI(){ + } + + @Override + public void run(LExecutor exec){ + Object unitObj = exec.obj(varUnit); + LogicAI ai = UnitControlI.checkLogicAI(exec, unitObj); + + if(unitObj instanceof Unit unit && ai != null){ + ai.controlTimer = LogicAI.logicControlTimeout; + + Cache cache = (Cache)ai.execCache.get(this, Cache::new); + + if(ai.checkTargetTimer(this)){ + Tile res = null; + boolean build = false; + + switch(locate){ + case ore -> { + if(exec.obj(ore) instanceof Item item){ + res = indexer.findClosestOre(unit.x, unit.y, item); + } + } + case building -> { + res = Geometry.findClosest(unit.x, unit.y, exec.bool(enemy) ? indexer.getEnemy(unit.team, flag) : indexer.getAllied(unit.team, flag)); + build = true; + } + case spawn -> { + res = Geometry.findClosest(unit.x, unit.y, Vars.spawner.getSpawns()); + } + case damaged -> { + Building b = Units.findDamagedTile(unit.team, unit.x, unit.y); + res = b == null ? null : b.tile; + build = true; + } + } + + if(res != null && (!build || res.build != null)){ + cache.found = true; + //set result if found + exec.setnum(outX, cache.x = World.conv(build ? res.build.x : res.worldx())); + exec.setnum(outY, cache.y = World.conv(build ? res.build.y : res.worldy())); + exec.setnum(outFound, 1); + }else{ + cache.found = false; + exec.setnum(outFound, 0); + } + exec.setobj(outFound, res != null && res.build != null && res.build.team == exec.team ? res.build : null); + }else{ + exec.setbool(outFound, cache.found); + exec.setnum(outX, cache.x); + exec.setnum(outY, cache.y); + } + } + } + + static class Cache{ + float x, y; + boolean found; + } + } + + /** Controls the unit based on some parameters. */ + public static class UnitControlI implements LInstruction{ + public LUnitControl type = LUnitControl.move; + public int p1, p2, p3, p4; + + public UnitControlI(LUnitControl type, int p1, int p2, int p3, int p4){ + this.type = type; + this.p1 = p1; + this.p2 = p2; + this.p3 = p3; + this.p4 = p4; + } + + public UnitControlI(){ + } + + /** Checks is a unit is valid for logic AI control, and returns the controller. */ + @Nullable + public static LogicAI checkLogicAI(LExecutor exec, Object unitObj){ + if(unitObj instanceof Unit unit && exec.obj(varUnit) == unit && unit.team == exec.team && !unit.isPlayer() && !(unit.controller() instanceof FormationAI)){ + if(!(unit.controller() instanceof LogicAI)){ + unit.controller(new LogicAI()); + ((LogicAI)unit.controller()).controller = exec.building(varThis); + + //clear old state + if(unit instanceof Minerc miner){ + miner.mineTile(null); + } + + if(unit instanceof Builderc builder){ + builder.clearBuilding(); + } + + return (LogicAI)unit.controller(); + } + return (LogicAI)unit.controller(); + } + return null; + } + + @Override + public void run(LExecutor exec){ + Object unitObj = exec.obj(varUnit); + LogicAI ai = checkLogicAI(exec, unitObj); + + //only control standard AI units + if(unitObj instanceof Unit unit && ai != null){ + ai.controlTimer = LogicAI.logicControlTimeout; + float x1 = World.unconv(exec.numf(p1)), y1 = World.unconv(exec.numf(p2)), d1 = World.unconv(exec.numf(p3)); + + switch(type){ + case move, stop, approach -> { + ai.control = type; + ai.moveX = x1; + ai.moveY = y1; + if(type == LUnitControl.approach){ + ai.moveRad = d1; + } + + //stop mining/building + if(type == LUnitControl.stop){ + if(unit instanceof Minerc miner){ + miner.mineTile(null); + } + if(unit instanceof Builderc build){ + build.clearBuilding(); + } + } + } + case within -> { + exec.setnum(p4, unit.within(x1, y1, d1) ? 1 : 0); + } + case pathfind -> { + ai.control = type; + } + case target -> { + ai.posTarget.set(x1, y1); + ai.aimControl = type; + ai.mainTarget = null; + ai.shoot = exec.bool(p3); + } + case targetp -> { + ai.aimControl = type; + ai.mainTarget = exec.obj(p1) instanceof Teamc t ? t : null; + ai.shoot = exec.bool(p2); + } + case boost -> { + ai.boost = exec.bool(p1); + } + case flag -> { + unit.flag = exec.num(p1); + } + case mine -> { + Tile tile = world.tileWorld(x1, y1); + if(unit instanceof Minerc miner){ + miner.mineTile(miner.validMine(tile) ? tile : null); + } + } + case payDrop -> { + if(ai.payTimer > 0) return; + + if(unit instanceof Payloadc pay && pay.hasPayload()){ + Call.payloadDropped(unit, unit.x, unit.y); + ai.payTimer = LogicAI.transferDelay; + } + } + case payTake -> { + if(ai.payTimer > 0) return; + + if(unit instanceof Payloadc pay){ + //units + if(exec.bool(p1)){ + Unit result = Units.closest(unit.team, unit.x, unit.y, unit.type.hitSize * 2f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f)); + + if(result != null){ + Call.pickedUnitPayload(unit, result); + } + }else{ //buildings + Building tile = world.buildWorld(unit.x, unit.y); + + //TODO copy pasted code + if(tile != null && tile.team == unit.team){ + if(tile.block.buildVisibility != BuildVisibility.hidden && tile.canPickup() && pay.canPickup(tile)){ + Call.pickedBuildPayload(unit, tile, true); + }else{ //pick up block payload + Payload current = tile.getPayload(); + if(current != null && pay.canPickupPayload(current)){ + Call.pickedBuildPayload(unit, tile, false); + } + } + } + } + ai.payTimer = LogicAI.transferDelay; + } + } + case build -> { + if(unit instanceof Builderc builder && exec.obj(p3) instanceof Block block){ + int x = World.toTile(x1), y = World.toTile(y1); + int rot = exec.numi(p4); + + //reset state of last request when necessary + if(ai.plan.x != x || ai.plan.y != y || ai.plan.block != block || builder.plans().isEmpty()){ + ai.plan.progress = 0; + ai.plan.initialized = false; + ai.plan.stuck = false; + } + + ai.plan.set(x, y, rot, block); + ai.plan.config = null; + + builder.clearBuilding(); + + if(ai.plan.tile() != null){ + builder.updateBuilding(true); + builder.addBuild(ai.plan); + } + } + } + case getBlock -> { + float range = Math.max(unit.range(), buildingRange); + if(!unit.within(x1, y1, range)){ + exec.setobj(p3, null); + exec.setobj(p4, null); + }else{ + Tile tile = world.tileWorld(x1, y1); + //any environmental solid block is returned as StoneWall, aka "@solid" + Block block = tile == null ? null : !tile.synthetic() ? (tile.solid() ? Blocks.stoneWall : Blocks.air) : tile.block(); + exec.setobj(p3, block); + exec.setobj(p4, tile != null && tile.build != null ? tile.build : null); + } + } + case itemDrop -> { + if(ai.itemTimer > 0) return; + + Building build = exec.building(p1); + int amount = exec.numi(p2); + int dropped = Math.min(unit.stack.amount, amount); + if(build != null && dropped > 0 && unit.within(build, logicItemTransferRange)){ + int accepted = build.acceptStack(unit.item(), dropped, unit); + if(accepted > 0){ + Call.transferItemTo(unit, unit.item(), accepted, unit.x, unit.y, build); + ai.itemTimer = LogicAI.transferDelay; + } + } + } + case itemTake -> { + if(ai.itemTimer > 0) return; + + Building build = exec.building(p1); + int amount = exec.numi(p3); + + if(build != null && build.items != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange)){ + int taken = Math.min(build.items.get(item), Math.min(amount, unit.maxAccepted(item))); + + if(taken > 0){ + Call.takeItems(build, item, taken, unit); + ai.itemTimer = LogicAI.transferDelay; + } + } + } + default -> {} + } + } + } + } + /** Controls a building's state. */ public static class ControlI implements LInstruction{ public int target; @@ -162,9 +513,12 @@ public class LExecutor{ @Override public void run(LExecutor exec){ Object obj = exec.obj(target); - if(obj instanceof Controllable){ - Controllable cont = (Controllable)obj; - cont.control(type, exec.num(p1), exec.num(p2), exec.num(p3), exec.num(p4)); + if(obj instanceof Building b && b.team == exec.team && exec.linkIds.contains(b.id)){ + if(type.isObj){ + b.control(type, exec.obj(p1), exec.num(p2), exec.num(p3), exec.num(p4)); + }else{ + b.control(type, exec.num(p1), exec.num(p2), exec.num(p3), exec.num(p4)); + } } } } @@ -205,8 +559,7 @@ public class LExecutor{ int address = exec.numi(position); Building from = exec.building(target); - if(from instanceof MemoryBuild){ - MemoryBuild mem = (MemoryBuild)from; + if(from instanceof MemoryBuild mem){ exec.setnum(output, address < 0 || address >= mem.memory.length ? 0 : mem.memory[address]); } @@ -230,8 +583,7 @@ public class LExecutor{ int address = exec.numi(position); Building from = exec.building(target); - if(from instanceof MemoryBuild){ - MemoryBuild mem = (MemoryBuild)from; + if(from instanceof MemoryBuild mem){ if(address >= 0 && address < mem.memory.length){ mem.memory[address] = exec.num(value); @@ -258,8 +610,8 @@ public class LExecutor{ Object target = exec.obj(from); Object sense = exec.obj(type); - if(target instanceof Senseable){ - Senseable se = (Senseable)target; + //TODO should remote enemy buildings be senseable? + if(target instanceof Senseable se){ if(sense instanceof Content){ exec.setnum(to, se.sense(((Content)sense))); }else if(sense instanceof LAccess){ @@ -307,16 +659,20 @@ public class LExecutor{ @Override public void run(LExecutor exec){ - Building target = exec.building(radar); + Object base = exec.obj(radar); int sortDir = exec.bool(sortOrder) ? 1 : -1; + LogicAI ai = null; - if(target instanceof Ranged){ - float range = ((Ranged)target).range(); + if(base instanceof Ranged r && r.team() == exec.team && + (base instanceof Building || (ai = UnitControlI.checkLogicAI(exec, base)) != null)){ //must be a building or a controllable unit + float range = r.range(); Healthc targeted; - if(timer.get(30f)){ + //timers update on a fixed 30 tick interval + //units update on a special timer per controller instance + if((base instanceof Building && timer.get(30f)) || (ai != null && ai.checkTargetTimer(this))){ //if any of the targets involve enemies boolean enemies = target1 == RadarTarget.enemy || target2 == RadarTarget.enemy || target3 == RadarTarget.enemy; @@ -324,11 +680,14 @@ public class LExecutor{ bestValue = 0; if(enemies){ - for(Team enemy : state.teams.enemiesOf(target.team)){ - find(target, range, sortDir, enemy); + Seq data = state.teams.present; + for(int i = 0; i < data.size; i++){ + if(data.items[i].team != r.team()){ + find(r, range, sortDir, data.items[i].team); + } } }else{ - find(target, range, sortDir, target.team); + find(r, range, sortDir, r.team()); } lastTarget = targeted = best; @@ -342,14 +701,14 @@ public class LExecutor{ } } - void find(Building b, float range, int sortDir, Team team){ - Units.nearby(team, b.x, b.y, range, u -> { + void find(Ranged b, float range, int sortDir, Team team){ + Units.nearby(team, b.x(), b.y(), range, u -> { if(!u.within(b, range)) return; boolean valid = - target1.func.get(b.team, u) && - target2.func.get(b.team, u) && - target3.func.get(b.team, u); + target1.func.get(b.team(), u) && + target2.func.get(b.team(), u) && + target3.func.get(b.team(), u); if(!valid) return; @@ -383,7 +742,7 @@ public class LExecutor{ v.objval = f.objval; v.isobj = true; }else{ - v.numval = f.numval; + v.numval = Double.isNaN(f.numval) || Double.isInfinite(f.numval) ? 0 : f.numval; v.isobj = false; } } @@ -483,8 +842,7 @@ public class LExecutor{ if(Vars.headless) return; Building build = exec.building(target); - if(build instanceof LogicDisplayBuild){ - LogicDisplayBuild d = (LogicDisplayBuild)build; + if(build instanceof LogicDisplayBuild d){ if(d.commands.size + exec.graphicsBuffer.size < maxDisplayBuffer){ for(int i = 0; i < exec.graphicsBuffer.size; i++){ d.commands.addLast(exec.graphicsBuffer.items[i]); @@ -546,8 +904,7 @@ public class LExecutor{ public void run(LExecutor exec){ Building build = exec.building(target); - if(build instanceof MessageBuild){ - MessageBuild d = (MessageBuild)build; + if(build instanceof MessageBuild d){ d.message.setLength(0); d.message.append(exec.textBuffer, 0, Math.min(exec.textBuffer.length(), maxTextBuffer)); diff --git a/core/src/mindustry/logic/LLocate.java b/core/src/mindustry/logic/LLocate.java new file mode 100644 index 0000000000..84da2321f9 --- /dev/null +++ b/core/src/mindustry/logic/LLocate.java @@ -0,0 +1,10 @@ +package mindustry.logic; + +public enum LLocate{ + ore, + building, + spawn, + damaged; + + public static final LLocate[] all = values(); +} diff --git a/core/src/mindustry/logic/LStatement.java b/core/src/mindustry/logic/LStatement.java index 3f2f6fd413..9fdc6407ef 100644 --- a/core/src/mindustry/logic/LStatement.java +++ b/core/src/mindustry/logic/LStatement.java @@ -31,6 +31,10 @@ public abstract class LStatement{ return read.size == 0 ? null : read.first(); } + public boolean hidden(){ + return false; + } + //protected methods are only for internal UI layout utilities protected Cell field(Table table, String value, Cons setter){ @@ -38,9 +42,9 @@ public abstract class LStatement{ .size(144f, 40f).pad(2f).color(table.color).addInputDialog(); } - protected void fields(Table table, String desc, String value, Cons setter){ + protected Cell fields(Table table, String desc, String value, Cons setter){ table.add(desc).padLeft(10).left(); - field(table, value, setter).width(85f).padRight(10).left(); + return field(table, value, setter).width(85f).padRight(10).left(); } protected void fields(Table table, String value, Cons setter){ @@ -87,8 +91,8 @@ public abstract class LStatement{ hitter.fillParent = true; hitter.tapped(hide); - Core.scene.add(hitter); + Core.scene.add(hitter); Core.scene.add(t); t.update(() -> { @@ -102,6 +106,8 @@ public abstract class LStatement{ b.localToStageCoordinates(Tmp.v1.set(b.getWidth()/2f, b.getHeight()/2f)); t.setPosition(Tmp.v1.x, Tmp.v1.y, Align.center); + if(t.getWidth() > Core.scene.getWidth()) t.setWidth(Core.graphics.getWidth()); + if(t.getHeight() > Core.scene.getHeight()) t.setHeight(Core.graphics.getHeight()); t.keepInStage(); }); t.actions(Actions.alpha(0), Actions.fadeIn(0.3f, Interp.fade)); diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index 2ce318f4a7..517d53bcc6 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -12,6 +12,7 @@ import mindustry.logic.LCanvas.*; import mindustry.logic.LExecutor.*; import mindustry.type.*; import mindustry.ui.*; +import mindustry.world.meta.*; import static mindustry.world.blocks.logic.LogicDisplay.*; @@ -347,9 +348,9 @@ public class LStatements{ //Q: why don't you just use arrays for this? //A: arrays aren't as easy to serialize so the code generator doesn't handle them int c = 0; - for(int i = 0; i < type.parameters.length; i++){ + for(int i = 0; i < type.params.length; i++){ - fields(table, type.parameters[i], i == 0 ? p1 : i == 1 ? p2 : i == 2 ? p3 : p4, i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : i == 2 ? v -> p3 = v : v -> p4 = v); + fields(table, type.params[i], i == 0 ? p1 : i == 1 ? p2 : i == 2 ? p3 : p4, i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : i == 2 ? v -> p3 = v : v -> p4 = v); if(++c % 2 == 0) row(table); } @@ -376,11 +377,13 @@ public class LStatements{ public void build(Table table){ table.defaults().left(); - table.add(" from "); + if(buildFrom()){ + table.add(" from "); - fields(table, radar, v -> radar = v); + fields(table, radar, v -> radar = v); - row(table); + row(table); + } for(int i = 0; i < 3; i++){ int fi = i; @@ -420,6 +423,10 @@ public class LStatements{ fields(table, output, v -> output = v); } + public boolean buildFrom(){ + return true; + } + @Override public LCategory category(){ return LCategory.blocks; @@ -694,4 +701,223 @@ public class LStatements{ return LCategory.control; } } + + @RegisterStatement("ubind") + public static class UnitBindStatement extends LStatement{ + public String type = "@poly"; + + @Override + public void build(Table table){ + table.add(" type "); + + TextField field = field(table, type, str -> type = str).get(); + + table.button(b -> { + b.image(Icon.pencilSmall); + b.clicked(() -> showSelectTable(b, (t, hide) -> { + t.row(); + t.table(i -> { + i.left(); + int c = 0; + for(UnitType item : Vars.content.units()){ + if(!item.unlockedNow() || item.isHidden()) continue; + i.button(new TextureRegionDrawable(item.icon(Cicon.small)), Styles.cleari, () -> { + type = "@" + item.name; + field.setText(type); + hide.run(); + }).size(40f).get().resizeImage(Cicon.small.size); + + if(++c % 6 == 0) i.row(); + } + }).colspan(3).width(240f).left(); + })); + }, Styles.logict, () -> {}).size(40f).padLeft(-2).color(table.color); + } + + @Override + public LCategory category(){ + return LCategory.units; + } + + @Override + public LInstruction build(LAssembler builder){ + return new UnitBindI(builder.var(type)); + } + } + + @RegisterStatement("ucontrol") + public static class UnitControlStatement extends LStatement{ + public LUnitControl type = LUnitControl.move; + public String p1 = "0", p2 = "0", p3 = "0", p4 = "0"; + + @Override + public void build(Table table){ + rebuild(table); + } + + void rebuild(Table table){ + table.clearChildren(); + + table.left(); + + table.add(" "); + + table.button(b -> { + b.label(() -> type.name()); + b.clicked(() -> showSelect(b, LUnitControl.all, type, t -> { + type = t; + rebuild(table); + }, 2, cell -> cell.size(120, 50))); + }, Styles.logict, () -> {}).size(120, 40).color(table.color).left().padLeft(2); + + row(table); + + //Q: why don't you just use arrays for this? + //A: arrays aren't as easy to serialize so the code generator doesn't handle them + int c = 0; + for(int i = 0; i < type.params.length; i++){ + + fields(table, type.params[i], i == 0 ? p1 : i == 1 ? p2 : i == 2 ? p3 : p4, i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : i == 2 ? v -> p3 = v : v -> p4 = v).width(110f); + + if(++c % 2 == 0) row(table); + } + } + + @Override + public LCategory category(){ + return LCategory.units; + } + + @Override + public LInstruction build(LAssembler builder){ + return new UnitControlI(type, builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4)); + } + } + + @RegisterStatement("uradar") + public static class UnitRadarStatement extends RadarStatement{ + + @Override + public boolean buildFrom(){ + //do not build the "from" section + return false; + } + + @Override + public LCategory category(){ + return LCategory.units; + } + + @Override + public LInstruction build(LAssembler builder){ + return new RadarI(target1, target2, target3, sort, LExecutor.varUnit, builder.var(sortOrder), builder.var(output)); + } + } + + @RegisterStatement("ulocate") + public static class UnitLocateStatement extends LStatement{ + public LLocate locate = LLocate.building; + public BlockFlag flag = BlockFlag.core; + public String enemy = "true", ore = "@copper"; + public String outX = "outx", outY = "outy", outFound = "found", outBuild = "building"; + + @Override + public void build(Table table){ + rebuild(table); + } + + void rebuild(Table table){ + table.clearChildren(); + + table.add(" find ").left(); + + table.button(b -> { + b.label(() -> locate.name()); + b.clicked(() -> showSelect(b, LLocate.all, locate, t -> { + locate = t; + rebuild(table); + }, 2, cell -> cell.size(110, 50))); + }, Styles.logict, () -> {}).size(110, 40).color(table.color).left().padLeft(2); + + switch(locate){ + case building -> { + row(table); + table.add(" type ").left(); + table.button(b -> { + b.label(() -> flag.name()); + b.clicked(() -> showSelect(b, BlockFlag.all, flag, t -> flag = t, 2, cell -> cell.size(110, 50))); + }, Styles.logict, () -> {}).size(110, 40).color(table.color).left().padLeft(2); + row(table); + + table.add(" enemy ").left(); + + fields(table, enemy, str -> enemy = str); + + table.row(); + } + + case ore -> { + table.add(" ore ").left(); + table.table(ts -> { + ts.color.set(table.color); + + field(ts, ore, str -> ore = str); + + ts.button(b -> { + b.image(Icon.pencilSmall); + b.clicked(() -> showSelectTable(b, (t, hide) -> { + t.row(); + t.table(i -> { + i.left(); + int c = 0; + for(Item item : Vars.content.items()){ + if(!item.unlockedNow()) continue; + i.button(new TextureRegionDrawable(item.icon(Cicon.small)), Styles.cleari, () -> { + ore = "@" + item.name; + rebuild(table); + hide.run(); + }).size(40f).get().resizeImage(Cicon.small.size); + + if(++c % 6 == 0) i.row(); + } + }).colspan(3).width(240f).left(); + })); + }, Styles.logict, () -> {}).size(40f).padLeft(-2).color(table.color); + }); + + + table.row(); + } + + case spawn, damaged -> { + table.row(); + } + } + + table.add(" outX ").left(); + fields(table, outX, str -> outX = str); + + table.add(" outY ").left(); + fields(table, outY, str -> outY = str); + + row(table); + + table.add(" found ").left(); + fields(table, outFound, str -> outFound = str); + + table.add(" building ").left(); + fields(table, outBuild, str -> outBuild = str); + + } + + @Override + public LCategory category(){ + return LCategory.units; + } + + @Override + public LInstruction build(LAssembler builder){ + return new UnitLocateI(locate, flag, builder.var(enemy), builder.var(ore), builder.var(outX), builder.var(outY), builder.var(outFound), builder.var(outBuild)); + } + } } diff --git a/core/src/mindustry/logic/LUnitControl.java b/core/src/mindustry/logic/LUnitControl.java new file mode 100644 index 0000000000..b4c7f8254c --- /dev/null +++ b/core/src/mindustry/logic/LUnitControl.java @@ -0,0 +1,27 @@ +package mindustry.logic; + +public enum LUnitControl{ + stop, + move("x", "y"), + approach("x", "y", "radius"), + boost("enable"), + pathfind(), + target("x", "y", "shoot"), + targetp("unit", "shoot"), + itemDrop("to", "amount"), + itemTake("from", "item", "amount"), + payDrop, + payTake("takeUnits"), + mine("x", "y"), + flag("value"), + build("x", "y", "block", "rotation"), + getBlock("x", "y", "type", "building"), + within("x", "y", "radius", "result"); + + public final String[] params; + public static final LUnitControl[] all = values(); + + LUnitControl(String... params){ + this.params = params; + } +} diff --git a/core/src/mindustry/logic/LogicDialog.java b/core/src/mindustry/logic/LogicDialog.java index fb97e5c4bc..44fcddd2c0 100644 --- a/core/src/mindustry/logic/LogicDialog.java +++ b/core/src/mindustry/logic/LogicDialog.java @@ -60,7 +60,7 @@ public class LogicDialog extends BaseDialog{ int i = 0; for(Prov prov : LogicIO.allStatements){ LStatement example = prov.get(); - if(example instanceof InvalidStatement) continue; + if(example instanceof InvalidStatement || example.hidden()) continue; TextButtonStyle style = new TextButtonStyle(Styles.cleart); style.fontColor = example.category().color; diff --git a/core/src/mindustry/logic/LogicOp.java b/core/src/mindustry/logic/LogicOp.java index b289efc1f2..40d02a8345 100644 --- a/core/src/mindustry/logic/LogicOp.java +++ b/core/src/mindustry/logic/LogicOp.java @@ -1,6 +1,7 @@ package mindustry.logic; import arc.math.*; +import arc.util.*; public enum LogicOp{ add("+", (a, b) -> a + b), @@ -9,8 +10,8 @@ public enum LogicOp{ div("/", (a, b) -> a / b), idiv("//", (a, b) -> Math.floor(a / b)), mod("%", (a, b) -> a % b), - equal("==", (a, b) -> Math.abs(a - b) < 0.000001 ? 1 : 0, (a, b) -> a == b ? 1 : 0), - notEqual("not", (a, b) -> Math.abs(a - b) < 0.000001 ? 0 : 1, (a, b) -> a != b ? 1 : 0), + equal("==", (a, b) -> Math.abs(a - b) < 0.000001 ? 1 : 0, (a, b) -> Structs.eq(a, b) ? 1 : 0), + notEqual("not", (a, b) -> Math.abs(a - b) < 0.000001 ? 0 : 1, (a, b) -> !Structs.eq(a, b) ? 1 : 0), lessThan("<", (a, b) -> a < b ? 1 : 0), lessThanEq("<=", (a, b) -> a <= b ? 1 : 0), greaterThan(">", (a, b) -> a > b ? 1 : 0), diff --git a/core/src/mindustry/maps/Map.java b/core/src/mindustry/maps/Map.java index edef90cea7..0fdc818139 100644 --- a/core/src/mindustry/maps/Map.java +++ b/core/src/mindustry/maps/Map.java @@ -98,7 +98,9 @@ public class Map implements Comparable, Publishable{ public Rules rules(Rules base){ try{ - Rules result = JsonIO.read(Rules.class, base, tags.get("rules", "{}")); + //this replacement is a MASSIVE hack but it fixes some incorrect overwriting of team-specific rules. + //may need to be tweaked later + Rules result = JsonIO.read(Rules.class, base, tags.get("rules", "{}").replace("teams:{2:{infiniteAmmo:true}},", "")); if(result.spawns.isEmpty()) result.spawns = Vars.defaultWaves.get(); return result; }catch(Exception e){ diff --git a/core/src/mindustry/maps/Maps.java b/core/src/mindustry/maps/Maps.java index 7741f0942f..28e571cf72 100644 --- a/core/src/mindustry/maps/Maps.java +++ b/core/src/mindustry/maps/Maps.java @@ -29,7 +29,7 @@ import static mindustry.Vars.*; public class Maps{ /** List of all built-in maps. Filenames only. */ - private static String[] defaultMapNames = {"maze", "fortress", "labyrinth", "islands", "tendrils", "caldera", "wasteland", "shattered", "fork", "triad", "veins", "glacier"}; + private static String[] defaultMapNames = {"maze", "fortress", "labyrinth", "islands", "tendrils", "caldera", "wasteland", "shattered", "fork", "triad", "mudFlats", "moltenLake", "archipelago", "veins", "glacier"}; /** Maps tagged as PvP */ static final String[] pvpMaps = {"veins", "glacier"}; /** All maps stored in an ordered array. */ @@ -82,9 +82,7 @@ public class Maps{ } public Maps(){ - Events.on(ClientLoadEvent.class, event -> { - maps.sort(); - }); + Events.on(ClientLoadEvent.class, event -> maps.sort()); if(Core.assets != null){ ((CustomLoader)Core.assets.getLoader(ContentLoader.class)).loaded = this::createAllPreviews; diff --git a/core/src/mindustry/maps/SectorDamage.java b/core/src/mindustry/maps/SectorDamage.java index 5f4e267d74..eaa42a8293 100644 --- a/core/src/mindustry/maps/SectorDamage.java +++ b/core/src/mindustry/maps/SectorDamage.java @@ -3,11 +3,19 @@ package mindustry.maps; import arc.math.*; import arc.math.geom.*; import arc.struct.*; +import arc.util.*; import mindustry.ai.*; import mindustry.content.*; import mindustry.entities.*; +import mindustry.entities.abilities.*; +import mindustry.game.*; import mindustry.gen.*; +import mindustry.logic.*; +import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.defense.*; +import mindustry.world.blocks.defense.turrets.*; +import mindustry.world.blocks.defense.turrets.Turret.*; import mindustry.world.blocks.storage.*; import static mindustry.Vars.*; @@ -15,6 +23,300 @@ import static mindustry.Vars.*; public class SectorDamage{ //direct damage is for testing only private static final boolean direct = false, rubble = true; + private static final int maxWavesSimulated = 50; + + /** @return calculated capture progress of the enemy */ + public static float getDamage(SectorInfo info){ + float health = info.sumHealth; + int wavesPassed = info.wavesPassed; + int wave = info.wave; + float waveSpace = info.waveSpacing; + + //this approach is O(n), it simulates every wave passing. + //other approaches can assume all the waves come as one, but that's not as fair. + if(wavesPassed > 0){ + int waveBegin = wave; + int waveEnd = wave + wavesPassed; + + //do not simulate every single wave if there's too many + if(wavesPassed > maxWavesSimulated){ + waveBegin = waveEnd - maxWavesSimulated; + } + + for(int i = waveBegin; i <= waveEnd; i++){ + + float efficiency = health / info.sumHealth; + float dps = info.sumDps * efficiency; + float rps = info.sumRps * efficiency; + + float enemyDps = info.waveDpsBase + info.waveDpsSlope * (i); + float enemyHealth = info.waveHealthBase + info.waveHealthSlope * (i); + + //happens due to certain regressions + if(enemyHealth < 0 || enemyDps < 0) continue; + + //calculate time to destroy both sides + float timeDestroyEnemy = dps <= 0.0001f ? Float.POSITIVE_INFINITY : enemyHealth / dps; //if dps == 0, this is infinity + float timeDestroyBase = health / (enemyDps - rps); //if regen > enemyDps this is negative + + //sector is lost, enemy took too long. + if(timeDestroyEnemy > timeDestroyBase){ + health = 0f; + break; + } + + //otherwise, the enemy shoots for timeDestroyEnemy seconds, so calculate damage taken + float damageTaken = timeDestroyEnemy * (enemyDps - rps); + + //damage the base. + health -= damageTaken; + + //regen health after wave. + health = Math.min(health + rps / 60f * waveSpace, info.sumHealth); + } + } + + return 1f - Mathf.clamp(health / info.sumHealth); + } + + /** Applies wave damage based on sector parameters. */ + public static void applyCalculatedDamage(){ + //calculate base damage fraction + float damage = getDamage(state.secinfo); + + //scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier) + float scaled = Mathf.pow(damage, 1.5f); + + //apply damage to units + float unitDamage = damage * state.secinfo.sumHealth; + Tile spawn = spawner.getFirstSpawn(); + + //damage only units near the spawn point + if(spawn != null){ + Seq allies = new Seq<>(); + for(Unit ally : Groups.unit){ + if(ally.team == state.rules.defaultTeam && ally.within(spawn, state.rules.dropZoneRadius * 2.5f)){ + allies.add(ally); + } + } + + allies.sort(u -> u.dst2(spawn)); + + //damage units one by one, not uniformly + for(var u : allies){ + if(u.health < unitDamage){ + u.remove(); + unitDamage -= u.health; + }else{ + u.health -= unitDamage; + break; + } + } + } + + if(state.secinfo.wavesPassed > 0){ + //simply remove each block in the spawner range if a wave passed + for(Tile spawner : spawner.getSpawns()){ + spawner.circle((int)(state.rules.dropZoneRadius / tilesize), tile -> { + if(tile.team() == state.rules.defaultTeam){ + if(rubble && tile.floor().hasSurface() && Mathf.chance(0.4)){ + Effect.rubble(tile.build.x, tile.build.y, tile.block().size); + } + + tile.remove(); + } + }); + } + } + + //finally apply scaled damage + apply(scaled); + } + + /** Calculates damage simulation parameters before a game is saved. */ + public static void writeParameters(SectorInfo info){ + Building core = state.rules.defaultTeam.core(); + Seq spawns = new Seq<>(); + spawner.eachGroundSpawn((x, y) -> spawns.add(world.tile(x, y))); + + if(spawns.isEmpty() && state.rules.waveTeam.core() != null){ + spawns.add(state.rules.waveTeam.core().tile); + } + + if(core == null || spawns.isEmpty()) return; + + Tile start = spawns.first(); + + Time.mark(); + var field = pathfinder.getField(state.rules.waveTeam, Pathfinder.costGround, Pathfinder.fieldCore); + Seq path = new Seq<>(); + boolean found = false; + + if(field != null && field.weights != null){ + int[][] weights = field.weights; + int count = 0; + Tile current = start; + while(count < world.width() * world.height()){ + int minCost = Integer.MAX_VALUE; + int cx = current.x, cy = current.y; + for(Point2 p : Geometry.d4){ + int nx = cx + p.x, ny = cy + p.y; + + Tile other = world.tile(nx, ny); + if(other != null && weights[nx][ny] < minCost && weights[nx][ny] != -1){ + minCost = weights[nx][ny]; + current = other; + } + } + + path.add(current); + + if(current.build == core){ + found = true; + break; + } + + count ++; + } + } + + if(!found){ + path = Astar.pathfind(start, core.tile, SectorDamage::cost, t -> !(t.block().isStatic() && t.solid())); + } + + //create sparse tile array for fast range query + int sparseSkip = 5, sparseSkip2 = 3; + //TODO if this is slow, use a quadtree + Seq sparse = new Seq<>(path.size / sparseSkip + 1); + Seq sparse2 = new Seq<>(path.size / sparseSkip2 + 1); + + for(int i = 0; i < path.size; i++){ + if(i % sparseSkip == 0){ + sparse.add(path.get(i)); + } + if(i % sparseSkip2 == 0){ + sparse2.add(path.get(i)); + } + } + + //regen is in health per second + //dps is per second + float sumHealth = 0f, sumRps = 0f, sumDps = 0f; + float totalPathBuild = 0; + + //first, calculate the total health of blocks in the path + + //radius around the path that gets counted + int radius = 7; + IntSet counted = new IntSet(); + + for(Tile t : sparse2){ + + //radius is square. + for(int dx = -radius; dx <= radius; dx++){ + for(int dy = -radius; dy <= radius; dy++){ + int wx = dx + t.x, wy = dy + t.y; + if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height()){ + Tile tile = world.rawTile(wx, wy); + + if(tile.build != null && tile.team() == state.rules.defaultTeam && counted.add(tile.pos())){ + //health is divided by block size, because multiblocks are counted multiple times. + sumHealth += tile.build.health / tile.block().size; + totalPathBuild += 1f / tile.block().size; + } + } + } + } + } + + float avgHealth = totalPathBuild <= 1 ? sumHealth : sumHealth / totalPathBuild; + + //block dps + regen + extra health/shields + for(Building build : Groups.build){ + float e = build.efficiency(); + if(e > 0.08f){ + if(build.team == state.rules.defaultTeam && build instanceof Ranged ranged && sparse.contains(t -> t.within(build, ranged.range() + radius*tilesize))){ + if(build.block instanceof Turret t && build instanceof TurretBuild b && b.hasAmmo()){ + sumDps += t.shots / t.reloadTime * 60f * b.peekAmmo().estimateDPS() * e; + } + + if(build.block instanceof MendProjector m){ + sumRps += m.healPercent / m.reload * avgHealth * 60f / 100f * e; + } + + if(build.block instanceof ForceProjector f){ + sumHealth += f.breakage * e; + sumRps += 1f * e; + } + } + } + } + + float curEnemyHealth = 0f, curEnemyDps = 0f; + + //unit regen + health + dps + for(Unit unit : Groups.unit){ + //skip player + if(unit.isPlayer()) continue; + + if(unit.team == state.rules.defaultTeam){ + //scale health based on armor - yes, this is inaccurate, but better than nothing + float healthMult = 1f + Mathf.clamp(unit.armor / 20f); + + sumHealth += unit.health*healthMult + unit.shield; + sumDps += unit.type.dpsEstimate; + if(unit.abilities.find(a -> a instanceof RepairFieldAbility) instanceof RepairFieldAbility h){ + sumRps += h.amount / h.reload * 60f; + } + }else{ + curEnemyDps += unit.type.dpsEstimate; + curEnemyHealth += unit.health; + } + } + + //calculate DPS and health for the next few waves and store in list + var reg = new LinearRegression(); + Seq waveDps = new Seq<>(), waveHealth = new Seq<>(); + + for(int wave = state.wave, i = 0; i < 3; wave += (1 + i++)){ + float sumWaveDps = 0f, sumWaveHealth = 0f; + + //first wave has to take into account current dps + if(wave == state.wave){ + sumWaveDps += curEnemyDps; + sumWaveHealth += curEnemyHealth; + } + + for(SpawnGroup group : state.rules.spawns){ + float healthMult = 1f + Mathf.clamp(group.type.armor / 20f); + StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect); + int spawned = group.getSpawned(wave); + if(spawned <= 0) continue; + sumWaveHealth += spawned * (group.getShield(wave) + group.type.health * effect.healthMultiplier * healthMult); + sumWaveDps += spawned * group.type.dpsEstimate * effect.damageMultiplier; + } + waveDps.add(new Vec2(wave, sumWaveDps)); + waveHealth.add(new Vec2(wave, sumWaveHealth)); + } + + //calculate linear regression of the wave data and store it + reg.calculate(waveHealth); + info.waveHealthBase = reg.intercept; + info.waveHealthSlope = reg.slope; + + reg.calculate(waveDps); + info.waveDpsBase = reg.intercept; + info.waveDpsSlope = reg.slope; + + //enemy units like to aim for a lot of non-essential things, so increase resulting health slightly + info.sumHealth = sumHealth * 1.2f; + //players tend to have longer range units/turrets, so assume DPS is higher + info.sumDps = sumDps * 1.5f; + info.sumRps = sumRps; + + //finally, find an equation to put it all together and produce a 0-1 number + //due to the way most defenses are structured, this number will likely need a ^4 power or so + } public static void apply(float fraction){ Tiles tiles = world.tiles; @@ -35,23 +337,71 @@ public class SectorDamage{ if(core != null && !frontier.isEmpty()){ for(Tile spawner : frontier){ //find path from spawn to core - //TODO this is broken Seq path = Astar.pathfind(spawner, core.tile, SectorDamage::cost, t -> !(t.block().isStatic() && t.solid())); - int amount = (int)(path.size * fraction); - for(int i = 0; i < amount; i++){ - Tile t = path.get(i); - Geometry.circle(t.x, t.y, tiles.width, tiles.height, 5, (cx, cy) -> { - Tile other = tiles.getn(cx, cy); - //just remove all the buildings in the way - as long as they're not cores! - if(other.build != null && other.team() == state.rules.defaultTeam && !(other.block() instanceof CoreBlock)){ - if(rubble && !other.floor().solid && !other.floor().isLiquid && Mathf.chance(0.4)){ - Effect.rubble(other.build.x, other.build.y, other.block().size); - } + Seq removal = new Seq<>(); - other.remove(); + int radius = 3; + + //only penetrate a certain % by health, not by distance + float totalHealth = damage >= 1f ? 1f : path.sumf(t -> { + float s = 0; + for(int dx = -radius; dx <= radius; dx++){ + for(int dy = -radius; dy <= radius; dy++){ + int wx = dx + t.x, wy = dy + t.y; + if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){ + Tile other = world.rawTile(wx, wy); + s += other.team() == state.rules.defaultTeam ? other.build.health / other.block().size : 0f; + } } - }); + } + return s; + }); + float targetHealth = totalHealth * fraction; + float healthCount = 0; + + out: + for(int i = 0; i < path.size && (healthCount < targetHealth || damage >= 1f); i++){ + Tile t = path.get(i); + + for(int dx = -radius; dx <= radius; dx++){ + for(int dy = -radius; dy <= radius; dy++){ + int wx = dx + t.x, wy = dy + t.y; + if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){ + Tile other = world.rawTile(wx, wy); + + //just remove all the buildings in the way - as long as they're not cores + if(other.build != null && other.team() == state.rules.defaultTeam && !(other.block() instanceof CoreBlock)){ + if(rubble && !other.floor().solid && !other.floor().isLiquid && Mathf.chance(0.4)){ + Effect.rubble(other.build.x, other.build.y, other.block().size); + } + + //since the whole block is removed, count the whole health + healthCount += other.build.health; + + removal.add(other.build); + + if(healthCount >= targetHealth && damage < 0.999f){ + break out; + } + } + } + } + } } + + for(Building r : removal){ + if(r.tile.build == r){ + r.addPlan(false); + r.tile.remove(); + } + } + } + } + + //kill every core if damage is maximum + if(fraction >= 1){ + for(Building c : state.rules.defaultTeam.cores().copy()){ + c.tile.remove(); } } @@ -90,6 +440,7 @@ public class SectorDamage{ Effect.rubble(other.build.x, other.build.y, other.block().size); } + other.build.addPlan(false); other.remove(); } } diff --git a/core/src/mindustry/maps/filters/ClearFilter.java b/core/src/mindustry/maps/filters/ClearFilter.java index 3769d7f77d..4da2564a79 100644 --- a/core/src/mindustry/maps/filters/ClearFilter.java +++ b/core/src/mindustry/maps/filters/ClearFilter.java @@ -11,7 +11,7 @@ public class ClearFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr(new BlockOption("block", () -> block, b -> block = b, wallsOnly)); + return Structs.arr(new BlockOption("block", () -> block, b -> block = b, b -> oresOnly.get(b) || wallsOnly.get(b))); } @Override @@ -20,5 +20,9 @@ public class ClearFilter extends GenerateFilter{ if(in.block == block){ in.block = Blocks.air; } + + if(in.overlay == block){ + in.overlay = Blocks.air; + } } } diff --git a/core/src/mindustry/maps/filters/DistortFilter.java b/core/src/mindustry/maps/filters/DistortFilter.java index 0d3691f1f7..daedca1765 100644 --- a/core/src/mindustry/maps/filters/DistortFilter.java +++ b/core/src/mindustry/maps/filters/DistortFilter.java @@ -3,7 +3,6 @@ package mindustry.maps.filters; import arc.util.*; import mindustry.maps.filters.FilterOption.*; import mindustry.world.*; -import mindustry.world.blocks.environment.*; public class DistortFilter extends GenerateFilter{ float scl = 40, mag = 5; @@ -27,6 +26,6 @@ public class DistortFilter extends GenerateFilter{ in.floor = tile.floor(); if(!tile.block().synthetic() && !in.block.synthetic()) in.block = tile.block(); - if(!((Floor)in.floor).isLiquid) in.ore = tile.overlay(); + in.overlay = tile.overlay(); } } diff --git a/core/src/mindustry/maps/filters/FilterOption.java b/core/src/mindustry/maps/filters/FilterOption.java index dedebfe713..e7059f3032 100644 --- a/core/src/mindustry/maps/filters/FilterOption.java +++ b/core/src/mindustry/maps/filters/FilterOption.java @@ -20,9 +20,10 @@ public abstract class FilterOption{ public static final Boolf floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full)); public static final Boolf wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full)) && b.inEditor; public static final Boolf floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full))); - public static final Boolf wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full))); + public static final Boolf wallsOptional = b -> (b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full)))) && b.inEditor; public static final Boolf wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full))) && b.inEditor; - public static final Boolf oresOnly = b -> b instanceof OverlayFloor && !headless && Core.atlas.isFound(b.icon(mindustry.ui.Cicon.full)); + public static final Boolf oresOnly = b -> b instanceof OverlayFloor && !headless && Core.atlas.isFound(b.icon(Cicon.full)); + public static final Boolf oresFloorsOptional = b -> (b instanceof Floor) && !headless && Core.atlas.isFound(b.icon(Cicon.full)); public static final Boolf anyOptional = b -> (floorsOnly.get(b) || wallsOnly.get(b) || oresOnly.get(b) || b == Blocks.air) && b.inEditor; public abstract void build(Table table); diff --git a/core/src/mindustry/maps/filters/GenerateFilter.java b/core/src/mindustry/maps/filters/GenerateFilter.java index 6d0f48d121..47d8420936 100644 --- a/core/src/mindustry/maps/filters/GenerateFilter.java +++ b/core/src/mindustry/maps/filters/GenerateFilter.java @@ -5,7 +5,10 @@ import arc.math.*; import arc.scene.ui.*; import arc.util.*; import arc.util.noise.*; +import mindustry.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; +import mindustry.gen.*; import mindustry.world.*; public abstract class GenerateFilter{ @@ -15,15 +18,42 @@ public abstract class GenerateFilter{ public void apply(Tiles tiles, GenerateInput in){ this.in = in; - for(Tile tile : tiles){ - in.apply(tile.x, tile.y, tile.floor(), tile.block(), tile.overlay()); - apply(); - tile.setFloor(in.floor.asFloor()); - tile.setOverlay(in.floor.asFloor().isLiquid ? Blocks.air : in.ore); + if(isBuffered()){ + //buffer of tiles used, each tile packed into a long struct + long[] buffer = new long[tiles.width * tiles.height]; - if(!tile.block().synthetic() && !in.block.synthetic()){ - tile.setBlock(in.block); + //save to buffer + for(int i = 0; i < tiles.width * tiles.height; i++){ + Tile tile = tiles.geti(i); + buffer[i] = PackTile.get(tile.blockID(), tile.floorID(), tile.overlayID()); + } + + for(int i = 0; i < tiles.width * tiles.height; i++){ + Tile tile = tiles.geti(i); + long b = buffer[i]; + + in.apply(tile.x, tile.y, Vars.content.block(PackTile.block(b)), Vars.content.block(PackTile.floor(b)), Vars.content.block(PackTile.overlay(b))); + apply(); + + tile.setFloor(in.floor.asFloor()); + tile.setOverlay(!in.floor.asFloor().hasSurface() ? Blocks.air : in.overlay); + + if(!tile.block().synthetic() && !in.block.synthetic()){ + tile.setBlock(in.block); + } + } + }else{ + for(Tile tile : tiles){ + in.apply(tile.x, tile.y, tile.block(), tile.floor(), tile.overlay()); + apply(); + + tile.setFloor(in.floor.asFloor()); + tile.setOverlay(!in.floor.asFloor().hasSurface() ? Blocks.air : in.overlay); + + if(!tile.block().synthetic() && !in.block.synthetic()){ + tile.setBlock(in.block); + } } } } @@ -89,16 +119,16 @@ public abstract class GenerateFilter{ public int x, y, width, height; /** output parameters */ - public Block floor, block, ore; + public Block floor, block, overlay; Simplex noise = new Simplex(); RidgedPerlin pnoise = new RidgedPerlin(0, 1); TileProvider buffer; - public void apply(int x, int y, Block floor, Block block, Block ore){ + public void apply(int x, int y, Block block, Block floor, Block overlay){ this.floor = floor; this.block = block; - this.ore = ore; + this.overlay = overlay; this.x = x; this.y = y; } @@ -119,4 +149,9 @@ public abstract class GenerateFilter{ Tile get(int x, int y); } } + + @Struct + class PackTileStruct{ + short block, floor, overlay; + } } diff --git a/core/src/mindustry/maps/filters/MirrorFilter.java b/core/src/mindustry/maps/filters/MirrorFilter.java index 8d2e22bdbe..3ebdb45a71 100644 --- a/core/src/mindustry/maps/filters/MirrorFilter.java +++ b/core/src/mindustry/maps/filters/MirrorFilter.java @@ -39,7 +39,7 @@ public class MirrorFilter extends GenerateFilter{ if(!tile.block().synthetic()){ in.block = tile.block(); } - in.ore = tile.overlay(); + in.overlay = tile.overlay(); } } diff --git a/core/src/mindustry/maps/filters/NoiseFilter.java b/core/src/mindustry/maps/filters/NoiseFilter.java index 857be64369..63e98e3ad9 100644 --- a/core/src/mindustry/maps/filters/NoiseFilter.java +++ b/core/src/mindustry/maps/filters/NoiseFilter.java @@ -9,7 +9,7 @@ import static mindustry.maps.filters.FilterOption.*; public class NoiseFilter extends GenerateFilter{ float scl = 40, threshold = 0.5f, octaves = 3f, falloff = 0.5f; - Block floor = Blocks.stone, block = Blocks.stoneWall; + Block floor = Blocks.stone, block = Blocks.stoneWall, target = Blocks.air; @Override public FilterOption[] options(){ @@ -18,8 +18,9 @@ public class NoiseFilter extends GenerateFilter{ new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), - new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly), - new BlockOption("wall", () -> block, b -> block = b, wallsOnly) + new BlockOption("target", () -> target, b -> target = b, anyOptional), + new BlockOption("floor", () -> floor, b -> floor = b, floorsOptional), + new BlockOption("wall", () -> block, b -> block = b, wallsOptional) ); } @@ -27,9 +28,9 @@ public class NoiseFilter extends GenerateFilter{ public void apply(){ float noise = noise(in.x, in.y, scl, 1f, octaves, falloff); - if(noise > threshold){ - in.floor = floor; - if(wallsOnly.get(in.block)) in.block = block; + if(noise > threshold && (target == Blocks.air || in.floor == target || in.block == target)){ + if(floor != Blocks.air) in.floor = floor; + if(block != Blocks.air && in.block != Blocks.air) in.block = block; } } } diff --git a/core/src/mindustry/maps/filters/OreFilter.java b/core/src/mindustry/maps/filters/OreFilter.java index 491bbf0123..3d9aee7e6e 100644 --- a/core/src/mindustry/maps/filters/OreFilter.java +++ b/core/src/mindustry/maps/filters/OreFilter.java @@ -9,7 +9,7 @@ import static mindustry.maps.filters.FilterOption.*; public class OreFilter extends GenerateFilter{ public float scl = 23, threshold = 0.81f, octaves = 2f, falloff = 0.3f; - public Block ore = Blocks.oreCopper; + public Block ore = Blocks.oreCopper, target = Blocks.air; @Override public FilterOption[] options(){ @@ -18,7 +18,8 @@ public class OreFilter extends GenerateFilter{ new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), - new BlockOption("ore", () -> ore, b -> ore = b, oresOnly) + new BlockOption("ore", () -> ore, b -> ore = b, oresOnly), + new BlockOption("target", () -> target, b -> target = b, oresFloorsOptional) ); } @@ -26,8 +27,8 @@ public class OreFilter extends GenerateFilter{ public void apply(){ float noise = noise(in.x, in.y, scl, 1f, octaves, falloff); - if(noise > threshold && in.ore != Blocks.spawn){ - in.ore = ore; + if(noise > threshold && in.overlay != Blocks.spawn && (target == Blocks.air || in.floor == target || in.overlay == target)){ + in.overlay = ore; } } } diff --git a/core/src/mindustry/maps/filters/OreMedianFilter.java b/core/src/mindustry/maps/filters/OreMedianFilter.java index c9fd8d91c6..27a10548af 100644 --- a/core/src/mindustry/maps/filters/OreMedianFilter.java +++ b/core/src/mindustry/maps/filters/OreMedianFilter.java @@ -29,14 +29,14 @@ public class OreMedianFilter extends GenerateFilter{ @Override public void apply(){ - if(in.ore == Blocks.spawn) return; + if(in.overlay == Blocks.spawn) return; int cx = (in.x / 2) * 2; int cy = (in.y / 2) * 2; - if(in.ore != Blocks.air){ - if(!(in.tile(cx + 1, cy).overlay() == in.ore && in.tile(cx, cy).overlay() == in.ore && in.tile(cx + 1, cy + 1).overlay() == in.ore && in.tile(cx, cy + 1).overlay() == in.ore && + if(in.overlay != Blocks.air){ + if(!(in.tile(cx + 1, cy).overlay() == in.overlay && in.tile(cx, cy).overlay() == in.overlay && in.tile(cx + 1, cy + 1).overlay() == in.overlay && in.tile(cx, cy + 1).overlay() == in.overlay && !in.tile(cx + 1, cy).block().isStatic() && !in.tile(cx, cy).block().isStatic() && !in.tile(cx + 1, cy + 1).block().isStatic() && !in.tile(cx, cy + 1).block().isStatic())){ - in.ore = Blocks.air; + in.overlay = Blocks.air; } } @@ -58,6 +58,6 @@ public class OreMedianFilter extends GenerateFilter{ int index = Math.min((int)(blocks.size * percentile), blocks.size - 1); int overlay = blocks.get(index); - in.ore = Vars.content.block(overlay); + in.overlay = Vars.content.block(overlay); } } diff --git a/core/src/mindustry/maps/filters/ScatterFilter.java b/core/src/mindustry/maps/filters/ScatterFilter.java index 4b90275b1f..67d2b0229e 100644 --- a/core/src/mindustry/maps/filters/ScatterFilter.java +++ b/core/src/mindustry/maps/filters/ScatterFilter.java @@ -27,7 +27,7 @@ public class ScatterFilter extends GenerateFilter{ if(!block.isOverlay()){ in.block = block; }else{ - in.ore = block; + in.overlay = block; } } diff --git a/core/src/mindustry/maps/filters/SpawnPathFilter.java b/core/src/mindustry/maps/filters/SpawnPathFilter.java new file mode 100644 index 0000000000..8384024186 --- /dev/null +++ b/core/src/mindustry/maps/filters/SpawnPathFilter.java @@ -0,0 +1,64 @@ +package mindustry.maps.filters; + +import arc.math.*; +import arc.struct.*; +import arc.util.*; +import mindustry.*; +import mindustry.ai.*; +import mindustry.content.*; +import mindustry.maps.filters.FilterOption.*; +import mindustry.world.*; +import mindustry.world.blocks.storage.*; + +import static mindustry.Vars.*; + +/** Selects X spawns from the spawn pool.*/ +public class SpawnPathFilter extends GenerateFilter{ + int radius = 3; + + @Override + public FilterOption[] options(){ + return Structs.arr( + new SliderOption("radius", () -> radius, f -> radius = (int)f, 1, 20).display() + ); + } + + @Override + public void apply(Tiles tiles, GenerateInput in){ + Tile core = null; + var spawns = new Seq(); + + for(Tile tile : tiles){ + if(tile.overlay() == Blocks.spawn){ + spawns.add(tile); + } + if(tile.block() instanceof CoreBlock && tile.team() != Vars.state.rules.waveTeam){ + core = tile; + } + } + + if(core != null && spawns.any()){ + for(var spawn : spawns){ + var path = Astar.pathfind(core.x, core.y, spawn.x, spawn.y, t -> t.solid() ? 100 : 1, Astar.manhattan, tile -> !tile.floor().isDeep()); + for(var tile : path){ + for(int x = -radius; x <= radius; x++){ + for(int y = -radius; y <= radius; y++){ + int wx = tile.x + x, wy = tile.y + y; + if(Structs.inBounds(wx, wy, world.width(), world.height()) && Mathf.within(x, y, radius)){ + Tile other = tiles.getn(wx, wy); + if(!other.synthetic()){ + other.setBlock(Blocks.air); + } + } + } + } + } + } + } + } + + @Override + public boolean isPost(){ + return true; + } +} diff --git a/core/src/mindustry/maps/filters/TerrainFilter.java b/core/src/mindustry/maps/filters/TerrainFilter.java index cc0ba82b54..4caea2041a 100644 --- a/core/src/mindustry/maps/filters/TerrainFilter.java +++ b/core/src/mindustry/maps/filters/TerrainFilter.java @@ -31,11 +31,10 @@ public class TerrainFilter extends GenerateFilter{ float noise = noise(in.x, in.y, scl, magnitude, octaves, falloff) + Mathf.dst((float)in.x / in.width, (float)in.y / in.height, 0.5f, 0.5f) * circleScl; in.floor = floor; - in.ore = Blocks.air; if(noise >= threshold){ in.block = block; - }else{ + }else if(!in.block.synthetic()){ in.block = Blocks.air; } } diff --git a/core/src/mindustry/maps/generators/BaseGenerator.java b/core/src/mindustry/maps/generators/BaseGenerator.java index 7a752a453a..3a28078f74 100644 --- a/core/src/mindustry/maps/generators/BaseGenerator.java +++ b/core/src/mindustry/maps/generators/BaseGenerator.java @@ -4,6 +4,7 @@ import arc.func.*; import arc.math.*; import arc.math.geom.*; import arc.struct.*; +import arc.util.*; import mindustry.ai.BaseRegistry.*; import mindustry.content.*; import mindustry.game.*; @@ -12,7 +13,6 @@ import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.defense.*; -import mindustry.world.blocks.environment.*; import mindustry.world.blocks.power.*; import mindustry.world.blocks.production.*; import mindustry.world.meta.*; @@ -26,8 +26,6 @@ public class BaseGenerator{ private Tiles tiles; private Team team; - private ObjectMap ores = new ObjectMap<>(); - private ObjectMap oreFloors = new ObjectMap<>(); private Seq cores; public void generate(Tiles tiles, Seq cores, Tile spawn, Team team, Sector sector, float difficulty){ @@ -40,14 +38,6 @@ public class BaseGenerator{ Mathf.rand.setSeed(sector.id); - for(Block block : content.blocks()){ - if(block instanceof OreBlock && block.asFloor().itemDrop != null){ - ores.put(block.asFloor().itemDrop, (OreBlock)block); - }else if(block.isFloor() && block.asFloor().itemDrop != null && !oreFloors.containsKey(block.asFloor().itemDrop)){ - oreFloors.put(block.asFloor().itemDrop, block.asFloor()); - } - } - //TODO limit base size float costBudget = 1000; @@ -70,7 +60,7 @@ public class BaseGenerator{ for(Tile tile : cores){ tile.clearOverlay(); - Schematics.placeLoadout(coreschem.schematic, tile.x, tile.y, team, coreschem.required instanceof Item ? ores.get((Item)coreschem.required) : Blocks.oreCopper); + Schematics.placeLoadout(coreschem.schematic, tile.x, tile.y, team, coreschem.required instanceof Item ? bases.ores.get((Item)coreschem.required) : Blocks.oreCopper); //fill core with every type of item (even non-material) Building entity = tile.build; @@ -87,10 +77,10 @@ public class BaseGenerator{ || (tile.floor().liquidDrop != null && Mathf.chance(nonResourceChance * 2))) && Mathf.chance(resourceChance)){ Seq parts = bases.forResource(tile.drop() != null ? tile.drop() : tile.floor().liquidDrop); if(!parts.isEmpty()){ - tryPlace(parts.getFrac(bracket + Mathf.range(bracketRange)), tile.x, tile.y); + tryPlace(parts.getFrac(bracket + Mathf.range(bracketRange)), tile.x, tile.y, team); } }else if(Mathf.chance(nonResourceChance)){ - tryPlace(bases.parts.getFrac(bracket + Mathf.range(bracketRange)), tile.x, tile.y); + tryPlace(bases.parts.getFrac(bracket + Mathf.range(bracketRange)), tile.x, tile.y, team); } }); @@ -164,7 +154,19 @@ public class BaseGenerator{ core.circle(range, (x, y) -> cons.get(tiles.getn(x, y))); } - boolean tryPlace(BasePart part, int x, int y){ + /** + * Tries to place a base part at a certain location with a certain team. + * @return success state + * */ + public static boolean tryPlace(BasePart part, int x, int y, Team team){ + return tryPlace(part, x, y, team, null); + } + + /** + * Tries to place a base part at a certain location with a certain team. + * @return success state + * */ + public static boolean tryPlace(BasePart part, int x, int y, Team team, @Nullable Intc2 posc){ int rotation = Mathf.range(2); axis.set((int)(part.schematic.width / 2f), (int)(part.schematic.height / 2f)); Schematic result = Schematics.rotate(part.schematic, rotation); @@ -180,21 +182,24 @@ public class BaseGenerator{ if(isTaken(tile.block, realX, realY)){ return false; } + + if(posc != null){ + posc.get(realX, realY); + } } - if(part.required instanceof Item){ - Item item = (Item)part.required; + if(part.required instanceof Item item){ for(Stile tile : result.tiles){ if(tile.block instanceof Drill){ tile.block.iterateTaken(tile.x + cx, tile.y + cy, (ex, ey) -> { - if(!tiles.getn(ex, ey).floor().isLiquid){ - set(tiles.getn(ex, ey), item); + if(world.tiles.getn(ex, ey).floor().hasSurface()){ + set(world.tiles.getn(ex, ey), item); } - Tile rand = tiles.getc(ex + Mathf.range(1), ey + Mathf.range(1)); - if(!rand.floor().isLiquid){ + Tile rand = world.tiles.getc(ex + Mathf.range(1), ey + Mathf.range(1)); + if(rand.floor().hasSurface()){ //random ores nearby to make it look more natural set(rand, item); } @@ -206,8 +211,7 @@ public class BaseGenerator{ Schematics.place(result, cx + result.width/2, cy + result.height/2, team); //fill drills with items after placing - if(part.required instanceof Item){ - Item item = (Item)part.required; + if(part.required instanceof Item item){ for(Stile tile : result.tiles){ if(tile.block instanceof Drill){ @@ -223,15 +227,15 @@ public class BaseGenerator{ return true; } - void set(Tile tile, Item item){ - if(ores.containsKey(item)){ - tile.setOverlay(ores.get(item)); - }else if(oreFloors.containsKey(item)){ - tile.setFloor(oreFloors.get(item)); + static void set(Tile tile, Item item){ + if(bases.ores.containsKey(item)){ + tile.setOverlay(bases.ores.get(item)); + }else if(bases.oreFloors.containsKey(item)){ + tile.setFloor(bases.oreFloors.get(item)); } } - boolean isTaken(Block block, int x, int y){ + static boolean isTaken(Block block, int x, int y){ int offsetx = -(block.size - 1) / 2; int offsety = -(block.size - 1) / 2; int pad = 1; @@ -247,8 +251,8 @@ public class BaseGenerator{ return false; } - boolean overlaps(int x, int y){ - Tile tile = tiles.get(x, y); + static boolean overlaps(int x, int y){ + Tile tile = world.tiles.get(x, y); return tile == null || !tile.block().alwaysReplace || world.getDarkness(x, y) > 0; } diff --git a/core/src/mindustry/maps/generators/BasicGenerator.java b/core/src/mindustry/maps/generators/BasicGenerator.java index 542f84cf29..1ef6d31297 100644 --- a/core/src/mindustry/maps/generators/BasicGenerator.java +++ b/core/src/mindustry/maps/generators/BasicGenerator.java @@ -69,7 +69,7 @@ public abstract class BasicGenerator implements WorldGenerator{ public void ores(Seq ores){ pass((x, y) -> { - if(floor.asFloor().isLiquid) return; + if(!floor.asFloor().hasSurface()) return; int offsetX = x - 4, offsetY = y + 23; for(int i = ores.size - 1; i >= 0; i--){ @@ -124,7 +124,7 @@ public abstract class BasicGenerator implements WorldGenerator{ Block[] blocks = {Blocks.darkPanel3}; int secSize = 20; pass((x, y) -> { - if(floor.asFloor().isLiquid) return; + if(!floor.asFloor().hasSurface()) return; int mx = x % secSize, my = y % secSize; int sclx = x / secSize, scly = y / secSize; @@ -248,7 +248,7 @@ public abstract class BasicGenerator implements WorldGenerator{ for(int x = -rad; x <= rad; x++){ for(int y = -rad; y <= rad; y++){ int wx = cx + x, wy = cy + y; - if(Structs.inBounds(wx, wy, width, height) && Mathf.dst(x, y, 0, 0) <= rad){ + if(Structs.inBounds(wx, wy, width, height) && Mathf.within(x, y, rad)){ Tile other = tiles.getn(wx, wy); other.setBlock(Blocks.air); } diff --git a/core/src/mindustry/maps/generators/PlanetGenerator.java b/core/src/mindustry/maps/generators/PlanetGenerator.java index 6bbc15ed2f..4b5884014b 100644 --- a/core/src/mindustry/maps/generators/PlanetGenerator.java +++ b/core/src/mindustry/maps/generators/PlanetGenerator.java @@ -1,6 +1,7 @@ package mindustry.maps.generators; import arc.math.geom.*; +import arc.struct.*; import arc.util.noise.*; import mindustry.graphics.g3d.*; import mindustry.graphics.g3d.PlanetGrid.*; @@ -8,6 +9,7 @@ import mindustry.type.*; import mindustry.world.*; public abstract class PlanetGenerator extends BasicGenerator implements HexMesher{ + protected IntSeq ints = new IntSeq(); protected Sector sector; /** Should generate sector bases for a planet. */ @@ -23,6 +25,11 @@ public abstract class PlanetGenerator extends BasicGenerator implements HexMeshe if(noise < 0.15){ for(Ptile other : tile.tiles){ + //no sectors near start sector! + if(sector.planet.getSector(other).id == sector.planet.startSector){ + return; + } + if(sector.planet.getSector(other).generateEnemyBase){ any = false; break; diff --git a/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java b/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java index 6c5f047a90..4c7bd49a4e 100644 --- a/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java +++ b/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java @@ -7,6 +7,7 @@ import arc.struct.*; import arc.util.*; import arc.util.noise.*; import mindustry.ai.*; +import mindustry.ai.BaseRegistry.*; import mindustry.content.*; import mindustry.game.*; import mindustry.maps.generators.*; @@ -21,6 +22,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ float scl = 5f; float waterOffset = 0.07f; + //TODO fix sand near snow (sector 173) Block[][] arr = { {Blocks.water, Blocks.darksandWater, Blocks.darksand, Blocks.darksand, Blocks.darksand, Blocks.darksand, Blocks.sand, Blocks.sand, Blocks.sand, Blocks.sand, Blocks.darksandTaintedWater, Blocks.stone, Blocks.stone}, @@ -29,9 +31,9 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ {Blocks.water, Blocks.sandWater, Blocks.sand, Blocks.salt, Blocks.salt, Blocks.salt, Blocks.sand, Blocks.stone, Blocks.stone, Blocks.stone, Blocks.snow, Blocks.iceSnow, Blocks.ice}, {Blocks.deepwater, Blocks.water, Blocks.sandWater, Blocks.sand, Blocks.salt, Blocks.sand, Blocks.sand, Blocks.basalt, Blocks.snow, Blocks.snow, Blocks.snow, Blocks.snow, Blocks.ice}, {Blocks.deepwater, Blocks.water, Blocks.sandWater, Blocks.sand, Blocks.sand, Blocks.sand, Blocks.moss, Blocks.iceSnow, Blocks.snow, Blocks.snow, Blocks.ice, Blocks.snow, Blocks.ice}, - {Blocks.deepwater, Blocks.sandWater, Blocks.sand, Blocks.sand, Blocks.moss, Blocks.moss, Blocks.snow, Blocks.snow, Blocks.snow, Blocks.ice, Blocks.ice, Blocks.snow, Blocks.ice}, - {Blocks.taintedWater, Blocks.darksandTaintedWater, Blocks.darksand, Blocks.darksand, Blocks.basalt, Blocks.moss, Blocks.snow, Blocks.snow, Blocks.snow, Blocks.ice, Blocks.snow, Blocks.ice, Blocks.ice}, - {Blocks.darksandWater, Blocks.darksand, Blocks.darksand, Blocks.darksand, Blocks.moss, Blocks.sporeMoss, Blocks.snow, Blocks.snow, Blocks.snow, Blocks.snow, Blocks.snow, Blocks.ice, Blocks.ice}, + {Blocks.deepwater, Blocks.sandWater, Blocks.sand, Blocks.sand, Blocks.moss, Blocks.moss, Blocks.snow, Blocks.basalt, Blocks.basalt, Blocks.basalt, Blocks.ice, Blocks.snow, Blocks.ice}, + {Blocks.taintedWater, Blocks.darksandTaintedWater, Blocks.darksand, Blocks.darksand, Blocks.basalt, Blocks.moss, Blocks.basalt, Blocks.hotrock, Blocks.basalt, Blocks.ice, Blocks.snow, Blocks.ice, Blocks.ice}, + {Blocks.darksandWater, Blocks.darksand, Blocks.darksand, Blocks.darksand, Blocks.moss, Blocks.sporeMoss, Blocks.snow, Blocks.basalt, Blocks.basalt, Blocks.ice, Blocks.snow, Blocks.ice, Blocks.ice}, {Blocks.darksandWater, Blocks.darksand, Blocks.darksand, Blocks.sporeMoss, Blocks.ice, Blocks.ice, Blocks.snow, Blocks.snow, Blocks.snow, Blocks.snow, Blocks.ice, Blocks.ice, Blocks.ice}, {Blocks.taintedWater, Blocks.darksandTaintedWater, Blocks.darksand, Blocks.sporeMoss, Blocks.sporeMoss, Blocks.ice, Blocks.ice, Blocks.snow, Blocks.snow, Blocks.ice, Blocks.ice, Blocks.ice, Blocks.ice}, {Blocks.darksandTaintedWater, Blocks.darksandTaintedWater, Blocks.darksand, Blocks.sporeMoss, Blocks.moss, Blocks.sporeMoss, Blocks.iceSnow, Blocks.snow, Blocks.ice, Blocks.ice, Blocks.ice, Blocks.ice, Blocks.ice}, @@ -143,7 +145,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ float constraint = 1.3f; float radius = width / 2f / Mathf.sqrt3; int rooms = rand.random(2, 5); - Seq array = new Seq<>(); + Seq roomseq = new Seq<>(); for(int i = 0; i < rooms; i++){ Tmp.v1.trns(rand.random(360f), rand.random(radius / constraint)); @@ -151,7 +153,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ float ry = (height/2f + Tmp.v1.y); float maxrad = radius - Tmp.v1.len(); float rrad = Math.min(rand.random(9f, maxrad / 2f), 30f); - array.add(new Room((int)rx, (int)ry, (int)rrad)); + roomseq.add(new Room((int)rx, (int)ry, (int)rrad)); } //check positions on the map to place the player spawn. this needs to be in the corner of the map @@ -180,13 +182,13 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ } if(waterTiles <= 4 || (i + angleStep >= 360)){ - array.add(spawn = new Room(cx, cy, rand.random(8, 15))); + roomseq.add(spawn = new Room(cx, cy, rand.random(8, 15))); for(int j = 0; j < enemySpawns; j++){ float enemyOffset = rand.range(60f); Tmp.v1.set(cx - width/2, cy - height/2).rotate(180f + enemyOffset).add(width/2, height/2); Room espawn = new Room((int)Tmp.v1.x, (int)Tmp.v1.y, rand.random(8, 15)); - array.add(espawn); + roomseq.add(espawn); enemies.add(espawn); } @@ -194,16 +196,16 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ } } - for(Room room : array){ + for(Room room : roomseq){ erase(room.x, room.y, room.radius); } int connections = rand.random(Math.max(rooms - 1, 1), rooms + 3); for(int i = 0; i < connections; i++){ - array.random(rand).connect(array.random(rand)); + roomseq.random(rand).connect(roomseq.random(rand)); } - for(Room room : array){ + for(Room room : roomseq){ spawn.connect(room); } @@ -236,7 +238,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ } pass((x, y) -> { - if(floor.asFloor().isLiquid) return; + if(!floor.asFloor().hasSurface()) return; int offsetX = x - 4, offsetY = y + 23; for(int i = ores.size - 1; i >= 0; i--){ @@ -250,10 +252,6 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ } }); - for(Room espawn : enemies){ - tiles.getn(espawn.x, espawn.y).setOverlay(Blocks.spawn); - } - trimDark(); median(2); @@ -261,40 +259,168 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ tech(); pass((x, y) -> { - if(floor == Blocks.sporeMoss && rand.chance(0.9)){ - floor = Blocks.moss; - } - - //random stuff - - for(int i = 0; i < 4; i++){ - Tile near = world.tile(x + Geometry.d4[i].x, y + Geometry.d4[i].y); - if(near != null && near.block() != Blocks.air){ - return; + //random moss + if(floor == Blocks.sporeMoss){ + if(Math.abs(0.5f - noise(x - 90, y, 4, 0.8, 65)) > 0.02){ + floor = Blocks.moss; } } - if(rand.chance(0.01) && !floor.asFloor().isLiquid && block == Blocks.air){ - block = dec.get(floor, floor.asFloor().decoration); + //tar + if(floor == Blocks.darksand){ + if(Math.abs(0.5f - noise(x - 40, y, 2, 0.7, 80)) > 0.25f && + Math.abs(0.5f - noise(x, y + sector.id*10, 1, 1, 60)) > 0.41f && !(roomseq.contains(r -> Mathf.within(x, y, r.x, r.y, 15)))){ + floor = Blocks.tar; + ore = Blocks.air; + } + } + + //hotrock tweaks + if(floor == Blocks.hotrock){ + if(Math.abs(0.5f - noise(x - 90, y, 4, 0.8, 80)) > 0.035){ + floor = Blocks.basalt; + }else{ + ore = Blocks.air; + boolean all = true; + for(Point2 p : Geometry.d4){ + Tile other = tiles.get(x + p.x, y + p.y); + if(other == null || (other.floor() != Blocks.hotrock && other.floor() != Blocks.magmarock)){ + all = false; + } + } + if(all){ + floor = Blocks.magmarock; + } + } + } + + if(rand.chance(0.0075)){ + //random spore trees + boolean any = false; + boolean all = true; + for(Point2 p : Geometry.d4){ + Tile other = tiles.get(x + p.x, y + p.y); + if(other != null && other.block() == Blocks.air){ + any = true; + }else{ + all = false; + } + } + if(any && ((block == Blocks.snowWall || block == Blocks.iceWall) || (all && block == Blocks.air && floor == Blocks.snow && rand.chance(0.03)))){ + block = rand.chance(0.5) ? Blocks.whiteTree : Blocks.whiteTreeDead; + } + } + + //random stuff + dec: { + for(int i = 0; i < 4; i++){ + Tile near = world.tile(x + Geometry.d4[i].x, y + Geometry.d4[i].y); + if(near != null && near.block() != Blocks.air){ + break dec; + } + } + + if(rand.chance(0.01) && floor.asFloor().hasSurface() && block == Blocks.air){ + block = dec.get(floor, floor.asFloor().decoration); + } } }); + float difficulty = sector.baseCoverage; + ints.clear(); + ints.ensureCapacity(width * height / 4); + + int ruinCount = rand.random(-2, 4); + if(ruinCount > 0){ + int padding = 25; + + //create list of potential positions + for(int x = padding; x < width - padding; x++){ + for(int y = padding; y < height - padding; y++){ + Tile tile = tiles.getn(x, y); + if(!tile.solid() && (tile.drop() != null || tile.floor().liquidDrop != null)){ + ints.add(tile.pos()); + } + } + } + + ints.shuffle(rand); + + int placed = 0; + float diffRange = 0.4f; + //try each position + for(int i = 0; i < ints.size && placed < ruinCount; i++){ + int val = ints.items[i]; + int x = Point2.x(val), y = Point2.y(val); + + //do not overwrite player spawn + if(Mathf.within(x, y, spawn.x, spawn.y, 18f)){ + continue; + } + + float range = difficulty + rand.random(diffRange); + + Tile tile = tiles.getn(x, y); + BasePart part = null; + if(tile.overlay().itemDrop != null){ + part = bases.forResource(tile.drop()).getFrac(range); + }else if(tile.floor().liquidDrop != null && rand.chance(0.05)){ + part = bases.forResource(tile.floor().liquidDrop).getFrac(range); + }else if(rand.chance(0.05)){ //ore-less parts are less likely to occur. + part = bases.parts.getFrac(range); + } + + //actually place the part + if(part != null && BaseGenerator.tryPlace(part, x, y, Team.derelict, (cx, cy) -> { + Tile other = tiles.getn(cx, cy); + other.setOverlay(Blocks.oreScrap); + for(int j = 1; j <= 2; j++){ + for(Point2 p : Geometry.d8){ + Tile t = tiles.get(cx + p.x*j, cy + p.y*j); + if(t != null && t.floor().hasSurface() && rand.chance(j == 1 ? 0.4 : 0.2)){ + t.setOverlay(Blocks.oreScrap); + } + } + } + })){ + placed ++; + + int debrisRadius = Math.max(part.schematic.width, part.schematic.height)/2 + 3; + Geometry.circle(x, y, tiles.width, tiles.height, debrisRadius, (cx, cy) -> { + float dst = Mathf.dst(cx, cy, x, y); + float removeChance = Mathf.lerp(0.05f, 0.5f, dst / debrisRadius); + + Tile other = tiles.getn(cx, cy); + if(other.build != null && other.isCenter()){ + if(other.team() == Team.derelict && rand.chance(removeChance)){ + other.remove(); + }else if(rand.chance(0.5)){ + other.build.health = other.build.health - rand.random(other.build.health * 0.9f); + } + } + }); + } + } + } + Schematics.placeLaunchLoadout(spawn.x, spawn.y); - float difficulty = sector.baseCoverage; + for(Room espawn : enemies){ + tiles.getn(espawn.x, espawn.y).setOverlay(Blocks.spawn); + } if(sector.hasEnemyBase()){ basegen.generate(tiles, enemies.map(r -> tiles.getn(r.x, r.y)), tiles.get(spawn.x, spawn.y), state.rules.waveTeam, sector, difficulty); - state.rules.attackMode = true; + state.rules.attackMode = sector.info.attack = true; }else{ - state.rules.winWave = 15 * (int)Math.max(difficulty * 5, 1); + state.rules.winWave = sector.info.winWave = 10 + 5 * (int)Math.max(difficulty * 10, 1); } - state.rules.waves = true; + state.rules.waves = sector.info.waves = true; //TODO better waves - state.rules.spawns = defaultWaves.get(); + state.rules.spawns = DefaultWaves.generate(difficulty); } @Override diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index 9cc9535ee1..0d88d01034 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -26,6 +26,8 @@ import mindustry.mod.Mods.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; +import mindustry.world.blocks.units.*; +import mindustry.world.blocks.units.UnitFactory.*; import mindustry.world.consumers.*; import mindustry.world.draw.*; import mindustry.world.meta.*; @@ -36,7 +38,7 @@ import java.lang.reflect.*; public class ContentParser{ private static final boolean ignoreUnknownFields = true; ObjectMap, ContentType> contentTypes = new ObjectMap<>(); - ObjectSet> implicitNullable = ObjectSet.with(TextureRegion.class); + ObjectSet> implicitNullable = ObjectSet.with(TextureRegion.class, TextureRegion[].class, TextureRegion[][].class); ObjectMap, FieldParser> classParsers = new ObjectMap<>(){{ put(Effect.class, (type, data) -> field(Fx.class, data)); @@ -170,11 +172,9 @@ public class ContentParser{ readBundle(ContentType.block, name, value); Block block; - boolean exists; if(locate(ContentType.block, name) != null){ block = locate(ContentType.block, name); - exists = true; if(value.has("type")){ throw new IllegalArgumentException("When defining properties for an existing block, you must not re-declare its type. The original type will be used. Block: " + name); @@ -182,7 +182,6 @@ public class ContentParser{ }else{ //TODO generate dynamically instead of doing.. this Class type; - exists = false; try{ type = resolve(getType(value), @@ -191,6 +190,7 @@ public class ContentParser{ "mindustry.world.blocks.defense", "mindustry.world.blocks.defense.turrets", "mindustry.world.blocks.distribution", + "mindustry.world.blocks.environment", "mindustry.world.blocks.liquid", "mindustry.world.blocks.logic", "mindustry.world.blocks.power", @@ -208,14 +208,6 @@ public class ContentParser{ currentContent = block; - String[] research = {null}; - - //add research tech node - if(value.has("research")){ - research[0] = value.get("research").asString(); - value.remove("research"); - } - read(() -> { if(value.has("consumes")){ for(JsonValue child : value.get("consumes")){ @@ -246,33 +238,6 @@ public class ContentParser{ throw new IllegalArgumentException("Blocks cannot be larger than " + ConstructBlock.maxSize); } - //add research tech node - if(research[0] != null){ - //TODO only works with blocks - Block parent = find(ContentType.block, research[0]); - TechNode baseNode = exists && TechTree.all.contains(t -> t.content == block) ? TechTree.all.find(t -> t.content == block) : TechTree.create(parent, block); - LoadedMod cur = currentMod; - - postreads.add(() -> { - currentContent = block; - currentMod = cur; - - if(baseNode.parent != null){ - baseNode.parent.children.remove(baseNode); - } - - TechNode parnode = TechTree.all.find(t -> t.content == parent); - if(parnode == null){ - throw new IllegalArgumentException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched."); - } - if(!parnode.children.contains(baseNode)){ - parnode.children.add(baseNode); - } - baseNode.parent = parnode; - }); - - } - //make block visible by default if there are requirements and no visibility set if(value.has("requirements") && block.buildVisibility == BuildVisibility.hidden){ block.buildVisibility = BuildVisibility.shown; @@ -293,10 +258,65 @@ public class ContentParser{ } currentContent = unit; - read(() -> readFields(unit, value, true)); + //TODO test this! + read(() -> { + //add reconstructor type + if(value.has("requirements")){ + JsonValue rec = value.remove("requirements"); + + //intermediate class for parsing + class UnitReq{ + public Block block; + public ItemStack[] requirements = {}; + @Nullable + public UnitType previous; + public float time = 60f * 10f; + } + + UnitReq req = parser.readValue(UnitReq.class, rec); + + if(req.block instanceof Reconstructor r){ + if(req.previous != null){ + r.upgrades.add(new UnitType[]{req.previous, unit}); + } + }else if(req.block instanceof UnitFactory f){ + f.plans.add(new UnitPlan(unit, req.time, req.requirements)); + }else{ + throw new IllegalArgumentException("Missing a valid 'block' in 'requirements'"); + } + + } + + //read extra default waves + if(value.has("waves")){ + JsonValue waves = value.remove("waves"); + SpawnGroup[] groups = parser.readValue(SpawnGroup[].class, waves); + for(SpawnGroup group : groups){ + group.type = unit; + } + + Vars.defaultWaves.get().addAll(groups); + } + + readFields(unit, value, true); + }); return unit; }, + ContentType.weather, (TypeParser)(mod, name, value) -> { + Weather item; + if(locate(ContentType.weather, name) != null){ + item = locate(ContentType.weather, name); + readBundle(ContentType.weather, name, value); + }else{ + readBundle(ContentType.weather, name, value); + Class type = resolve(getType(value), "mindustry.type.weather"); + item = make(type); + } + currentContent = item; + read(() -> readFields(item, value)); + return item; + }, ContentType.item, parser(ContentType.item, Item::new), ContentType.liquid, parser(ContentType.liquid, Liquid::new) //ContentType.sector, parser(ContentType.sector, SectorPreset::new) @@ -324,8 +344,8 @@ public class ContentParser{ private TypeParser parser(ContentType type, Func constructor){ return (mod, name, value) -> { T item; - if(Vars.content.getByName(type, name) != null){ - item = (T)Vars.content.getByName(type, name); + if(locate(type, name) != null){ + item = (T)locate(type, name); readBundle(type, name, value); }else{ readBundle(type, name, value); @@ -563,6 +583,8 @@ public class ContentParser{ } void readFields(Object object, JsonValue jsonMap){ + JsonValue research = jsonMap.remove("research"); + toBeParsed.remove(object); Class type = object.getClass(); ObjectMap fields = parser.getFields(type); @@ -593,6 +615,57 @@ public class ContentParser{ throw ex; } } + + + if(object instanceof UnlockableContent unlock && research != null){ + + //add research tech node + String researchName; + ItemStack[] customRequirements; + + //research can be a single string or an object with parent and requirements + if(research.isString()){ + researchName = research.asString(); + customRequirements = null; + }else{ + researchName = research.getString("parent"); + customRequirements = research.has("requirements") ? parser.readValue(ItemStack[].class, research.get("requirements")) : null; + } + + //remove old node + TechNode lastNode = TechTree.all.find(t -> t.content == unlock); + if(lastNode != null){ + lastNode.remove(); + } + + TechNode node = new TechNode(null, unlock, customRequirements == null ? unlock.researchRequirements() : customRequirements); + LoadedMod cur = currentMod; + + postreads.add(() -> { + currentContent = unlock; + currentMod = cur; + + //remove old node from parent + if(node.parent != null){ + node.parent.children.remove(node); + } + + + //find parent node. + TechNode parent = TechTree.all.find(t -> t.content.name.equals(researchName) || t.content.name.equals(currentMod.name + "-" + researchName)); + + if(parent == null){ + throw new IllegalArgumentException("Content '" + researchName + "' isn't in the tech tree, but '" + unlock.name + "' requires it to be researched."); + } + + //add this node to the parent + if(!parent.children.contains(node)){ + parent.children.add(node); + } + //reparent the node + node.parent = parent; + }); + } } /** Tries to resolve a class from a list of potential class names. */ diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index 068a73062d..a596f3e7ae 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -170,8 +170,7 @@ public class Mods implements Loadable{ //generate new icons for(Seq arr : content.getContentMap()){ arr.each(c -> { - if(c instanceof UnlockableContent && c.minfo.mod != null){ - UnlockableContent u = (UnlockableContent)c; + if(c instanceof UnlockableContent u && c.minfo.mod != null){ u.load(); u.createIcons(packer); } @@ -630,7 +629,7 @@ public class Mods implements Loadable{ } //make sure the main class exists before loading it; if it doesn't just don't put it there - if(mainFile.exists()){ + if(mainFile.exists() && Core.settings.getBool("mod-" + meta.name.toLowerCase().replace(" ", "-") + "-enabled", true)){ //mobile versions don't support class mods if(ios){ throw new IllegalArgumentException("Java class mods are not supported on iOS."); diff --git a/core/src/mindustry/mod/Scripts.java b/core/src/mindustry/mod/Scripts.java index 1aa260e8fa..f372586863 100644 --- a/core/src/mindustry/mod/Scripts.java +++ b/core/src/mindustry/mod/Scripts.java @@ -59,12 +59,12 @@ public class Scripts implements Disposable{ if(o instanceof Undefined) o = "undefined"; return String.valueOf(o); }catch(Throwable t){ - return getError(t); + return getError(t, false); } } - private String getError(Throwable t){ - t.printStackTrace(); + private String getError(Throwable t, boolean log){ + if(log) Log.err(t); return t.getClass().getSimpleName() + (t.getMessage() == null ? "" : ": " + t.getMessage()); } @@ -138,7 +138,7 @@ public class Scripts implements Disposable{ if(currentMod != null){ file = currentMod.name + "/" + file; } - log(LogLevel.err, file, "" + getError(t)); + log(LogLevel.err, file, "" + getError(t, true)); return false; } } diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index f185744c28..ccf5f76755 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -577,7 +577,10 @@ public class Administration{ autosave("Whether the periodically save the map when playing.", false), autosaveAmount("The maximum amount of autosaves. Older ones get replaced.", 10), autosaveSpacing("Spacing between autosaves in seconds.", 60 * 5), - debug("Enable debug logging", false, () -> Log.setLogLevel(debug() ? LogLevel.debug : LogLevel.info)); + debug("Enable debug logging", false, () -> { + LogLevel level = debug() ? LogLevel.debug : LogLevel.info; + Log.level = level; + }); public static final Config[] all = values(); diff --git a/core/src/mindustry/net/ArcNetProvider.java b/core/src/mindustry/net/ArcNetProvider.java index bd4f948f89..91043037e8 100644 --- a/core/src/mindustry/net/ArcNetProvider.java +++ b/core/src/mindustry/net/ArcNetProvider.java @@ -361,8 +361,7 @@ public class ArcNetProvider implements NetProvider{ } public void writeFramework(ByteBuffer buffer, FrameworkMessage message){ - if(message instanceof Ping){ - Ping p = (Ping)message; + if(message instanceof Ping p){ buffer.put((byte)0); buffer.putInt(p.id); buffer.put(p.isReply ? 1 : (byte)0); @@ -370,12 +369,10 @@ public class ArcNetProvider implements NetProvider{ buffer.put((byte)1); }else if(message instanceof KeepAlive){ buffer.put((byte)2); - }else if(message instanceof RegisterUDP){ - RegisterUDP p = (RegisterUDP)message; + }else if(message instanceof RegisterUDP p){ buffer.put((byte)3); buffer.putInt(p.connectionID); - }else if(message instanceof RegisterTCP){ - RegisterTCP p = (RegisterTCP)message; + }else if(message instanceof RegisterTCP p){ buffer.put((byte)4); buffer.putInt(p.connectionID); } diff --git a/core/src/mindustry/net/CrashSender.java b/core/src/mindustry/net/CrashSender.java index fb37796d9c..0d2204890c 100644 --- a/core/src/mindustry/net/CrashSender.java +++ b/core/src/mindustry/net/CrashSender.java @@ -25,7 +25,7 @@ import static mindustry.Vars.*; public class CrashSender{ public static String createReport(String error){ - String report = "Mindustry has crashed. How unforunate.\n"; + String report = "Mindustry has crashed. How unfortunate.\n"; if(mods.list().size == 0 && Version.build != -1){ report += "Report this at " + Vars.reportIssueURL + "\n\n"; } diff --git a/core/src/mindustry/net/Net.java b/core/src/mindustry/net/Net.java index 89272f3470..0bf782600e 100644 --- a/core/src/mindustry/net/Net.java +++ b/core/src/mindustry/net/Net.java @@ -237,12 +237,10 @@ public class Net{ */ public void handleClientReceived(Object object){ - if(object instanceof StreamBegin){ - StreamBegin b = (StreamBegin)object; + if(object instanceof StreamBegin b){ streams.put(b.id, currentStream = new StreamBuilder(b)); - }else if(object instanceof StreamChunk){ - StreamChunk c = (StreamChunk)object; + }else if(object instanceof StreamChunk c){ StreamBuilder builder = streams.get(c.id); if(builder == null){ throw new RuntimeException("Received stream chunk without a StreamBegin beforehand!"); diff --git a/core/src/mindustry/net/NetworkIO.java b/core/src/mindustry/net/NetworkIO.java index 3a32d5cb6b..f4494e1c4f 100644 --- a/core/src/mindustry/net/NetworkIO.java +++ b/core/src/mindustry/net/NetworkIO.java @@ -3,7 +3,9 @@ package mindustry.net; import arc.*; import arc.util.*; import arc.util.io.*; +import mindustry.content.*; import mindustry.core.*; +import mindustry.ctype.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.io.*; @@ -21,6 +23,18 @@ public class NetworkIO{ public static void writeWorld(Player player, OutputStream os){ try(DataOutputStream stream = new DataOutputStream(os)){ + //write all researched content to rules if hosting + if(state.isCampaign()){ + state.rules.researched.clear(); + for(ContentType type : ContentType.all){ + for(Content c : content.getBy(type)){ + if(c instanceof UnlockableContent u && u.unlocked() && TechTree.get(u) != null){ + state.rules.researched.add(u.name); + } + } + } + } + stream.writeUTF(JsonIO.write(state.rules)); SaveIO.getSaveWriter().writeStringMap(stream, state.map.tags); diff --git a/core/src/mindustry/type/AmmoTypes.java b/core/src/mindustry/type/AmmoTypes.java index 6b3769b361..761bcbc8d0 100644 --- a/core/src/mindustry/type/AmmoTypes.java +++ b/core/src/mindustry/type/AmmoTypes.java @@ -41,15 +41,15 @@ public class AmmoTypes implements ContentList{ @Override public void resupply(Unit unit){ float range = unit.hitSize + 60f; - Tile closest = Vars.indexer.findClosestFlag(unit.x, unit.y, unit.team, BlockFlag.powerResupply); + Tile closest = Vars.indexer.findClosestFlag(unit.x, unit.y, unit.team, BlockFlag.battery); if(closest != null && closest.build != null && unit.within(closest.build, range) && closest.build.power != null){ var build = closest.build; if(build.block.consumes.hasPower() && build.block.consumes.getPower().buffered){ float amount = closest.build.power.status * build.block.consumes.getPower().capacity; - float powerPerAmmo = totalPower / unit.type().ammoCapacity; - float ammoRequired = unit.type().ammoCapacity - unit.ammo; + float powerPerAmmo = totalPower / unit.type.ammoCapacity; + float ammoRequired = unit.type.ammoCapacity - unit.ammo; float powerRequired = ammoRequired * powerPerAmmo; float powerTaken = Math.min(amount, powerRequired); diff --git a/core/src/mindustry/type/Item.java b/core/src/mindustry/type/Item.java index 9329efb47e..f52323d655 100644 --- a/core/src/mindustry/type/Item.java +++ b/core/src/mindustry/type/Item.java @@ -1,16 +1,15 @@ package mindustry.type; import arc.graphics.*; -import arc.scene.ui.layout.*; import arc.struct.*; import mindustry.ctype.*; -import mindustry.ui.*; import mindustry.world.blocks.environment.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; public class Item extends UnlockableContent{ - public final Color color; + public Color color; /** how explosive this item is. */ public float explosiveness = 0f; @@ -36,8 +35,10 @@ public class Item extends UnlockableContent{ } @Override - public void displayInfo(Table table){ - ContentDisplay.displayItem(table, this); + public void setStats(){ + stats.addPercent(Stat.explosiveness, explosiveness); + stats.addPercent(Stat.flammability, flammability); + stats.addPercent(Stat.radioactivity, radioactivity); } @Override diff --git a/core/src/mindustry/type/ItemSeq.java b/core/src/mindustry/type/ItemSeq.java index 0407f6a3f8..49055fb5b9 100644 --- a/core/src/mindustry/type/ItemSeq.java +++ b/core/src/mindustry/type/ItemSeq.java @@ -21,6 +21,13 @@ public class ItemSeq implements Iterable, Serializable{ stacks.each(this::add); } + public ItemSeq copy(){ + ItemSeq out = new ItemSeq(); + out.total = total; + System.arraycopy(values, 0, out.values, 0, values.length); + return out; + } + public void each(ItemConsumer cons){ for(int i = 0; i < values.length; i++){ if(values[i] != 0){ @@ -46,6 +53,19 @@ public class ItemSeq implements Iterable, Serializable{ return values[item.id] > 0; } + public boolean has(ItemSeq seq){ + for(int i = 0; i < values.length; i++){ + if(seq.values[i] > values[i]){ + return false; + } + } + return true; + } + + public boolean has(Item item, int amount){ + return values[item.id] >= amount; + } + public int get(Item item){ return values[item.id]; } diff --git a/core/src/mindustry/type/ItemStack.java b/core/src/mindustry/type/ItemStack.java index d5f4097b58..e2e0d2d5f4 100644 --- a/core/src/mindustry/type/ItemStack.java +++ b/core/src/mindustry/type/ItemStack.java @@ -64,6 +64,13 @@ public class ItemStack implements Comparable{ return item.compareTo(itemStack.item); } + @Override + public boolean equals(Object o){ + if(this == o) return true; + if(!(o instanceof ItemStack stack)) return false; + return amount == stack.amount && item == stack.item; + } + @Override public String toString(){ return "ItemStack{" + diff --git a/core/src/mindustry/type/Liquid.java b/core/src/mindustry/type/Liquid.java index 19e77a9987..e62805e60b 100644 --- a/core/src/mindustry/type/Liquid.java +++ b/core/src/mindustry/type/Liquid.java @@ -1,15 +1,14 @@ package mindustry.type; import arc.graphics.*; -import arc.scene.ui.layout.*; import arc.util.*; import mindustry.content.*; import mindustry.ctype.*; -import mindustry.ui.*; +import mindustry.world.meta.*; public class Liquid extends UnlockableContent{ /** Color used in pipes and on the ground. */ - public final Color color; + public Color color; /** Color used in bars. */ public @Nullable Color barColor; /** Color used to draw lights. Note that the alpha channel is used to dictate brightness. */ @@ -46,8 +45,12 @@ public class Liquid extends UnlockableContent{ } @Override - public void displayInfo(Table table){ - ContentDisplay.displayLiquid(table, this); + public void setStats(){ + stats.addPercent(Stat.explosiveness, explosiveness); + stats.addPercent(Stat.flammability, flammability); + stats.addPercent(Stat.temperature, temperature); + stats.addPercent(Stat.heatCapacity, heatCapacity); + stats.addPercent(Stat.viscosity, viscosity); } @Override diff --git a/core/src/mindustry/type/Planet.java b/core/src/mindustry/type/Planet.java index 8c4b40b4c2..4550ae6805 100644 --- a/core/src/mindustry/type/Planet.java +++ b/core/src/mindustry/type/Planet.java @@ -5,7 +5,6 @@ import arc.func.*; import arc.graphics.*; import arc.math.*; import arc.math.geom.*; -import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; import arc.util.noise.*; @@ -19,7 +18,7 @@ import static mindustry.Vars.*; public class Planet extends UnlockableContent{ /** Default spacing between planet orbits in world units. */ - private static final float orbitSpacing = 6f; + private static final float orbitSpacing = 8f; /** intersect() temp var. */ private static final Vec3 intersectResult = new Vec3(); /** Mesh used for rendering. Created on load() - will be null on the server! */ @@ -46,6 +45,8 @@ public class Planet extends UnlockableContent{ public float sectorApproxRadius; /** Whether this planet is tidally locked relative to its parent - see https://en.wikipedia.org/wiki/Tidal_locking */ public boolean tidalLock = false; + /** Whether or not this planet is listed in the planet access UI. **/ + public boolean accessible = true; /** The default starting sector displayed to the map dialog. */ public int startSector = 0; /** Whether the bloom render effect is enabled. */ @@ -175,7 +176,7 @@ public class Planet extends UnlockableContent{ public void updateBaseCoverage(){ for(Sector sector : sectors){ float sum = 1f; - for(Sector other : sector.inRange(2)){ + for(Sector other : sector.near()){ if(other.generateEnemyBase){ sum += 1f; } @@ -185,7 +186,7 @@ public class Planet extends UnlockableContent{ sum += 2f; } - sector.baseCoverage = Mathf.clamp(sum / 5f); + sector.baseCoverage = sector.preset == null ? Mathf.clamp(sum / 5f) : Mathf.clamp(sector.preset.difficulty / 10f); } } @@ -202,6 +203,10 @@ public class Planet extends UnlockableContent{ @Override public void init(){ + for(Sector sector : sectors){ + sector.loadInfo(); + } + if(generator != null){ Noise.setSeed(id + 1); @@ -253,13 +258,16 @@ public class Planet extends UnlockableContent{ return true; } - @Override - public void displayInfo(Table table){ - - } - @Override public ContentType getContentType(){ return ContentType.planet; } + + public boolean visible(){ + return true; + } + + public void draw(Mat3D projection, Mat3D transform){ + mesh.render(projection, transform); + } } diff --git a/core/src/mindustry/type/Sector.java b/core/src/mindustry/type/Sector.java index 6d042296d1..d9d54ba91c 100644 --- a/core/src/mindustry/type/Sector.java +++ b/core/src/mindustry/type/Sector.java @@ -7,14 +7,15 @@ import arc.struct.*; import arc.util.*; import mindustry.*; import mindustry.game.Saves.*; +import mindustry.game.*; import mindustry.graphics.g3d.PlanetGrid.*; +import mindustry.world.modules.*; import static mindustry.Vars.*; /** A small section of a planet. */ public class Sector{ - private static final Seq tmpSeq1 = new Seq<>(), tmpSeq2 = new Seq<>(), tmpSeq3 = new Seq<>(); - private static final ObjectSet tmpSet = new ObjectSet<>(); + private static final Seq tmpSeq1 = new Seq<>(); public final SectorRect rect; public final Plane plane; @@ -24,6 +25,7 @@ public class Sector{ public @Nullable SaveSlot save; public @Nullable SectorPreset preset; + public SectorInfo info = new SectorInfo(); /** Number 0-1 indicating the difficulty based on nearby bases. */ public float baseCoverage; @@ -37,60 +39,69 @@ public class Sector{ this.id = tile.id; } - public Seq inRange(int range){ - //TODO cleanup/remove - if(true){ - tmpSeq1.clear(); - neighbors(tmpSeq1::add); - - return tmpSeq1; + /** @return a copy of the items in this sector - may be core items, or stored data. */ + public ItemSeq getItems(){ + if(isBeingPlayed()){ + ItemSeq out = new ItemSeq(); + if(state.rules.defaultTeam.core() != null) out.add(state.rules.defaultTeam.core().items); + return out; + }else{ + return info.items; } - - tmpSeq1.clear(); - tmpSeq2.clear(); - tmpSet.clear(); - - tmpSeq1.add(this); - tmpSet.add(this); - for(int i = 0; i < range; i++){ - while(!tmpSeq1.isEmpty()){ - Sector sec = tmpSeq1.pop(); - tmpSet.add(sec); - sec.neighbors(other -> { - if(tmpSet.add(other)){ - tmpSeq2.add(other); - } - }); - } - tmpSeq1.clear(); - tmpSeq1.addAll(tmpSeq2); - } - - tmpSeq3.clear().addAll(tmpSeq2); - return tmpSeq3; } - public void neighbors(Cons cons){ + public Seq near(){ + tmpSeq1.clear(); + for(Ptile tile : tile.tiles){ + tmpSeq1.add(planet.getSector(tile)); + } + + return tmpSeq1; + } + + public void near(Cons cons){ for(Ptile tile : tile.tiles){ cons.get(planet.getSector(tile)); } } /** @return whether this sector can be landed on at all. - * Only sectors adjacent to non-wave sectors can be landed on. - * TODO also preset sectors*/ + * Only sectors adjacent to non-wave sectors can be landed on. */ public boolean unlocked(){ return hasBase() || (preset != null && preset.alwaysUnlocked); } + public void saveInfo(){ + Core.settings.putJson(planet.name + "-s-" + id + "-info", info); + } + + public void loadInfo(){ + info = Core.settings.getJson(planet.name + "-s-" + id + "-info", SectorInfo.class, SectorInfo::new); + } + + /** Removes any sector info. */ + public void clearInfo(){ + info = new SectorInfo(); + Core.settings.remove(planet.name + "-s-" + id + "-info"); + } + + public float getProductionScale(){ + return Math.max(1f - info.damage, 0); + } + + public boolean isAttacked(){ + if(isBeingPlayed()) return state.rules.waves; + return save != null && info.waves && info.hasCore; + } + /** @return whether the player has a base here. */ public boolean hasBase(){ - return save != null && !save.meta.tags.getBool("nocores"); + return save != null && info.hasCore; } /** @return whether the enemy has a generated base here. */ public boolean hasEnemyBase(){ - return generateEnemyBase && (save == null || save.meta.rules.waves); + return generateEnemyBase && (save == null || info.waves); } public boolean isBeingPlayed(){ @@ -98,13 +109,18 @@ public class Sector{ return Vars.state.isGame() && Vars.state.rules.sector == this && !Vars.state.gameOver; } - public boolean isCaptured(){ - return save != null && !save.meta.rules.waves; + public String name(){ + if(preset != null) return preset.localizedName; + return info.name == null ? id + "" : info.name; } - /** @return whether waves are present - if true, any bases here will be attacked. */ - public boolean hasWaves(){ - return save != null && save.meta.rules.waves; + public void setName(String name){ + info.name = name; + saveInfo(); + } + + public boolean isCaptured(){ + return save != null && !info.waves; } public boolean hasSave(){ @@ -129,155 +145,50 @@ public class Sector{ return res % 2 == 0 ? res : res + 1; } - //TODO this should be stored in a more efficient structure, and be updated each turn - public ItemSeq getExtraItems(){ - return Core.settings.getJson(key("extra-items"), ItemSeq.class, ItemSeq::new); - } - - public void setExtraItems(ItemSeq stacks){ - Core.settings.putJson(key("extra-items"), stacks); - } - public void addItem(Item item, int amount){ removeItem(item, -amount); } + public void removeItems(ItemSeq items){ + ItemSeq copy = items.copy(); + copy.each((i, a) -> copy.set(i, -a)); + addItems(copy); + } + public void removeItem(Item item, int amount){ + ItemSeq seq = new ItemSeq(); + seq.add(item, -amount); + addItems(seq); + } + + public void addItems(ItemSeq items){ if(isBeingPlayed()){ if(state.rules.defaultTeam.core() != null){ - state.rules.defaultTeam.items().remove(item, amount); + ItemModule storage = state.rules.defaultTeam.items(); + int cap = state.rules.defaultTeam.core().storageCapacity; + items.each((item, amount) -> storage.add(item, Math.min(cap - storage.get(item), amount))); } - }else{ - ItemSeq recv = getExtraItems(); - - if(save != null){ - //"shave off" extra items - - ItemSeq count = new ItemSeq(); - - //add items already present - count.add(save.meta.secinfo.coreItems); - - count.add(calculateReceivedItems()); - - int capacity = save.meta.secinfo.storageCapacity; - - //when over capacity, add that to the extra items - count.each((i, a) -> { - if(a > capacity){ - recv.remove(i, (a - capacity)); - } - }); - } - - recv.remove(item, amount); - - setExtraItems(recv); + }else if(hasBase()){ + items.each((item, amount) -> info.items.add(item, Math.min(info.storageCapacity - info.items.get(item), amount))); + saveInfo(); } } - public ItemSeq calculateItems(){ + /** @return items currently in this sector, taking into account playing state. */ + public ItemSeq items(){ ItemSeq count = new ItemSeq(); //for sectors being played on, add items directly if(isBeingPlayed()){ count.add(state.rules.defaultTeam.items()); - }else if(save != null){ + }else{ //add items already present - count.add(save.meta.secinfo.coreItems); - - count.add(calculateReceivedItems()); - - int capacity = save.meta.secinfo.storageCapacity; - - //validation - count.each((item, amount) -> { - //ensure positive items - if(amount < 0) count.set(item, 0); - //cap the items - if(amount > capacity) count.set(item, capacity); - }); + count.add(info.items); } return count; } - public ItemSeq calculateReceivedItems(){ - ItemSeq count = new ItemSeq(); - - if(save != null){ - long seconds = getSecondsPassed(); - - //add produced items - save.meta.secinfo.production.each((item, stat) -> count.add(item, (int)(stat.mean * seconds))); - - //add received items - count.add(getExtraItems()); - } - - return count; - } - - //TODO these methods should maybe move somewhere else and/or be contained in a data object - public void setSpawnPosition(int position){ - put("spawn-position", position); - } - - /** Only valid after this sector has been landed on once. */ - //TODO move to sector data? - public int getSpawnPosition(){ - return Core.settings.getInt(key("spawn-position"), Point2.pack(world.width() / 2, world.height() / 2)); - } - - /** @return time spent in this sector this turn in ticks. */ - public float getTimeSpent(){ - //return currently counting time spent if being played on - if(isBeingPlayed()) return state.secinfo.internalTimeSpent; - - //else return the stored value - return getStoredTimeSpent(); - } - - public void setTimeSpent(float time){ - put("time-spent", time); - - //update counting time - if(isBeingPlayed()){ - state.secinfo.internalTimeSpent = time; - } - } - - public String displayTimeRemaining(){ - float amount = Vars.turnDuration - getTimeSpent(); - int seconds = (int)(amount / 60); - int sf = seconds % 60; - return (seconds / 60) + ":" + (sf < 10 ? "0" : "") + sf; - } - - /** @return the stored amount of time spent in this sector this turn in ticks. - * Do not use unless you know what you're doing. */ - public float getStoredTimeSpent(){ - return Core.settings.getFloat(key("time-spent")); - } - - public void setSecondsPassed(int number){ - put("secondsi-passed", number); - } - - /** @return how much time has passed in this sector without the player resuming here. - * Used for resource production calculations. */ - public int getSecondsPassed(){ - return Core.settings.getInt(key("secondsi-passed")); - } - - private String key(String key){ - return planet.name + "-s-" + id + "-" + key; - } - - private void put(String key, Object value){ - Core.settings.put(key(key), value); - } - public String toString(){ return planet.name + "#" + id; } diff --git a/core/src/mindustry/type/SectorPreset.java b/core/src/mindustry/type/SectorPreset.java index c38ea7ad9f..0e9b90fb30 100644 --- a/core/src/mindustry/type/SectorPreset.java +++ b/core/src/mindustry/type/SectorPreset.java @@ -2,7 +2,6 @@ package mindustry.type; import arc.func.*; import arc.graphics.g2d.*; -import arc.scene.ui.layout.*; import mindustry.ctype.*; import mindustry.game.*; import mindustry.gen.*; @@ -16,11 +15,14 @@ public class SectorPreset extends UnlockableContent{ public int captureWave = 0; public Cons rules = rules -> rules.winWave = captureWave; + /** Difficulty, 0-10. */ + public float difficulty; public SectorPreset(String name, Planet planet, int sector){ super(name); this.generator = new FileMapGenerator(name); this.planet = planet; + sector %= planet.sectors.size; this.sector = planet.sectors.get(sector); planet.preset(sector, this); @@ -36,11 +38,6 @@ public class SectorPreset extends UnlockableContent{ return true; } - //neither of these are implemented, as zones are not displayed in a normal fashion... yet - @Override - public void displayInfo(Table table){ - } - @Override public ContentType getContentType(){ return ContentType.sector; diff --git a/core/src/mindustry/type/StatusEffect.java b/core/src/mindustry/type/StatusEffect.java index fda8dbbbf2..90488c62ea 100644 --- a/core/src/mindustry/type/StatusEffect.java +++ b/core/src/mindustry/type/StatusEffect.java @@ -13,8 +13,8 @@ import mindustry.gen.*; public class StatusEffect extends MappableContent{ /** Damage dealt by the unit with the effect. */ public float damageMultiplier = 1f; - /** Unit armor multiplier. */ - public float armorMultiplier = 1f; + /** Unit health multiplier. */ + public float healthMultiplier = 1f; /** Unit speed multiplier */ public float speedMultiplier = 1f; /** Unit speed multiplier */ @@ -56,7 +56,7 @@ public class StatusEffect extends MappableContent{ } if(effect != Fx.none && Mathf.chanceDelta(effectChance)){ - Tmp.v1.rnd(unit.type().hitSize /2f); + Tmp.v1.rnd(unit.type.hitSize /2f); effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y); } } diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index f927bc83d5..8a2d274b44 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -18,7 +18,6 @@ import mindustry.core.*; import mindustry.ctype.*; import mindustry.entities.*; import mindustry.entities.abilities.*; -import mindustry.entities.bullet.*; import mindustry.entities.units.*; import mindustry.game.*; import mindustry.gen.*; @@ -29,6 +28,8 @@ import mindustry.world.blocks.environment.*; import mindustry.world.blocks.payloads.*; import mindustry.world.blocks.units.*; import mindustry.world.consumers.*; +import mindustry.world.meta.*; +import mindustry.world.meta.values.*; import static mindustry.Vars.*; @@ -42,7 +43,7 @@ public class UnitType extends UnlockableContent{ public Prov defaultController = () -> !flying ? new GroundAI() : new FlyingAI(); public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f; public float drag = 0.3f, accel = 0.5f, landShake = 0f, rippleScale = 1f, fallSpeed = 0.018f; - public float health = 200f, range = -1, armor = 0f; + public float health = 200f, range = -1, armor = 0f, maxRange = -1f; public float crashDamageMultiplier = 1f; public boolean targetAir = true, targetGround = true; public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false; @@ -51,7 +52,7 @@ public class UnitType extends UnlockableContent{ public float groundLayer = Layer.groundUnit; public float payloadCapacity = 8; public float aimDst = -1f; - public int commandLimit = 24; + public int commandLimit = 8; public float visualElevation = -1f; public boolean allowLegStep = false; public boolean hovering = false; @@ -59,6 +60,7 @@ public class UnitType extends UnlockableContent{ public Effect fallEffect = Fx.fallSmoke; public Effect fallThrusterEffect = Fx.fallSmoke; public Seq abilities = new Seq<>(); + public BlockFlag targetFlag = BlockFlag.generator; public int legCount = 4, legGroupSize = 2; public float legLength = 10f, legSpeed = 0.1f, legTrns = 1f, legBaseOffset = 0f, legMoveSpace = 1f, legExtension = 0, legPairOffset = 0, legLengthScl = 1f, kinematicScl = 1f, maxStretch = 1.75f; @@ -80,6 +82,8 @@ public class UnitType extends UnlockableContent{ public int mineTier = -1; public float buildSpeed = 1f, mineSpeed = 1f; + /** This is a VERY ROUGH estimate of unit DPS. */ + public float dpsEstimate = -1; public float clipSize = -1; public boolean canDrown = true; public float engineOffset = 5f, engineSize = 2.5f; @@ -116,7 +120,7 @@ public class UnitType extends UnlockableContent{ public Unit create(Team team){ Unit unit = constructor.get(); unit.team = team; - unit.type(this); + unit.setType(this); unit.ammo = ammoCapacity; //fill up on ammo upon creation unit.elevation = flying ? 1f : 0; unit.heal(); @@ -155,14 +159,21 @@ public class UnitType extends UnlockableContent{ table.table(bars -> { bars.defaults().growX().height(20f).pad(4); - bars.add(new Bar("blocks.health", Pal.health, unit::healthf).blink(Color.white)); + bars.add(new Bar("stat.health", Pal.health, unit::healthf).blink(Color.white)); bars.row(); if(state.rules.unitAmmo){ - bars.add(new Bar(ammoType.icon + " " + Core.bundle.get("blocks.ammo"), ammoType.barColor, () -> unit.ammo / ammoCapacity)); + bars.add(new Bar(ammoType.icon + " " + Core.bundle.get("stat.ammo"), ammoType.barColor, () -> unit.ammo / ammoCapacity)); bars.row(); } }).growX(); + + if(unit.controller() instanceof LogicAI){ + table.row(); + table.add(Blocks.microProcessor.emoji() + " " + Core.bundle.get("units.processorcontrol")).growX().left(); + table.row(); + table.label(() -> Iconc.settings + " " + (long)unit.flag + "").color(Color.lightGray).growX().wrap().left(); + } table.row(); } @@ -171,8 +182,7 @@ public class UnitType extends UnlockableContent{ public void getDependencies(Cons cons){ //units require reconstructors being researched for(Block block : content.blocks()){ - if(block instanceof Reconstructor){ - Reconstructor r = (Reconstructor)block; + if(block instanceof Reconstructor r){ for(UnitType[] recipe : r.upgrades){ //result of reconstruction is this, so it must be a dependency if(recipe[1] == this){ @@ -183,10 +193,37 @@ public class UnitType extends UnlockableContent{ } } - @Override - public void displayInfo(Table table){ - ContentDisplay.displayUnit(table, this); + public void setStats(){ + Unit inst = constructor.get(); + + stats.add(Stat.health, health); + stats.add(Stat.speed, speed); + stats.add(Stat.itemCapacity, health); + stats.add(Stat.range, (int)(maxRange / tilesize), StatUnit.blocks); + stats.add(Stat.commandLimit, commandLimit); + //TODO abilities, maybe try something like DPS + + if(abilities.any()){ + var unique = new ObjectSet(); + + for(Ability a : abilities){ + if(unique.add(a.localized())){ + stats.add(Stat.abilities, a.localized()); + } + } + } + + if(inst instanceof Minerc && mineTier >= 1){ + stats.addPercent(Stat.mineSpeed, mineSpeed); + stats.add(Stat.mineTier, new BlockFilterValue(b -> b instanceof Floor f && f.itemDrop != null && f.itemDrop.hardness <= mineTier && !f.playerUnmineable)); + } + if(inst instanceof Builderc){ + stats.addPercent(Stat.buildSpeed, buildSpeed); + } + if(inst instanceof Payloadc){ + stats.add(Stat.payloadCapacity, (payloadCapacity / (tilesize * tilesize)), StatUnit.blocksSquared); + } } @CallSuper @@ -206,14 +243,23 @@ public class UnitType extends UnlockableContent{ singleTarget = weapons.size <= 1; if(itemCapacity < 0){ - itemCapacity = Math.max(Mathf.round(hitSize * 7, 20), 20); + itemCapacity = Math.max(Mathf.round(hitSize * 4, 10), 10); } //set up default range if(range < 0){ range = Float.MAX_VALUE; for(Weapon weapon : weapons){ - range = Math.min(range, weapon.bullet.range() + hitSize /2f); + range = Math.min(range, weapon.bullet.range() + hitSize / 2f); + maxRange = Math.max(maxRange, weapon.bullet.range() + hitSize / 2f); + } + } + + if(maxRange < 0){ + maxRange = 0f; + + for(Weapon weapon : weapons){ + maxRange = Math.max(maxRange, weapon.bullet.range() + hitSize / 2f); } } @@ -230,7 +276,7 @@ public class UnitType extends UnlockableContent{ mechStepParticles = hitSize > 15f; } - canHeal = weapons.contains(w -> w.bullet instanceof HealBulletType); + canHeal = weapons.contains(w -> w.bullet.healPercent > 0f); //add mirrored weapon variants Seq mapped = new Seq<>(); @@ -263,6 +309,17 @@ public class UnitType extends UnlockableContent{ ammoCapacity = Math.max(1, (int)(shotsPerSecond * targetSeconds)); } + + //calculate estimated DPS for one target based on weapons + if(dpsEstimate < 0){ + dpsEstimate = weapons.sumf(w -> (w.bullet.estimateDPS() / w.reload) * w.shots * 60f); + + //suicide enemy + if(weapons.contains(w -> w.bullet.killShooter)){ + //scale down DPS to be insignificant + dpsEstimate /= 100f; + } + } } @CallSuper @@ -292,21 +349,21 @@ public class UnitType extends UnlockableContent{ ItemStack[] stacks = null; //calculate costs based on reconstructors or factories found - Block rec = content.blocks().find(b -> b instanceof Reconstructor && Structs.contains(((Reconstructor)b).upgrades, u -> u[1] == this)); + Block rec = content.blocks().find(b -> b instanceof Reconstructor && ((Reconstructor)b).upgrades.contains(u -> u[1] == this)); if(rec != null && rec.consumes.has(ConsumeType.item) && rec.consumes.get(ConsumeType.item) instanceof ConsumeItems){ stacks = ((ConsumeItems)rec.consumes.get(ConsumeType.item)).items; }else{ - UnitFactory factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory && Structs.contains(((UnitFactory)u).plans, p -> p.unit == this)); + UnitFactory factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory && ((UnitFactory)u).plans.contains(p -> p.unit == this)); if(factory != null){ - stacks = Structs.find(factory.plans, p -> p.unit == this).requirements; + stacks = factory.plans.find(p -> p.unit == this).requirements; } } if(stacks != null){ ItemStack[] out = new ItemStack[stacks.length]; for(int i = 0; i < out.length; i++){ - out[i] = new ItemStack(stacks[i].item, UI.roundAmount((int)(Math.pow(stacks[i].amount, 1.1) * 50))); + out[i] = new ItemStack(stacks[i].item, UI.roundAmount((int)(Math.pow(stacks[i].amount, 1) * 50))); } return out; @@ -433,7 +490,7 @@ public class UnitType extends UnlockableContent{ applyColor(unit); //draw back items - if(unit.hasItem() && unit.itemTime > 0.01f){ + if(unit.item() != null && unit.itemTime > 0.01f){ float size = (itemSize + Mathf.absin(Time.time(), 5f, 1f)) * unit.itemTime; Draw.mixcol(Pal.accent, Mathf.absin(Time.time(), 5f, 0.5f)); diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index 63a6c33ce7..2038374ad5 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -70,6 +70,8 @@ public class Weapon{ public int otherSide = -1; /** sound used for shooting */ public Sound shootSound = Sounds.pew; + /** sound used for weapons that have a delay */ + public Sound chargeSound = Sounds.none; /** sound played when there is nothing to shoot */ public Sound noAmmoSound = Sounds.click; /** displayed region (autoloaded) */ diff --git a/core/src/mindustry/type/Weather.java b/core/src/mindustry/type/Weather.java index 8fb30aecb6..4d17ab7c0e 100644 --- a/core/src/mindustry/type/Weather.java +++ b/core/src/mindustry/type/Weather.java @@ -1,16 +1,18 @@ package mindustry.type; +import arc.*; import arc.func.*; +import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; -import arc.scene.ui.layout.*; import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.ctype.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.world.*; import mindustry.world.blocks.*; import static mindustry.Vars.*; @@ -91,9 +93,136 @@ public abstract class Weather extends UnlockableContent{ } - @Override - public void displayInfo(Table table){ - //do not + public void drawParticles(TextureRegion region, Color color, + float sizeMin, float sizeMax, + float density, float intensity, float opacity, + float windx, float windy, + float minAlpha, float maxAlpha, + float sinSclMin, float sinSclMax, float sinMagMin, float sinMagMax){ + rand.setSeed(0); + Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale()); + Tmp.r1.grow(sizeMax * 1.5f); + Core.camera.bounds(Tmp.r2); + int total = (int)(Tmp.r1.area() / density * intensity); + Draw.color(color, opacity); + + for(int i = 0; i < total; i++){ + float scl = rand.random(0.5f, 1f); + float scl2 = rand.random(0.5f, 1f); + float size = rand.random(sizeMin, sizeMax); + float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2); + float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl); + float alpha = rand.random(minAlpha, maxAlpha); + + x += Mathf.sin(y, rand.random(sinSclMin, sinSclMax), rand.random(sinMagMin, sinMagMax)); + + x -= Tmp.r1.x; + y -= Tmp.r1.y; + x = Mathf.mod(x, Tmp.r1.width); + y = Mathf.mod(y, Tmp.r1.height); + x += Tmp.r1.x; + y += Tmp.r1.y; + + if(Tmp.r3.setCentered(x, y, size).overlaps(Tmp.r2)){ + Draw.alpha(alpha * opacity); + Draw.rect(region, x, y, size, size); + } + } + } + + public void drawRain(float sizeMin, float sizeMax, float xspeed, float yspeed, float density, float intensity, float stroke, Color color){ + float padding = sizeMax*0.9f; + + Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale()); + Tmp.r1.grow(padding); + Core.camera.bounds(Tmp.r2); + int total = (int)(Tmp.r1.area() / density * intensity); + Lines.stroke(stroke); + float alpha = Draw.getColor().a; + Draw.color(color); + + for(int i = 0; i < total; i++){ + float scl = rand.random(0.5f, 1f); + float scl2 = rand.random(0.5f, 1f); + float size = rand.random(sizeMin, sizeMax); + float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2); + float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl); + float tint = rand.random(1f) * alpha; + + x -= Tmp.r1.x; + y -= Tmp.r1.y; + x = Mathf.mod(x, Tmp.r1.width); + y = Mathf.mod(y, Tmp.r1.height); + x += Tmp.r1.x; + y += Tmp.r1.y; + + if(Tmp.r3.setCentered(x, y, size).overlaps(Tmp.r2)){ + Draw.alpha(tint); + Lines.lineAngle(x, y, Angles.angle(xspeed * scl2, - yspeed * scl), size/2f); + } + } + } + + public void drawSplashes(TextureRegion[] splashes, float padding, float density, float intensity, float opacity, float timeScale, float stroke, Color color, Liquid splasher){ + Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale()); + Tmp.r1.grow(padding); + Core.camera.bounds(Tmp.r2); + int total = (int)(Tmp.r1.area() / density * intensity) / 2; + Lines.stroke(stroke); + + float t = Time.time() / timeScale; + + for(int i = 0; i < total; i++){ + float offset = rand.random(0f, 1f); + float time = t + offset; + + int pos = (int)((time)); + float life = time % 1f; + float x = (rand.random(0f, world.unitWidth()) + pos*953); + float y = (rand.random(0f, world.unitHeight()) - pos*453); + + x -= Tmp.r1.x; + y -= Tmp.r1.y; + x = Mathf.mod(x, Tmp.r1.width); + y = Mathf.mod(y, Tmp.r1.height); + x += Tmp.r1.x; + y += Tmp.r1.y; + + if(Tmp.r3.setCentered(x, y, life * 4f).overlaps(Tmp.r2)){ + Tile tile = world.tileWorld(x, y); + + //only create splashes on specific liquid. + if(tile != null && tile.floor().liquidDrop == splasher){ + Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.5f).a(opacity)); + Draw.rect(splashes[(int)(life * (splashes.length - 1))], x, y); + }else if(tile != null && tile.floor().liquidDrop == null && !tile.floor().solid){ + Draw.color(color); + Draw.alpha(Mathf.slope(life) * opacity); + + float space = 45f; + for(int j : new int[]{-1, 1}){ + Tmp.v1.trns(90f + j*space, 1f + 5f * life); + Lines.lineAngle(x + Tmp.v1.x, y + Tmp.v1.y, 90f + j*space, 3f * (1f - life)); + } + } + } + } + } + + public void drawNoise(Texture noise, Color color, float noisescl, float opacity, float baseSpeed, float intensity, float vwindx, float vwindy, float offset){ + Draw.alpha(opacity); + Draw.tint(color); + + float speed = baseSpeed * intensity; + float windx = vwindx * speed, windy = vwindy * speed; + + float scale = 1f / noisescl; + float scroll = Time.time() * scale + offset; + Tmp.tr1.texture = noise; + Core.camera.bounds(Tmp.r1); + Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale); + Tmp.tr1.scroll(-windx * scroll, -windy * scroll); + Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height); } @Override diff --git a/core/src/mindustry/type/weather/ParticleWeather.java b/core/src/mindustry/type/weather/ParticleWeather.java new file mode 100644 index 0000000000..060e9cbe62 --- /dev/null +++ b/core/src/mindustry/type/weather/ParticleWeather.java @@ -0,0 +1,90 @@ +package mindustry.type.weather; + +import arc.*; +import arc.graphics.*; +import arc.graphics.Texture.*; +import arc.graphics.g2d.*; +import arc.util.*; +import mindustry.gen.*; +import mindustry.type.*; + +public class ParticleWeather extends Weather{ + public String particleRegion = "circle-shadow"; + public Color color = Color.white.cpy(); + public TextureRegion region; + public float yspeed = -2f, xspeed = 0.25f, padding = 16f, sizeMin = 2.4f, sizeMax = 12f, density = 1200f, minAlpha = 1f, maxAlpha = 1f, force = 0, noiseScale = 2000f, baseSpeed = 6.1f; + public float sinSclMin = 30f, sinSclMax = 80f, sinMagMin = 1f, sinMagMax = 7f; + + public Color noiseColor = color; + public boolean drawNoise = false, drawParticles = true, useWindVector = false; + public int noiseLayers = 1; + public float noiseLayerSpeedM = 1.1f, noiseLayerAlphaM = 0.8f, noiseLayerSclM = 0.99f, noiseLayerColorM = 1f; + public String noisePath = "noiseAlpha"; + public @Nullable Texture noise; + + public ParticleWeather(String name){ + super(name); + } + + @Override + public void load(){ + super.load(); + + region = Core.atlas.find(particleRegion); + + //load noise texture + //TODO mod support + if(drawNoise){ + Core.assets.load("sprites/" + noisePath + ".png", Texture.class); + } + } + + @Override + public void update(WeatherState state){ + float speed = force * state.intensity; + if(speed > 0.001f){ + float windx = state.windVector.x * speed, windy = state.windVector.y * speed; + + for(Unit unit : Groups.unit){ + unit.impulse(windx, windy); + } + } + } + + @Override + public void drawOver(WeatherState state){ + + float windx, windy; + if(useWindVector){ + float speed = baseSpeed * state.intensity; + windx = state.windVector.x * speed; + windy = state.windVector.y * speed; + }else{ + windx = this.xspeed; + windy = this.yspeed; + } + + if(drawNoise){ + if(noise == null){ + noise = Core.assets.get("sprites/" + noisePath + ".png", Texture.class); + noise.setWrap(TextureWrap.repeat); + noise.setFilter(TextureFilter.linear); + } + + float sspeed = 1f, sscl = 1f, salpha = 1f, offset = 0f; + Color col = Tmp.c1.set(noiseColor); + for(int i = 0; i < noiseLayers; i++){ + drawNoise(noise, noiseColor, noiseScale * sscl, state.opacity * salpha * opacityMultiplier, baseSpeed * sspeed, state.intensity, windx, windy, offset); + sspeed *= noiseLayerSpeedM; + salpha *= noiseLayerAlphaM; + sscl *= noiseLayerSclM; + offset += 0.29f; + col.mul(noiseLayerColorM); + } + } + + if(drawParticles){ + drawParticles(region, color, sizeMin, sizeMax, density, state.intensity, state.opacity, windx, windy, minAlpha, maxAlpha, sinSclMin, sinSclMax, sinMagMin, sinMagMax); + } + } +} diff --git a/core/src/mindustry/type/weather/RainWeather.java b/core/src/mindustry/type/weather/RainWeather.java new file mode 100644 index 0000000000..78fd096062 --- /dev/null +++ b/core/src/mindustry/type/weather/RainWeather.java @@ -0,0 +1,38 @@ +package mindustry.type.weather; + +import arc.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import mindustry.content.*; +import mindustry.gen.*; +import mindustry.type.*; + +public class RainWeather extends Weather{ + public float yspeed = 5f, xspeed = 1.5f, padding = 16f, density = 1200f, stroke = 0.75f, sizeMin = 8f, sizeMax = 40f, splashTimeScale = 22f; + public Liquid liquid = Liquids.water; + public TextureRegion[] splashes = new TextureRegion[12]; + public Color color = Color.valueOf("7a95eaff"); + + public RainWeather(String name){ + super(name); + } + + @Override + public void load(){ + super.load(); + + for(int i = 0; i < splashes.length; i++){ + splashes[i] = Core.atlas.find("splash-" + i); + } + } + + @Override + public void drawOver(WeatherState state){ + drawRain(sizeMin, sizeMax, xspeed, yspeed, density, state.intensity, stroke, color); + } + + @Override + public void drawUnder(WeatherState state){ + drawSplashes(splashes, sizeMax, density, state.intensity, state.opacity, splashTimeScale, stroke, color, liquid); + } +} diff --git a/core/src/mindustry/ui/ContentDisplay.java b/core/src/mindustry/ui/ContentDisplay.java deleted file mode 100644 index 6eefedcd53..0000000000 --- a/core/src/mindustry/ui/ContentDisplay.java +++ /dev/null @@ -1,165 +0,0 @@ -package mindustry.ui; - -import arc.*; -import arc.graphics.*; -import arc.scene.ui.layout.*; -import arc.struct.*; -import arc.util.*; -import mindustry.gen.*; -import mindustry.graphics.*; -import mindustry.type.*; -import mindustry.world.*; -import mindustry.world.meta.*; - -public class ContentDisplay{ - - public static void displayBlock(Table table, Block block){ - - table.table(title -> { - int size = 8 * 6; - - title.image(block.icon(Cicon.xlarge)).size(size); - title.add("[accent]" + block.localizedName).padLeft(5); - }); - - table.row(); - - table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX(); - - table.row(); - - if(block.description != null){ - table.add(block.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX(); - table.row(); - - table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX(); - table.row(); - } - - BlockStats stats = block.stats; - - for(StatCategory cat : stats.toMap().keys()){ - OrderedMap> map = stats.toMap().get(cat); - - if(map.size == 0) continue; - - table.add("@category." + cat.name()).color(Pal.accent).fillX(); - table.row(); - - for(BlockStat stat : map.keys()){ - table.table(inset -> { - inset.left(); - inset.add("[lightgray]" + stat.localized() + ":[] ").left(); - Seq arr = map.get(stat); - for(StatValue value : arr){ - value.display(inset); - inset.add().size(10f); - } - - }).fillX().padLeft(10); - table.row(); - } - } - } - - public static void displayItem(Table table, Item item){ - - table.table(title -> { - title.image(item.icon(Cicon.xlarge)).size(8 * 6); - title.add("[accent]" + item.localizedName).padLeft(5); - }); - - table.row(); - - table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); - - table.row(); - - if(item.description != null){ - table.add(item.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX(); - table.row(); - - table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); - table.row(); - } - - table.left().defaults().fillX(); - - table.add(Core.bundle.format("item.explosiveness", (int)(item.explosiveness * 100))); - table.row(); - table.add(Core.bundle.format("item.flammability", (int)(item.flammability * 100))); - table.row(); - table.add(Core.bundle.format("item.radioactivity", (int)(item.radioactivity * 100))); - table.row(); - } - - public static void displayLiquid(Table table, Liquid liquid){ - - table.table(title -> { - title.image(liquid.icon(Cicon.xlarge)).size(8 * 6); - title.add("[accent]" + liquid.localizedName).padLeft(5); - }); - - table.row(); - - table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); - - table.row(); - - if(liquid.description != null){ - table.add(liquid.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX(); - table.row(); - - table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); - table.row(); - } - - table.left().defaults().fillX(); - - table.add(Core.bundle.format("item.explosiveness", (int)(liquid.explosiveness * 100))); - table.row(); - table.add(Core.bundle.format("item.flammability", (int)(liquid.flammability * 100))); - table.row(); - table.add(Core.bundle.format("liquid.heatcapacity", (int)(liquid.heatCapacity * 100))); - table.row(); - table.add(Core.bundle.format("liquid.temperature", (int)(liquid.temperature * 100))); - table.row(); - table.add(Core.bundle.format("liquid.viscosity", (int)(liquid.viscosity * 100))); - table.row(); - } - - public static void displayUnit(Table table, UnitType unit){ - table.table(title -> { - title.image(unit.icon(Cicon.xlarge)).size(8 * 6).scaling(Scaling.fit); - title.add("[accent]" + unit.localizedName).padLeft(5); - }); - - table.row(); - - table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); - - table.row(); - - if(unit.description != null){ - table.add(unit.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX(); - table.row(); - - table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); - table.row(); - } - - table.left().defaults().fillX(); - - Unit inst = unit.constructor.get(); - - //TODO more stats - table.add(Core.bundle.format("unit.health", unit.health)).row(); - table.add(Core.bundle.format("unit.speed", Strings.fixed(unit.speed, 1))).row(); - table.add(Core.bundle.format("unit.itemcapacity", unit.itemCapacity)).row(); - - if(inst instanceof Minerc) table.add(Core.bundle.format("unit.minespeed", (int)(unit.mineSpeed * 100f))).row(); - if(inst instanceof Builderc) table.add(Core.bundle.format("unit.buildspeed", (int)(unit.buildSpeed * 100f))).row(); - - table.row(); - } -} diff --git a/core/src/mindustry/ui/IntFormat.java b/core/src/mindustry/ui/IntFormat.java index 2ca0e9de1f..fab10cd67f 100644 --- a/core/src/mindustry/ui/IntFormat.java +++ b/core/src/mindustry/ui/IntFormat.java @@ -10,7 +10,7 @@ import arc.func.*; public class IntFormat{ private final StringBuilder builder = new StringBuilder(); private final String text; - private int lastValue = Integer.MIN_VALUE; + private int lastValue = Integer.MIN_VALUE, lastValue2 = Integer.MIN_VALUE; private Func converter = String::valueOf; public IntFormat(String text){ @@ -30,4 +30,14 @@ public class IntFormat{ lastValue = value; return builder; } + + public CharSequence get(int value1, int value2){ + if(lastValue != value1 || lastValue2 != value2){ + builder.setLength(0); + builder.append(Core.bundle.format(text, value1, value2)); + } + lastValue = value1; + lastValue2 = value2; + return builder; + } } diff --git a/core/src/mindustry/ui/Styles.java b/core/src/mindustry/ui/Styles.java index 13e97202e5..802a18004b 100644 --- a/core/src/mindustry/ui/Styles.java +++ b/core/src/mindustry/ui/Styles.java @@ -23,6 +23,7 @@ import static mindustry.gen.Tex.*; @StyleDefaults public class Styles{ + //TODO all these names are inconsistent and not descriptive public static Drawable black, black9, black8, black6, black3, black5, none, flatDown, flatOver; public static ButtonStyle defaultb, waveb; public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt, fullTogglet, logict; diff --git a/core/src/mindustry/ui/dialogs/ContentInfoDialog.java b/core/src/mindustry/ui/dialogs/ContentInfoDialog.java index 0ee1960f9f..89cf556cb1 100644 --- a/core/src/mindustry/ui/dialogs/ContentInfoDialog.java +++ b/core/src/mindustry/ui/dialogs/ContentInfoDialog.java @@ -1,8 +1,14 @@ package mindustry.ui.dialogs; +import arc.graphics.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; +import arc.struct.*; +import arc.util.*; import mindustry.ctype.*; +import mindustry.graphics.*; +import mindustry.ui.*; +import mindustry.world.meta.*; public class ContentInfoDialog extends BaseDialog{ @@ -18,11 +24,62 @@ public class ContentInfoDialog extends BaseDialog{ Table table = new Table(); table.margin(10); - content.displayInfo(table); + //initialize stats if they haven't been yet + content.checkStats(); + + table.table(title1 -> { + int size = 8 * 6; + + title1.image(content.icon(Cicon.xlarge)).size(size).scaling(Scaling.fit); + title1.add("[accent]" + content.localizedName).padLeft(5); + }); + + table.row(); + + table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX(); + + table.row(); + + if(content.description != null){ + table.add(content.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX(); + table.row(); + + table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX(); + table.row(); + } + + Stats stats = content.stats; + + for(StatCat cat : stats.toMap().keys()){ + OrderedMap> map = stats.toMap().get(cat); + + if(map.size == 0) continue; + + //TODO check + if(stats.useCategories){ + table.add("@category." + cat.name()).color(Pal.accent).fillX(); + table.row(); + } + + for(Stat stat : map.keys()){ + table.table(inset -> { + inset.left(); + inset.add("[lightgray]" + stat.localized() + ":[] ").left(); + Seq arr = map.get(stat); + for(StatValue value : arr){ + value.display(inset); + inset.add().size(10f); + } + + }).fillX().padLeft(10); + table.row(); + } + } ScrollPane pane = new ScrollPane(table); cont.add(pane); show(); } + } diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index e14629b594..4d6a4483f9 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -24,8 +24,8 @@ import static arc.util.Time.*; import static mindustry.Vars.*; public class CustomRulesDialog extends BaseDialog{ - private Table main; Rules rules; + private Table main; private Prov resetter; private LoadoutDialog loadoutDialog; private BaseDialog banDialog; @@ -134,7 +134,7 @@ public class CustomRulesDialog extends BaseDialog{ check("@rules.waves", b -> rules.waves = b, () -> rules.waves); check("@rules.wavetimer", b -> rules.waveTimer = b, () -> rules.waveTimer); check("@rules.waitForWaveToEnd", b -> rules.waitEnemies = b, () -> rules.waitEnemies); - number("@rules.wavespacing", false, f -> rules.waveSpacing = f * 60f, () -> rules.waveSpacing / 60f, () -> true); + number("@rules.wavespacing", false, f -> rules.waveSpacing = f * 60f, () -> rules.waveSpacing / 60f, () -> true, 1, Float.MAX_VALUE); number("@rules.dropzoneradius", false, f -> rules.dropZoneRadius = f * tilesize, () -> rules.dropZoneRadius / tilesize, () -> true); title("@rules.title.resourcesbuilding"); @@ -142,7 +142,7 @@ public class CustomRulesDialog extends BaseDialog{ check("@rules.reactorexplosions", b -> rules.reactorExplosions = b, () -> rules.reactorExplosions); check("@rules.schematic", b-> rules.schematicsAllowed = b, () -> rules.schematicsAllowed); number("@rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources); - number("@rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier); + number("@rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier, 0.00001f, 10000f); number("@rules.deconstructrefundmultiplier", false, f -> rules.deconstructRefundMultiplier = f, () -> rules.deconstructRefundMultiplier, () -> !rules.infiniteResources); number("@rules.blockhealthmultiplier", f -> rules.blockHealthMultiplier = f, () -> rules.blockHealthMultiplier); number("@rules.blockdamagemultiplier", f -> rules.blockDamageMultiplier = f, () -> rules.blockDamageMultiplier); @@ -162,11 +162,11 @@ public class CustomRulesDialog extends BaseDialog{ check("@rules.unitammo", b -> rules.unitAmmo = b, () -> rules.unitAmmo); number("@rules.unithealthmultiplier", f -> rules.unitHealthMultiplier = f, () -> rules.unitHealthMultiplier); number("@rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier); - number("@rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier); + number("@rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier, 0.00001f, 100f); title("@rules.title.enemy"); check("@rules.attack", b -> rules.attackMode = b, () -> rules.attackMode); - check("@rules.buildai", b -> rules.waveTeam.rules().ai = b, () -> rules.waveTeam.rules().ai); + check("@rules.buildai", b -> rules.teams.get(rules.waveTeam).ai = rules.teams.get(rules.waveTeam).infiniteResources = b, () -> rules.teams.get(rules.waveTeam).ai); number("@rules.enemycorebuildradius", f -> rules.enemyCoreBuildRadius = f * tilesize, () -> Math.min(rules.enemyCoreBuildRadius / tilesize, 200)); title("@rules.title.environment"); @@ -189,10 +189,22 @@ public class CustomRulesDialog extends BaseDialog{ } void number(String text, Floatc cons, Floatp prov){ - number(text, false, cons, prov, () -> true); + number(text, false, cons, prov, () -> true, 0, Float.MAX_VALUE); + } + + void number(String text, Floatc cons, Floatp prov, float min, float max){ + number(text, false, cons, prov, () -> true, min, max); } void number(String text, boolean integer, Floatc cons, Floatp prov, Boolp condition){ + number(text, integer, cons, prov, condition, 0, Float.MAX_VALUE); + } + + void number(String text, Floatc cons, Floatp prov, Boolp condition){ + number(text, false, cons, prov, condition, 0, Float.MAX_VALUE); + } + + void number(String text, boolean integer, Floatc cons, Floatp prov, Boolp condition, float min, float max){ main.table(t -> { t.left(); t.add(text).left().padRight(5) @@ -200,7 +212,7 @@ public class CustomRulesDialog extends BaseDialog{ t.field((integer ? (int)prov.get() : prov.get()) + "", s -> cons.get(Strings.parseFloat(s))) .padRight(100f) .update(a -> a.setDisabled(!condition.get())) - .valid(Strings::canParsePositiveFloat).width(120f).left().addInputDialog(); + .valid(f -> Strings.canParsePositiveFloat(f) && Strings.parseFloat(f) >= min && Strings.parseFloat(f) <= max).width(120f).left().addInputDialog(); }).padTop(0); main.row(); } diff --git a/core/src/mindustry/ui/dialogs/FileChooser.java b/core/src/mindustry/ui/dialogs/FileChooser.java index 2c8f2954b9..555df63e33 100644 --- a/core/src/mindustry/ui/dialogs/FileChooser.java +++ b/core/src/mindustry/ui/dialogs/FileChooser.java @@ -4,6 +4,7 @@ import arc.*; import arc.files.*; import arc.func.*; import arc.graphics.g2d.*; +import arc.input.*; import arc.scene.event.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; @@ -45,6 +46,16 @@ public class FileChooser extends BaseDialog{ cont.clear(); setupWidgets(); }); + + keyDown(KeyCode.enter, () -> { + ok.fireClick(); + }); + + keyDown(key -> { + if(key == KeyCode.escape || key == KeyCode.back){ + Core.app.post(this::hide); + } + }); } private void setupWidgets(){ diff --git a/core/src/mindustry/ui/dialogs/GameOverDialog.java b/core/src/mindustry/ui/dialogs/GameOverDialog.java index b9967e6564..ceea590826 100644 --- a/core/src/mindustry/ui/dialogs/GameOverDialog.java +++ b/core/src/mindustry/ui/dialogs/GameOverDialog.java @@ -2,7 +2,7 @@ package mindustry.ui.dialogs; import arc.*; import mindustry.game.EventType.*; -import mindustry.game.Stats.*; +import mindustry.game.GameStats.*; import mindustry.game.*; import mindustry.type.*; import mindustry.ui.*; diff --git a/core/src/mindustry/ui/dialogs/HostDialog.java b/core/src/mindustry/ui/dialogs/HostDialog.java index 25300fc0b1..1282d47b7d 100644 --- a/core/src/mindustry/ui/dialogs/HostDialog.java +++ b/core/src/mindustry/ui/dialogs/HostDialog.java @@ -76,13 +76,15 @@ public class HostDialog extends BaseDialog{ platform.updateLobby(); }); })); + + if(Version.modifier.contains("beta") || Version.modifier.contains("alpha")){ + Core.settings.put("publichost", false); + platform.updateLobby(); + Core.settings.getBoolOnce("betapublic", () -> ui.showInfo("@public.beta")); + } } - if(Version.modifier.contains("beta")){ - Core.settings.put("publichost", false); - platform.updateLobby(); - Core.settings.getBoolOnce("betapublic", () -> ui.showInfo("@public.beta")); - } + }catch(IOException e){ ui.showException("@server.error", e); } diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index 1c80418708..aa4d9c22c8 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -367,8 +367,10 @@ public class JoinDialog extends BaseDialog{ local.row(); - TextButton button = local.button("", Styles.cleart, () -> safeConnect(host.address, host.port, host.version)) - .width(w).pad(5f).get(); + TextButton button = local.button("", Styles.cleart, () -> { + Events.fire(new ClientPreConnectEvent(host)); + safeConnect(host.address, host.port, host.version); + }).width(w).pad(5f).get(); button.clearChildren(); buildServer(host, button); } @@ -379,8 +381,10 @@ public class JoinDialog extends BaseDialog{ global.row(); - TextButton button = global.button("", Styles.cleart, () -> safeConnect(host.address, host.port, host.version)) - .width(w).pad(5f).get(); + TextButton button = global.button("", Styles.cleart, () -> { + Events.fire(new ClientPreConnectEvent(host)); + safeConnect(host.address, host.port, host.version); + }).width(w).pad(5f).get(); button.clearChildren(); buildServer(host, button); } diff --git a/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java b/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java index acb240d7c9..6cb50dbf36 100644 --- a/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java +++ b/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java @@ -2,6 +2,7 @@ package mindustry.ui.dialogs; import arc.*; import arc.func.*; +import arc.input.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.struct.*; @@ -29,18 +30,27 @@ public class LaunchLoadoutDialog extends BaseDialog{ super("@configure"); } - public void show(CoreBlock core, Building build, Runnable confirm){ + public void show(CoreBlock core, Sector sector, Runnable confirm){ cont.clear(); buttons.clear(); - addCloseButton(); + buttons.defaults().size(160f, 64f); + buttons.button("@back", Icon.left, this::hide); + + keyDown(key -> { + if(key == KeyCode.escape || key == KeyCode.back){ + Core.app.post(this::hide); + } + }); + + ItemSeq sitems = sector.getItems(); //updates sum requirements Runnable update = () -> { total.clear(); selected.requirements().each(total::add); universe.getLaunchResources().each(total::add); - valid = build.items.has(total); + valid = sitems.has(total); }; Cons rebuild = table -> { @@ -57,8 +67,8 @@ public class LaunchLoadoutDialog extends BaseDialog{ String amountStr = "[lightgray]" + (al + " + [accent]" + as + "[lightgray]"); table.add( - build.items.has(s.item, s.amount) ? amountStr : - "[scarlet]" + (Math.min(build.items.get(s.item), s.amount) + "[lightgray]/" + amountStr)).padLeft(2).left().padRight(4); + sitems.has(s.item, s.amount) ? amountStr : + "[scarlet]" + (Math.min(sitems.get(s.item), s.amount) + "[lightgray]/" + amountStr)).padLeft(2).left().padRight(4); if(++i % 4 == 0){ table.row(); @@ -79,7 +89,7 @@ public class LaunchLoadoutDialog extends BaseDialog{ update.run(); rebuildItems.run(); }); - }); + }).width(204); buttons.button("@launch.text", Icon.ok, () -> { universe.updateLoadout(core, selected); @@ -100,7 +110,7 @@ public class LaunchLoadoutDialog extends BaseDialog{ selected = s; update.run(); rebuildItems.run(); - }).group(group).pad(4).disabled(!build.items.has(s.requirements())).checked(s == selected).size(200f); + }).group(group).pad(4).disabled(!sitems.has(s.requirements())).checked(s == selected).size(200f); if(++i % cols == 0){ t.row(); @@ -110,6 +120,8 @@ public class LaunchLoadoutDialog extends BaseDialog{ cont.row(); cont.add(items); + cont.row(); + cont.add("@sector.missingresources").visible(() -> !valid); update.run(); rebuildItems.run(); diff --git a/core/src/mindustry/ui/dialogs/ModsDialog.java b/core/src/mindustry/ui/dialogs/ModsDialog.java index 4695091886..866c3460e4 100644 --- a/core/src/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/mindustry/ui/dialogs/ModsDialog.java @@ -107,11 +107,13 @@ public class ModsDialog extends BaseDialog{ Core.settings.put("lastmod", text); ui.loadfrag.show(); - // Try to download the 6.0 branch first, but if it doesnt exist try master. + //Try to download the 6.0 branch first, but if it doesn't exist try master. githubImport("6.0", text, e1 -> { githubImport("master", text, e2 -> { - ui.showErrorMessage(Core.bundle.format("connectfail", e2)); - ui.loadfrag.hide(); + githubImport("main", text, e3 -> { + ui.showErrorMessage(Core.bundle.format("connectfail", e2)); + ui.loadfrag.hide(); + }); }); }); }); diff --git a/core/src/mindustry/ui/dialogs/PausedDialog.java b/core/src/mindustry/ui/dialogs/PausedDialog.java index 559450a591..fce68f3044 100644 --- a/core/src/mindustry/ui/dialogs/PausedDialog.java +++ b/core/src/mindustry/ui/dialogs/PausedDialog.java @@ -34,18 +34,11 @@ public class PausedDialog extends BaseDialog{ }); if(!mobile){ - //TODO localize - cont.label(() -> state.getSector() == null ? "" : - ("[lightgray]Next turn in [accent]" + state.getSector().displayTimeRemaining() + - (state.rules.winWave > 0 && !state.getSector().isCaptured() ? "\n[lightgray]Reach wave[accent] " + state.rules.winWave + "[] to capture" : ""))) - .visible(() -> state.getSector() != null).colspan(2); - cont.row(); - float dw = 220f; cont.defaults().width(dw).height(55).pad(5f); - cont.button("@back", Icon.left, this::hide); - cont.button("@settings", Icon.settings, ui.settings::show); + cont.button("@back", Icon.left, this::hide).name("back"); + cont.button("@settings", Icon.settings, ui.settings::show).name("settings"); if(!state.rules.tutorial){ if(!state.isCampaign() && !state.isEditor()){ @@ -85,10 +78,7 @@ public class PausedDialog extends BaseDialog{ cont.buttonRow("@load", Icon.download, load::show).disabled(b -> net.active()); }else if(state.isCampaign()){ - cont.buttonRow("@launchcore", Icon.up, () -> { - hide(); - ui.planet.showLaunch(state.getSector(), player.team().core()); - }).disabled(b -> player.team().core() == null); + cont.buttonRow("@research", Icon.tree, ui.research::show); cont.row(); diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java index b230f08a4f..00c68b4a0e 100644 --- a/core/src/mindustry/ui/dialogs/PlanetDialog.java +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -13,6 +13,7 @@ import arc.scene.event.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; +import mindustry.content.*; import mindustry.core.*; import mindustry.ctype.*; import mindustry.game.*; @@ -22,25 +23,26 @@ import mindustry.graphics.g3d.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.world.blocks.storage.*; -import mindustry.world.blocks.storage.CoreBlock.*; import static mindustry.Vars.*; import static mindustry.graphics.g3d.PlanetRenderer.*; import static mindustry.ui.dialogs.PlanetDialog.Mode.*; public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ - final FrameBuffer buffer = new FrameBuffer(2, 2, true); - final PlanetRenderer planets = renderer.planets; - final LaunchLoadoutDialog loadouts = new LaunchLoadoutDialog(); - final Table stable = new Table().background(Styles.black3); + //if true, enables launching anywhere for testing + public static boolean debugSelect = false; - int launchRange; - float zoom = 1f, selectAlpha = 1f; - @Nullable Sector selected, hovered, launchSector; - CoreBuild launcher; - Mode mode = look; - boolean launching; - Cons listener = s -> {}; + public final FrameBuffer buffer = new FrameBuffer(2, 2, true); + public final PlanetRenderer planets = renderer.planets; + public final LaunchLoadoutDialog loadouts = new LaunchLoadoutDialog(); + public final Table stable = new Table().background(Styles.black3); + + public int launchRange; + public float zoom = 1f, selectAlpha = 1f; + public @Nullable Sector selected, hovered, launchSector; + public Mode mode = look; + public boolean launching; + public Cons listener = s -> {}; public PlanetDialog(){ super("", Styles.fullDialog); @@ -88,9 +90,16 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ mode = look; selected = hovered = launchSector = null; launching = false; + + zoom = 1f; + planets.zoom = 1f; + selectAlpha = 0f; + launchSector = state.getSector(); + if(planets.planet.getLastSector() != null){ lookAt(planets.planet.getLastSector()); } + return super.show(); } @@ -103,7 +112,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ //update view to sector lookAt(sector); zoom = 1f; - planets.zoom = 2f; + planets.zoom = 1f; selectAlpha = 0f; launchSector = sector; @@ -112,68 +121,65 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ super.show(); } - public void showLaunch(Sector sector, CoreBuild launcher){ - if(launcher == null) return; - - this.launcher = launcher; - selected = null; - hovered = null; - launching = false; - - //update view to sector - lookAt(sector); - zoom = 1f; - planets.zoom = 2f; - selectAlpha = 0f; - launchRange = ((CoreBlock)launcher.block).launchRange; - launchSector = sector; - - mode = launch; - - super.show(); - } - - private void lookAt(Sector sector){ + void lookAt(Sector sector){ planets.camPos.set(Tmp.v33.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation())); } boolean canSelect(Sector sector){ if(mode == select) return sector.hasBase(); - return mode == launch && - (sector.tile.v.within(launchSector.tile.v, (launchRange + 0.5f) * planets.planet.sectorApproxRadius*2) //within range - || (sector.preset != null && sector.preset.unlocked())); //is an unlocked preset + return sector.hasBase() || sector.near().contains(Sector::hasBase) //near an occupied sector + || (sector.preset != null && sector.preset.unlocked()); //is an unlocked preset + } + + Sector findLauncher(Sector to){ + //directly nearby. + if(to.near().contains(launchSector)) return launchSector; + + Sector launchFrom = launchSector; + if(launchFrom == null){ + //TODO pick one with the most resources + launchFrom = to.near().find(Sector::hasBase); + if(launchFrom == null && to.preset != null){ + if(launchSector != null) return launchSector; + launchFrom = planets.planet.sectors.min(s -> !s.hasBase() ? Float.MAX_VALUE : s.tile.v.dst2(to.tile.v)); + if(!launchFrom.hasBase()) launchFrom = null; + } + } + + return launchFrom; } @Override public void renderSectors(Planet planet){ //draw all sector stuff - for(Sector sec : planet.sectors){ + if(!debugSelect){ + for(Sector sec : planet.sectors){ - if(selectAlpha > 0.01f){ - if(canSelect(sec) || sec.unlocked()){ - if(sec.baseCoverage > 0){ - planets.fill(sec, Tmp.c1.set(Team.crux.color).a(0.5f * sec.baseCoverage * selectAlpha), -0.002f); + if(selectAlpha > 0.01f){ + if(canSelect(sec) || sec.unlocked()){ + + Color color = + sec.hasBase() ? Team.sharded.color : + sec.preset != null ? Team.derelict.color : + sec.hasEnemyBase() ? Team.crux.color : + null; + + if(color != null){ + planets.drawSelection(sec, Tmp.c1.set(color).mul(0.8f).a(selectAlpha), 0.026f, -0.001f); + } + }else{ + planets.fill(sec, Tmp.c1.set(shadowColor).mul(1, 1, 1, selectAlpha), -0.001f); } - - Color color = - sec.hasBase() ? Team.sharded.color : - sec.preset != null ? Team.derelict.color : - sec.hasEnemyBase() ? Team.crux.color : - null; - - if(color != null){ - planets.drawSelection(sec, Tmp.c1.set(color).mul(0.8f).a(selectAlpha), 0.026f, -0.001f); - } - }else{ - planets.fill(sec, Tmp.c1.set(shadowColor).mul(1, 1, 1, selectAlpha), -0.001f); } } } - if(launchSector != null){ - planets.fill(launchSector, hoverColor, -0.001f); + Sector current = state.getSector() != null && state.getSector().isBeingPlayed() ? state.getSector() : null; + + if(current != null){ + planets.fill(current, hoverColor, -0.001f); } //draw hover border @@ -190,9 +196,10 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ planets.batch.flush(Gl.triangles); - if(mode == launch || mode == select){ - if(hovered != launchSector && hovered != null && canSelect(hovered)){ - planets.drawArc(planet, launchSector.tile.v, hovered.tile.v); + if(hovered != null && !hovered.hasBase()){ + Sector launchFrom = findLauncher(hovered); + if(launchFrom != null && hovered != launchFrom && canSelect(hovered)){ + planets.drawArc(planet, launchFrom.tile.v, hovered.tile.v); } } @@ -212,9 +219,9 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ public void renderProjections(){ if(hovered != null){ planets.drawPlane(hovered, () -> { - Draw.color(Color.white, Pal.accent, Mathf.absin(5f, 1f)); + Draw.color(hovered.isAttacked() ? Pal.remove : Color.white, Pal.accent, Mathf.absin(5f, 1f)); - TextureRegion icon = hovered.locked() && !canSelect(hovered) ? Icon.lock.getRegion() : null; + TextureRegion icon = hovered.locked() && !canSelect(hovered) ? Icon.lock.getRegion() : hovered.isAttacked() ? Icon.warning.getRegion() : null; if(icon != null){ Draw.rect(icon, 0, 0); @@ -232,7 +239,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ cont.clear(); titleTable.remove(); - cont.stack( new Element(){ { @@ -240,7 +246,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ addListener(new ElementGestureListener(){ @Override public void tap(InputEvent event, float x, float y, int count, KeyCode button){ - if(hovered != null && (mode == launch ? canSelect(hovered) && hovered != launchSector : hovered.unlocked())){ + if(hovered != null && ((mode == look ? canSelect(hovered) && hovered != launchSector : hovered.unlocked()) || debugSelect)){ selected = hovered; } @@ -258,9 +264,30 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } }, new Table(t -> { - //TODO localize + t.touchable = Touchable.disabled; t.top(); - t.label(() -> mode == select ? "@sectors.select" : mode == launch ? "Select Launch Sector" : "Turn " + universe.turn()).style(Styles.outlineLabel).color(Pal.accent); + t.label(() -> mode == select ? "@sectors.select" : "").style(Styles.outlineLabel).color(Pal.accent); + }), + new Table(t -> { + t.right(); + if(content.planets().count(p -> p.accessible) > 1) { + t.table(Styles.black6, pt -> { + //TODO localize + pt.add("[accent]Planets[]"); + pt.row(); + pt.image().growX().height(4f).pad(6f).color(Pal.accent); + pt.row(); + for(int i = 0; i < content.planets().size; i++){ + Planet planet = content.planets().get(i); + if(planet.accessible){ + pt.button(planet.localizedName, Styles.clearTogglet, () -> { + renderer.planets.planet = planet; + }).width(200).height(40).growX().update(bb -> bb.setChecked(renderer.planets.planet == planet)); + pt.row(); + } + } + }); + } })).grow(); } @@ -296,7 +323,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ stable.toFront(); //smooth camera toward the sector - if(mode == launch && launching){ + if(mode == look && launching){ float len = planets.camPos.len(); planets.camPos.slerp(Tmp.v31.set(selected.tile.v).rotate(Vec3.Y,-selected.planet.getRotation()).setLength(len), 0.1f); } @@ -326,67 +353,76 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ stable.clear(); stable.background(Styles.black6); - stable.add("[accent]" + (sector.preset == null ? sector.id : sector.preset.localizedName)).row(); + stable.table(title -> { + title.add("[accent]" + sector.name()); + if(sector.preset == null){ + title.button(Icon.pencilSmall, Styles.clearPartiali, () -> { + ui.showTextInput("@sectors.rename", "@name", 20, sector.name(), v -> { + sector.setName(v); + updateSelected(); + }); + }).size(40f).padLeft(4); + } + }).row(); + stable.image().color(Pal.accent).fillX().height(3f).pad(3f).row(); stable.add(sector.save != null ? sector.save.getPlayTime() : "@sectors.unexplored").row(); - if(sector.hasWaves() || sector.hasEnemyBase()){ + + if(sector.isAttacked() || !sector.hasBase()){ stable.add("[accent]Difficulty: " + (int)(sector.baseCoverage * 10)).row(); } - if(sector.hasBase() && sector.hasWaves()){ + if(sector.isAttacked()){ //TODO localize when finalized //these mechanics are likely to change and as such are not added to the bundle stable.add("[scarlet]Under attack!"); stable.row(); - stable.add("[accent]" + Mathf.ceil(sectorDestructionTurns - (sector.getSecondsPassed() * 60) / turnDuration) + " turn(s)\nuntil destruction"); + stable.add("[accent]" + (int)(sector.info.damage * 100) + "% damaged"); stable.row(); } - if(sector.save != null){ + if(sector.save != null && sector.info.resources.any()){ stable.add("@sectors.resources").row(); stable.table(t -> { - - if(sector.save != null && sector.save.meta.secinfo != null && sector.save.meta.secinfo.resources.any()){ - t.left(); - int idx = 0; - int max = 5; - for(UnlockableContent c : sector.save.meta.secinfo.resources){ - t.image(c.icon(Cicon.small)).padRight(3); - if(++idx % max == 0) t.row(); - } - }else{ - t.add("@unknown").color(Color.lightGray); + t.left(); + int idx = 0; + int max = 5; + for(UnlockableContent c : sector.info.resources){ + t.image(c.icon(Cicon.small)).padRight(3); + if(++idx % max == 0) t.row(); } - - }).fillX().row(); } //production - if(sector.hasBase() && sector.save.meta.hasProduction){ - stable.add("@sectors.production").row(); - stable.table(t -> { - t.left(); + if(sector.hasBase()){ + Table t = new Table().left(); - sector.save.meta.secinfo.production.each((item, stat) -> { - int total = (int)(stat.mean * 60); - if(total > 1){ - t.image(item.icon(Cicon.small)).padRight(3); - t.add(UI.formatAmount(total) + " " + Core.bundle.get("unit.perminute")).color(Color.lightGray); - t.row(); - } - }); - }).row(); + float scl = sector.getProductionScale(); + + sector.info.production.each((item, stat) -> { + int total = (int)(stat.mean * 60 * scl); + if(total > 1){ + t.image(item.icon(Cicon.small)).padRight(3); + t.add(UI.formatAmount(total) + " " + Core.bundle.get("unit.perminute")).color(Color.lightGray); + t.row(); + } + }); + + if(t.getChildren().any()){ + stable.add("@sectors.production").row(); + stable.add(t).row(); + } } //stored resources - if(sector.hasBase() && sector.save.meta.secinfo.coreItems.total > 0){ + if(sector.hasBase() && sector.info.items.total > 0){ stable.add("@sectors.stored").row(); stable.table(t -> { t.left(); t.table(res -> { - ItemSeq items = sector.calculateItems(); + ItemSeq items = sector.items(); int i = 0; for(ItemStack stack : items){ @@ -403,7 +439,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ stable.row(); - if((sector.hasBase() && mode == look) || canSelect(sector) || (sector.preset != null && sector.preset.alwaysUnlocked)){ + if((sector.hasBase() && mode == look) || canSelect(sector) || (sector.preset != null && sector.preset.alwaysUnlocked) || debugSelect){ stable.button(mode == select ? "@sectors.select" : sector.hasBase() ? "@sectors.resume" : "@sectors.launch", Styles.transt, () -> { boolean shouldHide = true; @@ -418,17 +454,26 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } } - if(mode == launch && !sector.hasBase()){ - Sector current = state.rules.sector; + if(mode == look && !sector.hasBase()){ shouldHide = false; - loadouts.show((CoreBlock)launcher.block, launcher, () -> { - control.handleLaunch(launcher); - launching = true; - zoom = 0.5f; + Sector from = findLauncher(sector); + if(from == null){ + //free launch. + control.playSector(sector); + }else{ + CoreBlock block = from.info.bestCoreType instanceof CoreBlock b ? b : (CoreBlock)Blocks.coreShard; - ui.hudfrag.showLaunchDirect(); - Time.runTask(launchDuration, () -> control.playSector(current, sector)); - }); + loadouts.show(block, from, () -> { + from.removeItems(universe.getLastLoadout().requirements()); + from.removeItems(universe.getLaunchResources()); + + launching = true; + zoom = 0.5f; + + ui.hudfrag.showLaunchDirect(); + Time.runTask(launchDuration, () -> control.playSector(from, sector)); + }); + } }else if(mode == select){ listener.get(sector); }else{ @@ -456,18 +501,15 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ selected = null; } } - } }); stable.act(0f); } - enum Mode{ + public enum Mode{ /** Look around for existing sectors. Can only deploy. */ look, - /** Launch to a new location. */ - launch, /** Select a sector for some purpose. */ select } diff --git a/core/src/mindustry/ui/dialogs/ResearchDialog.java b/core/src/mindustry/ui/dialogs/ResearchDialog.java index a87aa2d55c..b79aacbce5 100644 --- a/core/src/mindustry/ui/dialogs/ResearchDialog.java +++ b/core/src/mindustry/ui/dialogs/ResearchDialog.java @@ -31,14 +31,14 @@ import java.util.*; import static mindustry.Vars.*; public class ResearchDialog extends BaseDialog{ - final float nodeSize = Scl.scl(60f); - ObjectSet nodes = new ObjectSet<>(); - TechTreeNode root = new TechTreeNode(TechTree.root, null); - Rect bounds = new Rect(); - ItemsDisplay itemDisplay; - View view; + public final float nodeSize = Scl.scl(60f); + public ObjectSet nodes = new ObjectSet<>(); + public TechTreeNode root = new TechTreeNode(TechTree.root, null); + public Rect bounds = new Rect(); + public ItemsDisplay itemDisplay; + public View view; - ItemSeq items; + public ItemSeq items; public ResearchDialog(){ super(""); @@ -60,7 +60,7 @@ public class ResearchDialog extends BaseDialog{ for(Planet planet : content.planets()){ for(Sector sector : planet.sectors){ if(sector.hasSave()){ - ItemSeq cached = sector.calculateItems(); + ItemSeq cached = sector.items(); add(cached); cache.put(sector, cached); } @@ -114,7 +114,7 @@ public class ResearchDialog extends BaseDialog{ buttons.button("@database", Icon.book, () -> { hide(); ui.database.show(); - }).size(210f, 64f); + }).size(210f, 64f).name("database"); //scaling/drag input addListener(new InputListener(){ @@ -164,13 +164,10 @@ public class ResearchDialog extends BaseDialog{ @Override public Dialog show(){ - Core.app.post(() -> { - if(net.client()){ - //TODO make this not display every time - //TODO rework this in the future - ui.showInfo("@campaign.multiplayer"); - } - }); + if(net.client()){ + ui.showInfo("@research.multiplayer"); + return null; + } return super.show(); } @@ -250,7 +247,7 @@ public class ResearchDialog extends BaseDialog{ return node.content.unlocked() || !node.objectives.contains(i -> !i.complete()); } - void showToast(String info){ + public void showToast(String info){ Table table = new Table(); table.actions(Actions.fadeOut(0.5f, Interp.fade), Actions.remove()); table.top().add(info); @@ -279,11 +276,11 @@ public class ResearchDialog extends BaseDialog{ } } - class TechTreeNode extends TreeNode{ - final TechNode node; - boolean visible = true, selectable = true; + public class TechTreeNode extends TreeNode{ + public final TechNode node; + public boolean visible = true, selectable = true; - TechTreeNode(TechNode node, TechTreeNode parent){ + public TechTreeNode(TechNode node, TechTreeNode parent){ this.node = node; this.parent = parent; this.width = this.height = nodeSize; @@ -297,11 +294,11 @@ public class ResearchDialog extends BaseDialog{ } } - class View extends Group{ - float panX = 0, panY = -200, lastZoom = -1; - boolean moved = false; - ImageButton hoverNode; - Table infoTable = new Table(); + public class View extends Group{ + public float panX = 0, panY = -200, lastZoom = -1; + public boolean moved = false; + public ImageButton hoverNode; + public Table infoTable = new Table(); { infoTable.touchable = Touchable.enabled; @@ -400,7 +397,8 @@ public class ResearchDialog extends BaseDialog{ } } - return false; + //can always spend when locked + return node.content.locked(); } void spend(TechNode node){ @@ -414,7 +412,7 @@ public class ResearchDialog extends BaseDialog{ ItemStack completed = node.finishedRequirements[i]; //amount actually taken from inventory - int used = Math.min(req.amount - completed.amount, items.get(req.item)); + int used = Math.max(Math.min(req.amount - completed.amount, items.get(req.item)), 0); items.remove(req.item, used); completed.amount += used; diff --git a/core/src/mindustry/ui/dialogs/SchematicsDialog.java b/core/src/mindustry/ui/dialogs/SchematicsDialog.java index 99a087d39f..8c99272e89 100644 --- a/core/src/mindustry/ui/dialogs/SchematicsDialog.java +++ b/core/src/mindustry/ui/dialogs/SchematicsDialog.java @@ -4,6 +4,7 @@ import arc.*; import arc.graphics.*; import arc.graphics.Texture.*; import arc.graphics.g2d.*; +import arc.input.*; import arc.math.*; import arc.scene.style.*; import arc.scene.ui.*; @@ -106,18 +107,36 @@ public class SchematicsDialog extends BaseDialog{ }); buttons.button(Icon.pencil, style, () -> { - ui.showTextInput("@schematic.rename", "@name", s.name(), res -> { - Schematic replacement = schematics.all().find(other -> other.name().equals(res) && other != s); - if(replacement != null){ - //renaming to an existing schematic is not allowed, as it is not clear how the tags would be merged, and which one should be removed - ui.showErrorMessage("@schematic.exists"); - return; - } + new Dialog("@schematic.rename"){{ + cont.margin(30).add("@name").padRight(6f); + TextField nameField = cont.field(s.name(), null).size(400f, 55f).addInputDialog().get(); - s.tags.put("name", res); - s.save(); - rebuildPane[0].run(); - }); + cont.row(); + + cont.margin(30).add("@editor.description").padRight(6f); + TextField descripionField = cont.area(s.description(), Styles.areaField, t -> {}).size(400f, 140f).addInputDialog().get(); + + Runnable accept = () -> { + s.tags.put("name", nameField.getText()); + s.tags.put("description", descripionField.getText()); + s.save(); + hide(); + rebuildPane[0].run(); + }; + + buttons.defaults().size(120, 54).pad(4); + buttons.button("@ok", accept).disabled(b -> nameField.getText().isEmpty()); + buttons.button("@cancel", this::hide); + + keyDown(KeyCode.enter, () -> { + if(!nameField.getText().isEmpty() && Core.scene.getKeyboardFocus() != descripionField){ + accept.run(); + } + }); + keyDown(KeyCode.escape, this::hide); + keyDown(KeyCode.back, this::hide); + show(); + }}; }); if(s.hasSteamID()){ diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index 8dd9753fda..d58b930e77 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -14,8 +14,11 @@ import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; import arc.util.io.*; +import mindustry.content.*; +import mindustry.content.TechTree.*; import mindustry.core.GameState.*; import mindustry.core.*; +import mindustry.ctype.*; import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; @@ -116,6 +119,37 @@ public class SettingsMenuDialog extends SettingsDialog{ t.row(); + t.button("@settings.clearresearch", Icon.trash, style, () -> { + ui.showConfirm("@confirm", "@settings.clearresearch.confirm", () -> { + for(TechNode node : TechTree.all){ + node.reset(); + } + content.each(c -> { + if(c instanceof UnlockableContent u){ + u.clearUnlock(); + } + }); + }); + }).marginLeft(4); + + t.row(); + + t.button("@settings.clearcampaignsaves", Icon.trash, style, () -> { + ui.showConfirm("@confirm", "@settings.clearcampaignsaves.confirm", () -> { + for(var planet : content.planets()){ + for(var sec : planet.sectors){ + sec.clearInfo(); + if(sec.save != null){ + sec.save.delete(); + sec.save = null; + } + } + } + }); + }).marginLeft(4); + + t.row(); + t.button("@data.export", Icon.upload, style, () -> { if(ios){ Fi file = Core.files.local("mindustry-data-export.zip"); @@ -250,7 +284,6 @@ public class SettingsMenuDialog extends SettingsDialog{ if(!mobile){ game.checkPref("buildautopause", false); } - game.checkPref("mapcenter", true); if(steam){ game.sliderPref("playerlimit", 16, 2, 32, i -> { @@ -292,7 +325,7 @@ public class SettingsMenuDialog extends SettingsDialog{ } return s + "%"; }); - graphics.sliderPref("bridgeopacity", 75, 0, 100, 5, s -> s + "%"); + graphics.sliderPref("bridgeopacity", 100, 0, 100, 5, s -> s + "%"); if(!mobile){ graphics.checkPref("vsync", true, b -> Core.graphics.setVSync(b)); @@ -340,9 +373,6 @@ public class SettingsMenuDialog extends SettingsDialog{ graphics.checkPref("smoothcamera", true); graphics.checkPref("position", false); graphics.checkPref("fps", false); - if(!mobile){ - graphics.checkPref("blockselectkeys", true); - } graphics.checkPref("playerindicators", true); graphics.checkPref("indicators", true); graphics.checkPref("animatedwater", true); diff --git a/core/src/mindustry/ui/fragments/BlockInventoryFragment.java b/core/src/mindustry/ui/fragments/BlockInventoryFragment.java index 3b60918356..a4a97553bd 100644 --- a/core/src/mindustry/ui/fragments/BlockInventoryFragment.java +++ b/core/src/mindustry/ui/fragments/BlockInventoryFragment.java @@ -14,12 +14,8 @@ import arc.scene.ui.layout.Stack; import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; -import mindustry.annotations.Annotations.*; -import mindustry.entities.*; import mindustry.game.EventType.*; import mindustry.gen.*; -import mindustry.net.Administration.*; -import mindustry.net.*; import mindustry.type.*; import mindustry.ui.*; @@ -42,29 +38,6 @@ public class BlockInventoryFragment extends Fragment{ Events.on(WorldLoadEvent.class, e -> hide()); } - @Remote(called = Loc.server, targets = Loc.both, forward = true) - public static void requestItem(Player player, Building tile, Item item, int amount){ - if(player == null || tile == null || !tile.interactable(player.team()) || !player.within(tile, buildingRange)) return; - amount = Math.min(player.unit().maxAccepted(item), amount); - int fa = amount; - - if(amount == 0) return; - - if(net.server() && (!Units.canInteract(player, tile) || - !netServer.admins.allowAction(player, ActionType.withdrawItem, tile.tile(), action -> { - action.item = item; - action.itemAmount = fa; - }))) throw new ValidateException(player, "Player cannot request items."); - - int removed = tile.removeStack(item, amount); - - player.unit().addItem(item, removed); - Events.fire(new WithdrawEvent(tile, player, item, amount)); - for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){ - Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.x, tile.y, player.unit())); - } - } - @Override public void build(Group parent){ table.name = "inventory"; diff --git a/core/src/mindustry/ui/fragments/ChatFragment.java b/core/src/mindustry/ui/fragments/ChatFragment.java index 93654f048c..be9115293e 100644 --- a/core/src/mindustry/ui/fragments/ChatFragment.java +++ b/core/src/mindustry/ui/fragments/ChatFragment.java @@ -57,7 +57,7 @@ public class ChatFragment extends Table{ } } - return net.active() && ui.hudfrag.shown(); + return net.active() && ui.hudfrag.shown; }); update(() -> { diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index c16d2f23ec..d51c83881d 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -15,6 +15,7 @@ import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; import mindustry.annotations.Annotations.*; +import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.ctype.*; import mindustry.game.EventType.*; @@ -32,30 +33,55 @@ public class HudFragment extends Fragment{ private static final float dsize = 65f; public final PlacementFragment blockfrag = new PlacementFragment(); + public boolean shown = true; private ImageButton flip; - private Table lastUnlockTable; - private Table lastUnlockLayout; - private boolean shown = true; private CoreItemsDisplay coreItems = new CoreItemsDisplay(); private String hudText = ""; private boolean showHudText; + private Table lastUnlockTable; + private Table lastUnlockLayout; private long lastToast; @Override public void build(Group parent){ + //warn about guardian/boss waves + Events.on(WaveEvent.class, e -> { + int max = 10; + outer: + for(int i = state.wave - 1; i <= state.wave + max; i++){ + for(SpawnGroup group : state.rules.spawns){ + if(group.effect == StatusEffects.boss && group.getSpawned(i) > 0){ + int diff = (i + 2) - state.wave; + + //increments at which to warn about incoming guardian + if(diff == 1 || diff == 2 || diff == 5 || diff == 10){ + showToast(Icon.warning, Core.bundle.format("wave.guardianwarn" + (diff == 1 ? ".one" : ""), diff)); + } + + break outer; + } + } + } + }); + //TODO details and stuff Events.on(SectorCaptureEvent.class, e ->{ //TODO localize - showToast("Sector[accent] captured[]!"); + showToast("Sector [accent]" + (e.sector.isBeingPlayed() ? "" : e.sector.name() + " ") + "[white]captured!"); }); //TODO localize Events.on(SectorLoseEvent.class, e -> { - showToast(Icon.warning, "Sector " + e.sector.id + " [scarlet]lost!"); + showToast(Icon.warning, "Sector [accent]" + e.sector.name() + "[white] lost!"); + }); + + //TODO localize + Events.on(SectorInvasionEvent.class, e -> { + showToast(Icon.warning, "Sector [accent]" + e.sector.name() + "[white] under attack!"); }); Events.on(ResetEvent.class, e -> { @@ -63,36 +89,25 @@ public class HudFragment extends Fragment{ coreItems.clear(); }); - Events.on(TurnEvent.class, e -> { - Seq attacked = universe.getAttacked(state.getSector().planet); - - if(attacked.any()){ - - //TODO localize - String text = attacked.size > 1 ? attacked.size + " sectors attacked." : "Sector " + attacked.first().id + " under attack."; - - showToast(Icon.warning, text); - } - - //ui.announce("[accent][[ Turn " + universe.turn() + " ]\n[scarlet]" + attackedSectors.size + "[lightgray] sector(s) attacked."); - }); - //paused table parent.fill(t -> { + t.name = "paused"; t.top().visible(() -> state.isPaused()).touchable = Touchable.disabled; t.table(Styles.black5, top -> top.add("@paused").style(Styles.outlineLabel).pad(8f)).growX(); }); //minimap + position parent.fill(t -> { + t.name = "minimap/position"; t.visible(() -> Core.settings.getBool("minimap") && !state.rules.tutorial && shown); //minimap - t.add(new Minimap()); + t.add(new Minimap()).name("minimap"); t.row(); //position t.label(() -> player.tileX() + "," + player.tileY()) .visible(() -> Core.settings.getBool("position") && !state.rules.tutorial) - .touchable(Touchable.disabled); + .touchable(Touchable.disabled) + .name("position"); t.top().right(); }); @@ -104,15 +119,18 @@ public class HudFragment extends Fragment{ if(mobile){ cont.table(select -> { + select.name = "mobile buttons"; select.left(); select.defaults().size(dsize).left(); ImageButtonStyle style = Styles.clearTransi; - select.button(Icon.menu, style, ui.paused::show); + select.button(Icon.menu, style, ui.paused::show).name("menu"); flip = select.button(Icon.upOpen, style, this::toggleMenus).get(); + flip.name = "flip"; - select.button(Icon.paste, style, ui.schematics::show); + select.button(Icon.paste, style, ui.schematics::show) + .name("schematics"); select.button(Icon.pause, style, () -> { if(net.active()){ @@ -141,7 +159,7 @@ public class HudFragment extends Fragment{ }else{ ui.database.show(); } - }).update(i -> { + }).name("chat").update(i -> { if(net.active() && mobile){ i.getStyle().imageUp = Icon.chat; }else if(state.isCampaign()){ @@ -167,14 +185,15 @@ public class HudFragment extends Fragment{ Table wavesMain, editorMain; - cont.stack(wavesMain = new Table(), editorMain = new Table()).height(wavesMain.getPrefHeight()); + cont.stack(wavesMain = new Table(), editorMain = new Table()).height(wavesMain.getPrefHeight()) + .name("waves/editor"); wavesMain.visible(() -> shown && !state.isEditor()); - wavesMain.top().left(); + wavesMain.top().left().name = "waves"; wavesMain.table(s -> { //wave info button with text - s.add(makeStatusTable()).grow(); + s.add(makeStatusTable()).grow().name("status"); //table with button to skip wave s.button(Icon.play, Styles.righti, 30f, () -> { @@ -183,18 +202,22 @@ public class HudFragment extends Fragment{ }else{ logic.skipWave(); } - }).growY().fillX().right().width(40f).disabled(b -> !canSkipWave()).visible(() -> state.rules.waves); + }).growY().fillX().right().width(40f).disabled(b -> !canSkipWave()) + .visible(() -> state.rules.waves).name("skip"); }).width(dsize * 5 + 4f); wavesMain.row(); wavesMain.table(Tex.button, t -> t.margin(10f).add(new Bar("boss.health", Pal.health, () -> state.boss() == null ? 0f : state.boss().healthf()).blink(Color.white)) - .grow()).fillX().visible(() -> state.rules.waves && state.boss() != null).height(60f).get(); + .grow()).fillX().visible(() -> state.rules.waves && state.boss() != null).height(60f).get() + .name = "boss"; wavesMain.row(); + editorMain.name = "editor"; editorMain.table(Tex.buttonEdge4, t -> { //t.margin(0f); + t.name = "teams"; t.add("@editor.teams").growX().left(); t.row(); t.table(teams -> { @@ -215,29 +238,33 @@ public class HudFragment extends Fragment{ }).width(dsize * 5 + 4f); editorMain.visible(() -> shown && state.isEditor()); - //fps display cont.table(info -> { + info.name = "fps/ping"; info.touchable = Touchable.disabled; info.top().left().margin(4).visible(() -> Core.settings.getBool("fps") && shown); info.update(() -> info.setTranslation(state.rules.waves || state.isEditor() ? 0f : -Scl.scl(dsize * 4 + 3), 0)); IntFormat fps = new IntFormat("fps"); IntFormat ping = new IntFormat("ping"); - info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left().style(Styles.outlineLabel); + info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left() + .style(Styles.outlineLabel).name("fps"); info.row(); - info.label(() -> ping.get(netClient.getPing())).visible(net::client).left().style(Styles.outlineLabel); + info.label(() -> ping.get(netClient.getPing())).visible(net::client).left() + .style(Styles.outlineLabel).name("ping"); }).top().left(); }); //core items parent.fill(t -> { + t.name = "coreitems"; t.top().add(coreItems); t.visible(() -> Core.settings.getBool("coreitems") && !mobile && !state.isPaused() && shown); }); //spawner warning parent.fill(t -> { + t.name = "nearpoint"; t.touchable = Touchable.disabled; t.table(Styles.black, c -> c.add("@nearpoint") .update(l -> l.setColor(Tmp.c1.set(Color.white).lerp(Color.scarlet, Mathf.absin(Time.time(), 10f, 1f)))) @@ -246,12 +273,14 @@ public class HudFragment extends Fragment{ }); parent.fill(t -> { + t.name = "waiting"; t.visible(() -> netServer.isWaitingForPlayers()); t.table(Tex.button, c -> c.add("@waiting.players")); }); //'core is under attack' table parent.fill(t -> { + t.name = "coreattack"; t.touchable = Touchable.disabled; float notifDuration = 240f; float[] coreAttackTime = {0}; @@ -262,6 +291,7 @@ public class HudFragment extends Fragment{ }); t.top().visible(() -> { + if(!shown) return false; if(state.isMenu() || !state.teams.get(player.team()).hasCore()){ coreAttackTime[0] = 0f; return false; @@ -284,6 +314,7 @@ public class HudFragment extends Fragment{ //tutorial text parent.fill(t -> { + t.name = "tutorial"; Runnable resize = () -> { t.clearChildren(); t.top().right().visible(() -> state.rules.tutorial); @@ -306,11 +337,13 @@ public class HudFragment extends Fragment{ //'saving' indicator parent.fill(t -> { + t.name = "saving"; t.bottom().visible(() -> control.saves.isSaving()); t.add("@saving").style(Styles.outlineLabel); }); parent.fill(p -> { + p.name = "hudtext"; p.top().table(Styles.black3, t -> t.margin(4).label(() -> hudText) .style(Styles.outlineLabel)).padTop(10).visible(p.color.a >= 0.001f); p.update(() -> { @@ -326,6 +359,7 @@ public class HudFragment extends Fragment{ //TODO DEBUG: rate table if(false) parent.fill(t -> { + t.name = "rates"; t.bottom().left(); t.table(Styles.black6, c -> { Bits used = new Bits(content.items().size); @@ -420,10 +454,6 @@ public class HudFragment extends Fragment{ }); } - public boolean shown(){ - return shown; - } - /** Show unlock notification for a new recipe. */ public void showUnlock(UnlockableContent content){ //some content may not have icons... yet @@ -564,6 +594,7 @@ public class HudFragment extends Fragment{ StringBuilder ibuild = new StringBuilder(); IntFormat wavef = new IntFormat("wave"); + IntFormat wavefc = new IntFormat("wave.cap"); IntFormat enemyf = new IntFormat("wave.enemy"); IntFormat enemiesf = new IntFormat("wave.enemies"); IntFormat waitingf = new IntFormat("wave.waiting", i -> { @@ -681,7 +712,7 @@ public class HudFragment extends Fragment{ t.add(new SideBar(() -> player.unit().healthf(), () -> true, true)).width(bw).growY().padRight(pad); t.image(() -> player.icon()).scaling(Scaling.bounded).grow().maxWidth(54f); t.add(new SideBar(() -> player.dead() ? 0f : player.displayAmmo() ? player.unit().ammof() : player.unit().healthf(), () -> !player.displayAmmo(), false)).width(bw).growY().padLeft(pad).update(b -> { - b.color.set(player.displayAmmo() ? player.dead() || player.unit() instanceof BlockUnitc ? Pal.ammo : player.unit().type().ammoType.color : Pal.health); + b.color.set(player.displayAmmo() ? player.dead() || player.unit() instanceof BlockUnitc ? Pal.ammo : player.unit().type.ammoType.color : Pal.health); }); t.getChildren().get(1).toFront(); @@ -689,7 +720,11 @@ public class HudFragment extends Fragment{ table.labelWrap(() -> { builder.setLength(0); - builder.append(wavef.get(state.wave)); + if(state.rules.winWave > 1 && state.rules.winWave >= state.wave && state.isCampaign()){ + builder.append(wavefc.get(state.wave, state.rules.winWave)); + }else{ + builder.append(wavef.get(state.wave)); + } builder.append("\n"); if(state.enemies > 0){ @@ -702,7 +737,7 @@ public class HudFragment extends Fragment{ } if(state.rules.waveTimer){ - builder.append((logic.isWaitingWave() ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60))))); + builder.append((logic.isWaitingWave() ? Core.bundle.get("wave.waveInProgress") : (waitingf.get((int)(state.wavetime/60))))); }else if(state.enemies == 0){ builder.append(Core.bundle.get("waiting")); } diff --git a/core/src/mindustry/ui/fragments/MenuFragment.java b/core/src/mindustry/ui/fragments/MenuFragment.java index 45faa9bf10..cd8d13be0d 100644 --- a/core/src/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/mindustry/ui/fragments/MenuFragment.java @@ -45,6 +45,7 @@ public class MenuFragment extends Fragment{ parent.fill(c -> { container = c; + c.name = "menu container"; if(!mobile){ buildDesktop(); @@ -57,8 +58,8 @@ public class MenuFragment extends Fragment{ //info icon if(mobile){ - parent.fill(c -> c.bottom().left().button("", Styles.infot, ui.about::show).size(84, 45)); - parent.fill(c -> c.bottom().right().button("", Styles.discordt, ui.discord::show).size(84, 45)); + parent.fill(c -> c.bottom().left().button("", Styles.infot, ui.about::show).size(84, 45).name("info")); + parent.fill(c -> c.bottom().right().button("", Styles.discordt, ui.discord::show).size(84, 45).name("discord")); }else if(becontrol.active()){ parent.fill(c -> c.bottom().right().button("@be.check", Icon.refresh, () -> { ui.loadfrag.show(); @@ -68,7 +69,7 @@ public class MenuFragment extends Fragment{ ui.showInfo("@be.noupdates"); } }); - }).size(200, 60).update(t -> { + }).size(200, 60).name("becheck").update(t -> { t.getLabel().setColor(becontrol.isUpdateAvailable() ? Tmp.c1.set(Color.white).lerp(Pal.accent, Mathf.absin(5f, 1f)) : Color.white); })); } @@ -93,6 +94,7 @@ public class MenuFragment extends Fragment{ private void buildMobile(){ container.clear(); + container.name = "buttons"; container.setSize(Core.graphics.getWidth(), Core.graphics.getHeight()); float size = 120f; @@ -153,7 +155,6 @@ public class MenuFragment extends Fragment{ container.clear(); container.setSize(Core.graphics.getWidth(), Core.graphics.getHeight()); - float width = 230f; Drawable background = Styles.black6; @@ -161,6 +162,7 @@ public class MenuFragment extends Fragment{ container.add().width(Core.graphics.getWidth()/10f); container.table(background, t -> { t.defaults().width(width).height(70f); + t.name = "buttons"; buttons(t, new Buttoni("@play", Icon.play, @@ -183,6 +185,7 @@ public class MenuFragment extends Fragment{ container.table(background, t -> { submenu = t; + t.name = "submenu"; t.color.a = 0f; t.top(); t.defaults().width(width).height(70f); diff --git a/core/src/mindustry/ui/fragments/MinimapFragment.java b/core/src/mindustry/ui/fragments/MinimapFragment.java index 7c9d3b5994..0bb3632a61 100644 --- a/core/src/mindustry/ui/fragments/MinimapFragment.java +++ b/core/src/mindustry/ui/fragments/MinimapFragment.java @@ -18,7 +18,7 @@ public class MinimapFragment extends Fragment{ private boolean shown; float panx, pany, zoom = 1f, lastZoom = -1; private float baseSize = Scl.scl(5f); - private Element elem; + public Element elem; @Override public void build(Group parent){ @@ -111,12 +111,11 @@ public class MinimapFragment extends Fragment{ } public void toggle(){ - if(Core.settings.getBool("mapcenter")){ - float size = baseSize * zoom * world.width(); - float ratio = (float)renderer.minimap.getTexture().height / renderer.minimap.getTexture().width; - panx = (size/2f - player.x() / (world.width() * tilesize) * size) / zoom; - pany = (size*ratio/2f - player.y() / (world.height() * tilesize) * size*ratio) / zoom; - } + float size = baseSize * zoom * world.width(); + float ratio = (float)renderer.minimap.getTexture().height / renderer.minimap.getTexture().width; + float px = player.dead() ? Core.camera.position.x : player.x, py = player.dead() ? Core.camera.position.y : player.y; + panx = (size/2f - px / (world.width() * tilesize) * size) / zoom; + pany = (size*ratio/2f - py / (world.height() * tilesize) * size*ratio) / zoom; shown = !shown; } } diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java index cd5279d0d8..25c009ff63 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -30,6 +30,7 @@ public class PlacementFragment extends Fragment{ final int rowWidth = 4; public Category currentCategory = Category.distribution; + Seq returnArray = new Seq<>(), returnArray2 = new Seq<>(); Seq returnCatArray = new Seq<>(); boolean[] categoryEmpty = new boolean[Category.all.length]; @@ -80,6 +81,10 @@ public class PlacementFragment extends Fragment{ }); } + public Displayable hover(){ + return hover; + } + void rebuild(){ currentCategory = Category.turret; Group group = toggler.parent; @@ -192,7 +197,7 @@ public class PlacementFragment extends Fragment{ public void build(Group parent){ parent.fill(full -> { toggler = full; - full.bottom().right().visible(() -> ui.hudfrag.shown()); + full.bottom().right().visible(() -> ui.hudfrag.shown); full.table(frame -> { @@ -284,7 +289,7 @@ public class PlacementFragment extends Fragment{ topTable.table(header -> { String keyCombo = ""; - if(!mobile && Core.settings.getBool("blockselectkeys")){ + if(!mobile){ Seq blocks = getByCategory(currentCategory); for(int i = 0; i < blocks.size; i++){ if(blocks.get(i) == displayBlock && (i + 1) / 10 - 1 < blockSelect.length){ diff --git a/core/src/mindustry/ui/fragments/PlayerListFragment.java b/core/src/mindustry/ui/fragments/PlayerListFragment.java index eae9407131..c006dcf3ff 100644 --- a/core/src/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/mindustry/ui/fragments/PlayerListFragment.java @@ -24,7 +24,9 @@ public class PlayerListFragment extends Fragment{ @Override public void build(Group parent){ + content.name = "players"; parent.fill(cont -> { + cont.name = "playerlist"; cont.visible(() -> visible); cont.update(() -> { if(!(net.active() && state.isGame())){ @@ -47,6 +49,7 @@ public class PlayerListFragment extends Fragment{ sField = pane.field(null, text -> { rebuild(); }).grow().pad(8).get(); + sField.name = "search"; sField.setMaxLength(maxNameLength); sField.setMessageText(Core.bundle.format("players.search")); @@ -56,6 +59,7 @@ public class PlayerListFragment extends Fragment{ pane.table(menu -> { menu.defaults().growX().height(50f).fillY(); + menu.name = "menu"; menu.button("@server.bans", ui.bans::show).disabled(b -> net.client()); menu.button("@server.admins", ui.admins::show).disabled(b -> net.client()); @@ -99,6 +103,7 @@ public class PlayerListFragment extends Fragment{ }; table.margin(8); table.add(new Image(user.icon()).setScaling(Scaling.bounded)).grow(); + table.name = user.name(); button.add(table).size(h); button.labelWrap("[#" + user.color().toString().toUpperCase() + "]" + user.name()).width(170f).pad(10); diff --git a/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java b/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java index 73861538e3..3f33dd1b4b 100644 --- a/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java +++ b/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java @@ -39,7 +39,6 @@ public class ScriptConsoleFragment extends Table{ }; public ScriptConsoleFragment(){ - setFillParent(true); font = Fonts.def; diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 189a9c21c1..f74e9bb099 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -14,6 +14,7 @@ import arc.struct.*; import arc.util.*; import arc.util.pooling.*; import mindustry.annotations.Annotations.*; +import mindustry.content.*; import mindustry.core.*; import mindustry.ctype.*; import mindustry.entities.*; @@ -35,8 +36,6 @@ import java.util.*; import static mindustry.Vars.*; public class Block extends UnlockableContent{ - public static final int crackRegions = 8, maxCrackSize = 9; - public boolean hasItems; public boolean hasLiquids; public boolean hasPower; @@ -52,7 +51,6 @@ public class Block extends UnlockableContent{ public float liquidCapacity = 10f; public float liquidPressure = 1f; - public final BlockStats stats = new BlockStats(); public final BlockBars bars = new BlockBars(); public final Consumers consumes = new Consumers(); @@ -102,6 +100,8 @@ public class Block extends UnlockableContent{ public boolean autoResetEnabled = true; /** if true, the block stops updating when disabled */ public boolean noUpdateDisabled = false; + /** Whether to use this block's color in the minimap. Only used for overlays. */ + public boolean useColor = true; /** tile entity health */ public int health = -1; /** base block explosiveness */ @@ -193,6 +193,8 @@ public class Block extends UnlockableContent{ public BuildPlaceability buildPlaceability = BuildPlaceability.always; /** Multiplier for speed of building this block. */ public float buildCostMultiplier = 1f; + /** Multiplier for cost of research in tech tree. */ + public float researchCostMultiplier = 1; /** Whether this block has instant transfer.*/ public boolean instantTransfer = false; /** Whether you can rotate this block with Keybind rotateplaced + Scroll Wheel. */ @@ -210,8 +212,6 @@ public class Block extends UnlockableContent{ public @Load("@-team") TextureRegion teamRegion; public TextureRegion[] teamRegions; - //TODO make this not static - public static TextureRegion[][] cracks; protected static final Seq tempTiles = new Seq<>(); protected static final Seq tempTileEnts = new Seq<>(); @@ -322,27 +322,30 @@ public class Block extends UnlockableContent{ return update || destructible; } + @Override public void setStats(){ - stats.add(BlockStat.size, "@x@", size, size); - stats.add(BlockStat.health, health, StatUnit.none); + super.setStats(); + + stats.add(Stat.size, "@x@", size, size); + stats.add(Stat.health, health, StatUnit.none); if(canBeBuilt()){ - stats.add(BlockStat.buildTime, buildCost / 60, StatUnit.seconds); - stats.add(BlockStat.buildCost, new ItemListValue(false, requirements)); + stats.add(Stat.buildTime, buildCost / 60, StatUnit.seconds); + stats.add(Stat.buildCost, new ItemListValue(false, requirements)); } if(instantTransfer){ - stats.add(BlockStat.maxConsecutive, 2, StatUnit.none); + stats.add(Stat.maxConsecutive, 2, StatUnit.none); } consumes.display(stats); - // Note: Power stats are added by the consumers. - if(hasLiquids) stats.add(BlockStat.liquidCapacity, liquidCapacity, StatUnit.liquidUnits); - if(hasItems && itemCapacity > 0) stats.add(BlockStat.itemCapacity, itemCapacity, StatUnit.items); + //Note: Power stats are added by the consumers. + if(hasLiquids) stats.add(Stat.liquidCapacity, liquidCapacity, StatUnit.liquidUnits); + if(hasItems && itemCapacity > 0) stats.add(Stat.itemCapacity, itemCapacity, StatUnit.items); } public void setBars(){ - bars.add("health", entity -> new Bar("blocks.health", Pal.health, entity::healthf).blink(Color.white)); + bars.add("health", entity -> new Bar("stat.health", Pal.health, entity::healthf).blink(Color.white)); if(hasLiquids){ Func current; @@ -350,7 +353,7 @@ public class Block extends UnlockableContent{ Liquid liquid = consumes.get(ConsumeType.liquid).liquid; current = entity -> liquid; }else{ - current = entity -> entity.liquids.current(); + current = entity -> entity.liquids == null ? Liquids.water : entity.liquids.current(); } bars.add("liquid", entity -> new Bar(() -> entity.liquids.get(current.get(entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get(entity).localizedName, () -> current.get(entity).barColor(), () -> entity.liquids.get(current.get(entity)) / liquidCapacity)); @@ -619,7 +622,7 @@ public class Block extends UnlockableContent{ public ItemStack[] researchRequirements(){ ItemStack[] out = new ItemStack[requirements.length]; for(int i = 0; i < out.length; i++){ - int quantity = 40 + Mathf.round(Mathf.pow(requirements[i].amount, 1.25f) * 20, 10); + int quantity = 40 + Mathf.round(Mathf.pow(requirements[i].amount, 1.15f) * 20 * researchCostMultiplier, 10); out[i] = new ItemStack(requirements[i].item, UI.roundAmount(quantity)); } @@ -635,11 +638,6 @@ public class Block extends UnlockableContent{ } } - @Override - public void displayInfo(Table table){ - ContentDisplay.displayBlock(table, this); - } - @Override public ContentType getContentType(){ return ContentType.block; @@ -670,9 +668,10 @@ public class Block extends UnlockableContent{ if(consumes.has(ConsumeType.item)) hasItems = true; if(consumes.has(ConsumeType.liquid)) hasLiquids = true; - setStats(); setBars(); + stats.useCategories = true; + consumes.init(); if(!outputsPower && consumes.hasPower() && consumes.getPower().buffered){ @@ -685,15 +684,6 @@ public class Block extends UnlockableContent{ public void load(){ region = Core.atlas.find(name); - if(cracks == null || (cracks[0][0].texture != null && cracks[0][0].texture.isDisposed())){ - cracks = new TextureRegion[maxCrackSize][crackRegions]; - for(int size = 1; size <= maxCrackSize; size++){ - for(int i = 0; i < crackRegions; i++){ - cracks[size - 1][i] = Core.atlas.find("cracks-" + size + "-" + i); - } - } - } - ContentRegions.loadRegions(this); //load specific team regions diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 070ddab553..98409e6d18 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -45,7 +45,7 @@ public class Build{ Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true))); } - /** Places a BuildBlock at this location. */ + /** Places a ConstructBlock at this location. */ @Remote(called = Loc.server) public static void beginPlace(Block result, Team team, int x, int y, int rotation){ if(!validPlace(result, team, x, y, rotation)){ diff --git a/core/src/mindustry/world/CachedTile.java b/core/src/mindustry/world/CachedTile.java index 3c14ade132..5777ece759 100644 --- a/core/src/mindustry/world/CachedTile.java +++ b/core/src/mindustry/world/CachedTile.java @@ -21,7 +21,7 @@ public class CachedTile extends Tile{ } @Override - protected void changeEntity(Team team, Prov entityprov, int rotation){ + protected void changeBuild(Team team, Prov entityprov, int rotation){ build = null; Block block = block(); diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index 0f761ad745..18696d8930 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -45,7 +45,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ this.block = wall; //update entity and create it if needed - changeEntity(Team.derelict, wall::newBuilding, 0); + changeBuild(Team.derelict, wall::newBuilding, 0); changed(); } @@ -186,7 +186,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ this.block = type; preChanged(); - changeEntity(team, entityprov, (byte)Mathf.mod(rotation, 4)); + changeBuild(team, entityprov, (byte)Mathf.mod(rotation, 4)); if(build != null){ build.team(team); @@ -267,6 +267,10 @@ public class Tile implements Position, QuadTreeObject, Displayable{ Geometry.circle(x, y, world.width(), world.height(), radius, cons); } + public void circle(int radius, Cons cons){ + circle(radius, (x, y) -> cons.get(world.rawTile(x, y))); + } + public void recache(){ if(!headless && !world.isGenerating()){ renderer.blocks.floor.recacheTile(this); @@ -332,6 +336,11 @@ public class Tile implements Position, QuadTreeObject, Displayable{ recache(); } + /** Sets the overlay without a recache. */ + public void setOverlayQuiet(Block block){ + this.overlay = (Floor)block; + } + public void clearOverlay(){ setOverlayID((short)0); } @@ -346,7 +355,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } public boolean solid(){ - return block.solid || (build != null && build.checkSolid()); + return block.solid || floor.solid || (build != null && build.checkSolid()); } public boolean breakable(){ @@ -421,15 +430,15 @@ public class Tile implements Position, QuadTreeObject, Displayable{ getHitbox(rect); } - public Tile getNearby(Point2 relative){ + public Tile nearby(Point2 relative){ return world.tile(x + relative.x, y + relative.y); } - public Tile getNearby(int dx, int dy){ + public Tile nearby(int dx, int dy){ return world.tile(x + dx, y + dy); } - public Tile getNearby(int rotation){ + public Tile nearby(int rotation){ if(rotation == 0) return world.tile(x + 1, y); if(rotation == 1) return world.tile(x, y + 1); if(rotation == 2) return world.tile(x - 1, y); @@ -437,7 +446,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ return null; } - public Building getNearbyEntity(int rotation){ + public Building nearbyBuild(int rotation){ if(rotation == 0) return world.build(x + 1, y); if(rotation == 1) return world.build(x, y + 1); if(rotation == 2) return world.build(x - 1, y); @@ -494,7 +503,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{ } } - protected void changeEntity(Team team, Prov entityprov, int rotation){ + protected void changeBuild(Team team, Prov entityprov, int rotation){ if(build != null){ int size = build.block.size; build.remove(); diff --git a/core/src/mindustry/world/blocks/Autotiler.java b/core/src/mindustry/world/blocks/Autotiler.java index 2989436fac..027ac93b31 100644 --- a/core/src/mindustry/world/blocks/Autotiler.java +++ b/core/src/mindustry/world/blocks/Autotiler.java @@ -133,7 +133,7 @@ public interface Autotiler{ for(int i = 0; i < 4; i++){ int realDir = Mathf.mod(rotation - i, 4); - if(blends(tile, rotation, directional, i, world) && (tile != null && tile.getNearbyEntity(realDir) != null && !tile.getNearbyEntity(realDir).block.squareSprite)){ + if(blends(tile, rotation, directional, i, world) && (tile != null && tile.nearbyBuild(realDir) != null && !tile.nearbyBuild(realDir).block.squareSprite)){ blendresult[4] |= (1 << i); } } @@ -194,7 +194,7 @@ public interface Autotiler{ // TODO docs -- use for direction? default boolean blends(Tile tile, int rotation, int direction){ - Building other = tile.getNearbyEntity(Mathf.mod(rotation - direction, 4)); + Building other = tile.nearbyBuild(Mathf.mod(rotation - direction, 4)); return other != null && other.team == tile.team() && blends(tile, rotation, other.tileX(), other.tileY(), other.rotation, other.block); } diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index 7f50b81c01..cefdfa6887 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -42,7 +42,7 @@ public class ConstructBlock extends Block{ consBlocks[size - 1] = this; } - /** Returns a BuildBlock by size. */ + /** Returns a ConstructBlock by size. */ public static ConstructBlock get(int size){ if(size > maxSize) throw new IllegalArgumentException("No. Don't place ConstructBlock of size greater than " + maxSize); return consBlocks[size - 1]; @@ -58,7 +58,7 @@ public class ConstructBlock extends Block{ } @Remote(called = Loc.server) - public static void constructFinish(Tile tile, Block block, Unit builder, byte rotation, Team team, Object config){ + public static void constructFinish(Tile tile, Block block, @Nullable Unit builder, byte rotation, Team team, Object config){ if(tile == null) return; float healthf = tile.build == null ? 1f : tile.build.healthf(); @@ -76,6 +76,10 @@ public class ConstructBlock extends Block{ if(prev != null && prev.size > 0){ tile.build.overwrote(prev); } + + if(builder != null && builder.isPlayer()){ + tile.build.lastAccessed = builder.getPlayer().name; + } } //last builder was this local client player, call placed() @@ -142,6 +146,9 @@ public class ConstructBlock extends Block{ public Block previous; public Object lastConfig; + @Nullable + public Unit lastBuilder; + private float[] accumulator; private float[] totalAccumulator; @@ -180,7 +187,7 @@ public class ConstructBlock extends Block{ public void onDestroyed(){ Fx.blockExplosionSmoke.at(tile); - if(!tile.floor().solid && !tile.floor().isLiquid){ + if(!tile.floor().solid && tile.floor().hasSurface()){ Effect.rubble(x, y, size); } } @@ -214,6 +221,10 @@ public class ConstructBlock extends Block{ return; } + if(builder.isPlayer()){ + lastBuilder = builder; + } + lastConfig = config; if(cblock.requirements.length != accumulator.length || totalAccumulator.length != cblock.requirements.length){ @@ -233,13 +244,18 @@ public class ConstructBlock extends Block{ progress = Mathf.clamp(progress + maxProgress); if(progress >= 1f || state.rules.infiniteResources){ - constructed(tile, cblock, builder, (byte)rotation, builder.team, config); + if(lastBuilder == null) lastBuilder = builder; + constructed(tile, cblock, lastBuilder, (byte)rotation, builder.team, config); } } public void deconstruct(Unit builder, @Nullable Building core, float amount){ float deconstructMultiplier = state.rules.deconstructRefundMultiplier; + if(builder.isPlayer()){ + lastBuilder = builder; + } + if(cblock != null){ ItemStack[] requirements = cblock.requirements; if(requirements.length != accumulator.length || totalAccumulator.length != requirements.length){ @@ -271,7 +287,8 @@ public class ConstructBlock extends Block{ progress = Mathf.clamp(progress - amount); if(progress <= 0 || state.rules.infiniteResources){ - Call.deconstructFinish(tile, this.cblock == null ? previous : this.cblock, builder); + if(lastBuilder == null) lastBuilder = builder; + Call.deconstructFinish(tile, this.cblock == null ? previous : this.cblock, lastBuilder); } } diff --git a/core/src/mindustry/world/blocks/ControlBlock.java b/core/src/mindustry/world/blocks/ControlBlock.java index 6724ff9205..7688cdab6a 100644 --- a/core/src/mindustry/world/blocks/ControlBlock.java +++ b/core/src/mindustry/world/blocks/ControlBlock.java @@ -10,4 +10,14 @@ public interface ControlBlock{ default boolean isControlled(){ return unit().isPlayer(); } + + /** @return whether this block can be controlled at all. */ + default boolean canControl(){ + return true; + } + + /** @return whether targets should automatically be selected (on mobile) */ + default boolean shouldAutoTarget(){ + return true; + } } diff --git a/core/src/mindustry/world/blocks/ItemSelection.java b/core/src/mindustry/world/blocks/ItemSelection.java index 921808eb08..f2c0b73084 100644 --- a/core/src/mindustry/world/blocks/ItemSelection.java +++ b/core/src/mindustry/world/blocks/ItemSelection.java @@ -15,6 +15,10 @@ public class ItemSelection{ private static float scrollPos = 0f; public static void buildTable(Table table, Seq items, Prov holder, Cons consumer){ + buildTable(table, items, holder, consumer, true); + } + + public static void buildTable(Table table, Seq items, Prov holder, Cons consumer, boolean closeSelect){ ButtonGroup group = new ButtonGroup<>(); group.setMinCheckCount(0); @@ -26,7 +30,9 @@ public class ItemSelection{ for(T item : items){ if(!item.unlockedNow()) continue; - ImageButton button = cont.button(Tex.whiteui, Styles.clearToggleTransi, 24, () -> control.input.frag.config.hideConfig()).group(group).get(); + ImageButton button = cont.button(Tex.whiteui, Styles.clearToggleTransi, 24, () -> { + if(closeSelect) control.input.frag.config.hideConfig(); + }).group(group).get(); button.changed(() -> consumer.get(button.isChecked() ? item : null)); button.getStyle().imageUp = new TextureRegionDrawable(item.icon(Cicon.small)); button.update(() -> button.setChecked(holder.get() == item)); diff --git a/core/src/mindustry/world/blocks/campaign/LaunchPad.java b/core/src/mindustry/world/blocks/campaign/LaunchPad.java index 093fff4f70..ff069acc48 100644 --- a/core/src/mindustry/world/blocks/campaign/LaunchPad.java +++ b/core/src/mindustry/world/blocks/campaign/LaunchPad.java @@ -42,7 +42,7 @@ public class LaunchPad extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.launchTime, launchTime / 60f, StatUnit.seconds); + stats.add(Stat.launchTime, launchTime / 60f, StatUnit.seconds); } @Override @@ -115,16 +115,16 @@ public class LaunchPad extends Block{ public void display(Table table){ super.display(table); + if(!state.isCampaign()) return; + table.row(); table.label(() -> { Sector dest = state.secinfo.getRealDestination(); return Core.bundle.format("launch.destination", dest == null ? Core.bundle.get("sectors.nonelaunch") : - dest.preset == null ? - "[accent]Sector " + dest.id : - "[accent]" + dest.preset.localizedName); - }).pad(4); + "[accent]" + dest.name()); + }).pad(4).wrap().width(200f).left(); } @Override @@ -213,7 +213,7 @@ public class LaunchPad extends Block{ //actually launch the items upon removal if(team() == state.rules.defaultTeam){ if(destsec != null && (destsec != state.rules.sector || net.client())){ - ItemSeq dest = destsec.getExtraItems(); + ItemSeq dest = new ItemSeq(); for(ItemStack stack : stacks){ dest.add(stack); @@ -223,7 +223,7 @@ public class LaunchPad extends Block{ Events.fire(new LaunchItemEvent(stack)); } - destsec.setExtraItems(dest); + destsec.addItems(dest); } } } diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index b508e90965..46fb01d7d5 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -12,6 +12,7 @@ import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.logic.*; import mindustry.world.*; import mindustry.world.consumers.*; import mindustry.world.meta.*; @@ -60,11 +61,11 @@ public class ForceProjector extends Block{ @Override public void setStats(){ super.setStats(); - stats.add(BlockStat.shieldHealth, breakage, StatUnit.none); - stats.add(BlockStat.cooldownTime, (int) (breakage / cooldownBrokenBase / 60f), StatUnit.seconds); - stats.add(BlockStat.powerUse, basePowerDraw * 60f, StatUnit.powerSecond); - stats.add(BlockStat.boostEffect, phaseRadiusBoost / tilesize, StatUnit.blocks); - stats.add(BlockStat.boostEffect, phaseShieldBoost, StatUnit.shieldHealth); + stats.add(Stat.shieldHealth, breakage, StatUnit.none); + stats.add(Stat.cooldownTime, (int) (breakage / cooldownBrokenBase / 60f), StatUnit.seconds); + stats.add(Stat.powerUse, basePowerDraw * 60f, StatUnit.powerSecond); + stats.add(Stat.boostEffect, phaseRadiusBoost / tilesize, StatUnit.blocks); + stats.add(Stat.boostEffect, phaseShieldBoost, StatUnit.shieldHealth); } @Override @@ -80,11 +81,16 @@ public class ForceProjector extends Block{ Draw.color(); } - public class ForceBuild extends Building{ + public class ForceBuild extends Building implements Ranged{ public boolean broken = true; public float buildup, radscl, hit, warmup, phaseHeat; public ForceDraw drawer; + @Override + public float range(){ + return realRadius(); + } + @Override public void created(){ super.created(); diff --git a/core/src/mindustry/world/blocks/defense/MendProjector.java b/core/src/mindustry/world/blocks/defense/MendProjector.java index f9fc7b0ac8..cf71928f26 100644 --- a/core/src/mindustry/world/blocks/defense/MendProjector.java +++ b/core/src/mindustry/world/blocks/defense/MendProjector.java @@ -9,6 +9,7 @@ import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.logic.*; import mindustry.world.*; import mindustry.world.meta.*; @@ -43,11 +44,11 @@ public class MendProjector extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.repairTime, (int)(100f / healPercent * reload / 60f), StatUnit.seconds); - stats.add(BlockStat.range, range / tilesize, StatUnit.blocks); + stats.add(Stat.repairTime, (int)(100f / healPercent * reload / 60f), StatUnit.seconds); + stats.add(Stat.range, range / tilesize, StatUnit.blocks); - stats.add(BlockStat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks); - stats.add(BlockStat.boostEffect, (phaseBoost + healPercent) / healPercent, StatUnit.timesSpeed); + stats.add(Stat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks); + stats.add(Stat.boostEffect, (phaseBoost + healPercent) / healPercent, StatUnit.timesSpeed); } @Override @@ -55,11 +56,16 @@ public class MendProjector extends Block{ Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent); } - public class MendBuild extends Building{ + public class MendBuild extends Building implements Ranged{ float heat; float charge = Mathf.random(reload); float phaseHeat; + @Override + public float range(){ + return range; + } + @Override public void updateTile(){ heat = Mathf.lerpDelta(heat, consValid() || cheating() ? 1f : 0f, 0.08f); @@ -100,10 +106,9 @@ public class MendProjector extends Block{ Draw.color(baseColor, phaseColor, phaseHeat); Draw.alpha(heat * Mathf.absin(Time.time(), 10f, 1f) * 0.5f); Draw.rect(topRegion, x, y); - Draw.alpha(1f); Lines.stroke((2f * f + 0.2f) * heat); - Lines.square(x, y, ((1f - f) * 8f) * size / 2f); + Lines.square(x, y, Math.min(1f + (1f - f) * size * tilesize / 2f, size * tilesize/2f)); Draw.reset(); } diff --git a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java index 56010c7c0f..7cadaede81 100644 --- a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java +++ b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java @@ -8,6 +8,7 @@ import arc.util.io.*; import mindustry.annotations.Annotations.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.logic.*; import mindustry.world.*; import mindustry.world.meta.*; @@ -50,21 +51,26 @@ public class OverdriveProjector extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.speedIncrease, (int)(100f * speedBoost), StatUnit.percent); - stats.add(BlockStat.range, range / tilesize, StatUnit.blocks); - stats.add(BlockStat.productionTime, useTime / 60f, StatUnit.seconds); + stats.add(Stat.speedIncrease, (int)(100f * speedBoost), StatUnit.percent); + stats.add(Stat.range, range / tilesize, StatUnit.blocks); + stats.add(Stat.productionTime, useTime / 60f, StatUnit.seconds); if(hasBoost){ - stats.add(BlockStat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks); - stats.add(BlockStat.boostEffect, (int)((speedBoost + speedBoostPhase) * 100f), StatUnit.percent); + stats.add(Stat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks); + stats.add(Stat.boostEffect, (int)((speedBoost + speedBoostPhase) * 100f), StatUnit.percent); } } - public class OverdriveBuild extends Building{ + public class OverdriveBuild extends Building implements Ranged{ float heat; float charge = Mathf.random(reload); float phaseHeat; + @Override + public float range(){ + return range; + } + @Override public void drawLight(){ Drawf.light(team, x, y, 50f * efficiency(), baseColor, 0.7f * efficiency()); diff --git a/core/src/mindustry/world/blocks/defense/Wall.java b/core/src/mindustry/world/blocks/defense/Wall.java index 873cbaea78..a23a2583cd 100644 --- a/core/src/mindustry/world/blocks/defense/Wall.java +++ b/core/src/mindustry/world/blocks/defense/Wall.java @@ -17,16 +17,17 @@ import static mindustry.Vars.*; public class Wall extends Block{ public int variants = 0; - public float lightningChance = -0.001f; + /** Lighting chance. -1 to disable */ + public float lightningChance = -1f; public float lightningDamage = 20f; public int lightningLength = 17; public Color lightningColor = Pal.surge; public Sound lightningSound = Sounds.spark; - public float chanceDeflect = 10f; + /** Bullet deflection chance. -1 to disable */ + public float chanceDeflect = -1f; public boolean flashHit; public Color flashColor = Color.white; - public boolean deflect; public Sound deflectSound = Sounds.none; public Wall(String name){ @@ -34,10 +35,21 @@ public class Wall extends Block{ solid = true; destructible = true; group = BlockGroup.walls; - buildCostMultiplier = 5f; + buildCostMultiplier = 6f; canOverdrive = false; } + @Override + public void setStats(){ + super.setStats(); + + if(chanceDeflect > 0f) stats.add(Stat.baseDeflectChance, chanceDeflect, StatUnit.none); + if(lightningChance > 0f){ + stats.add(Stat.lightningChance, lightningChance * 100f, StatUnit.percent); + stats.add(Stat.lightningDamage, lightningDamage, StatUnit.none); + } + } + @Override public void load(){ super.load(); @@ -96,7 +108,7 @@ public class Wall extends Block{ hit = 1f; //create lightning if necessary - if(lightningChance > 0){ + if(lightningChance > 0f){ if(Mathf.chance(lightningChance)){ Lightning.create(team, lightningColor, lightningDamage, x, y, bullet.rotation() + 180f, lightningLength); lightningSound.at(tile, Mathf.random(0.9f, 1.1f)); @@ -104,7 +116,7 @@ public class Wall extends Block{ } //deflect bullets if necessary - if(deflect){ + if(chanceDeflect > 0f){ //slow bullets are not deflected if(bullet.vel().len() <= 0.1f || !bullet.type.reflectable) return true; diff --git a/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java b/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java new file mode 100644 index 0000000000..e10b1612e9 --- /dev/null +++ b/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java @@ -0,0 +1,67 @@ +package mindustry.world.blocks.defense.turrets; + +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.logic.*; +import mindustry.world.*; +import mindustry.world.consumers.*; +import mindustry.world.meta.*; + +import static mindustry.Vars.*; + +public abstract class BaseTurret extends Block{ + public float range = 80f; + public float rotateSpeed = 5; + + public boolean acceptCoolant = true; + /** Effect displayed when coolant is used. */ + public Effect coolEffect = Fx.fuelburn; + /** How much reload is lowered by for each unit of liquid of heat capacity. */ + public float coolantMultiplier = 5f; + + public BaseTurret(String name){ + super(name); + + update = true; + solid = true; + outlineIcon = true; + } + + @Override + public void init(){ + if(acceptCoolant && !consumes.has(ConsumeType.liquid)){ + hasLiquids = true; + consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.2f)).update(false).boost(); + } + + super.init(); + } + + @Override + public void drawPlace(int x, int y, int rotation, boolean valid){ + Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.placing); + } + + @Override + public void setStats(){ + super.setStats(); + + stats.add(Stat.shootRange, range / tilesize, StatUnit.blocks); + } + + public class BaseTurretBuild extends Building implements Ranged{ + public float rotation = 90; + + @Override + public float range(){ + return range; + } + + @Override + public void drawSelect(){ + Drawf.dashCircle(x, y, range, team.color); + } + } +} diff --git a/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java index 3680cce446..15feaf0379 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java @@ -1,10 +1,13 @@ package mindustry.world.blocks.defense.turrets; +import arc.audio.*; import arc.math.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.bullet.*; +import mindustry.type.*; +import mindustry.gen.*; import static mindustry.Vars.*; @@ -14,6 +17,7 @@ public class ChargeTurret extends PowerTurret{ public float chargeMaxDelay = 10f; public Effect chargeEffect = Fx.none; public Effect chargeBeginEffect = Fx.none; + public Sound chargeSound = Sounds.none; public ChargeTurret(String name){ super(name); @@ -28,7 +32,8 @@ public class ChargeTurret extends PowerTurret{ tr.trns(rotation, size * tilesize / 2f); chargeBeginEffect.at(x + tr.x, y + tr.y, rotation); - + chargeSound.at(x + tr.x, y + tr.y, 1); + for(int i = 0; i < chargeEffects; i++){ Time.run(Mathf.random(chargeMaxDelay), () -> { if(!isValid()) return; diff --git a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java index ea94a670b9..7550f23e79 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java @@ -19,7 +19,6 @@ import mindustry.world.meta.values.*; import static mindustry.Vars.*; public class ItemTurret extends Turret{ - public int maxAmmo = 30; public ObjectMap ammoTypes = new ObjectMap<>(); public ItemTurret(String name){ @@ -36,14 +35,18 @@ public class ItemTurret extends Turret{ public void setStats(){ super.setStats(); - stats.remove(BlockStat.itemCapacity); - stats.add(BlockStat.ammo, new AmmoListValue<>(ammoTypes)); + stats.remove(Stat.itemCapacity); + stats.add(Stat.ammo, new AmmoListValue<>(ammoTypes)); + } + + @Override + public void init(){ consumes.add(new ConsumeItemFilter(i -> ammoTypes.containsKey(i)){ @Override public void build(Building tile, Table table){ MultiReqImage image = new MultiReqImage(); content.items().each(i -> filter.get(i) && i.unlockedNow(), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium)), - () -> tile != null && !((ItemTurretBuild)tile).ammo.isEmpty() && ((ItemEntry)((ItemTurretBuild)tile).ammo.peek()).item == item))); + () -> tile != null && !((ItemTurretBuild)tile).ammo.isEmpty() && ((ItemEntry)((ItemTurretBuild)tile).ammo.peek()).item == item))); table.add(image).size(8 * 4); } @@ -55,10 +58,12 @@ public class ItemTurret extends Turret{ } @Override - public void display(BlockStats stats){ + public void display(Stats stats){ //don't display } }); + + super.init(); } public class ItemTurretBuild extends TurretBuild{ @@ -84,7 +89,7 @@ public class ItemTurret extends Turret{ public void displayBars(Table bars){ super.displayBars(bars); - bars.add(new Bar("blocks.ammo", Pal.ammo, () -> (float)totalAmmo / maxAmmo)).growX(); + bars.add(new Bar("stat.ammo", Pal.ammo, () -> (float)totalAmmo / maxAmmo)).growX(); bars.row(); } diff --git a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java index c47a279414..3aefcdd33c 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java @@ -33,11 +33,11 @@ public class LaserTurret extends PowerTurret{ public void setStats(){ super.setStats(); - stats.remove(BlockStat.booster); - stats.add(BlockStat.input, new BoosterListValue(reloadTime, consumes.get(ConsumeType.liquid).amount, coolantMultiplier, false, l -> consumes.liquidfilters.get(l.id))); - stats.remove(BlockStat.damage); + stats.remove(Stat.booster); + stats.add(Stat.input, new BoosterListValue(reloadTime, consumes.get(ConsumeType.liquid).amount, coolantMultiplier, false, l -> consumes.liquidfilters.get(l.id))); + stats.remove(Stat.damage); //damages every 5 ticks, at least in meltdown's case - stats.add(BlockStat.damage, shootType.damage * 60f / 5f, StatUnit.perSecond); + stats.add(Stat.damage, shootType.damage * 60f / 5f, StatUnit.perSecond); } public class LaserTurretBuild extends PowerTurretBuild{ diff --git a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java index 2710d0248b..25725cd0a9 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java @@ -8,6 +8,7 @@ import mindustry.entities.bullet.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; +import mindustry.world.*; import mindustry.world.consumers.*; import mindustry.world.meta.*; import mindustry.world.meta.values.*; @@ -35,7 +36,11 @@ public class LiquidTurret extends Turret{ public void setStats(){ super.setStats(); - stats.add(BlockStat.ammo, new AmmoListValue<>(ammoTypes)); + stats.add(Stat.ammo, new AmmoListValue<>(ammoTypes)); + } + + @Override + public void init(){ consumes.add(new ConsumeLiquidFilter(i -> ammoTypes.containsKey(i), 1f){ @Override public boolean valid(Building entity){ @@ -48,10 +53,12 @@ public class LiquidTurret extends Turret{ } @Override - public void display(BlockStats stats){ + public void display(Stats stats){ } }); + + super.init(); } public class LiquidTurretBuild extends TurretBuild{ @@ -83,7 +90,9 @@ public class LiquidTurret extends Turret{ int tr = (int)(range / tilesize); for(int x = -tr; x <= tr; x++){ for(int y = -tr; y <= tr; y++){ - if(Fires.has(x + tile.x, y + tile.y)){ + Tile other = world.tileWorld(x + tile.x, y + tile.y); + //do not extinguish fires on other team blocks + if(other != null && Fires.has(x + tile.x, y + tile.y) && (other.build == null || other.team() == team)){ target = Fires.get(x + tile.x, y + tile.y); return; } @@ -133,7 +142,7 @@ public class LiquidTurret extends Turret{ } @Override - public boolean acceptLiquid(Building source, Liquid liquid, float amount){ + public boolean acceptLiquid(Building source, Liquid liquid){ return ammoTypes.get(liquid) != null && (liquids.current() == liquid || (ammoTypes.containsKey(liquids.current()) && liquids.get(liquids.current()) <= 1f / ammoTypes.get(liquids.current()).ammoMultiplier + 0.001f)); diff --git a/core/src/mindustry/world/blocks/defense/PointDefenseTurret.java b/core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java similarity index 76% rename from core/src/mindustry/world/blocks/defense/PointDefenseTurret.java rename to core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java index 06746bcfaa..0184f9ff7a 100644 --- a/core/src/mindustry/world/blocks/defense/PointDefenseTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java @@ -1,4 +1,4 @@ -package mindustry.world.blocks.defense; +package mindustry.world.blocks.defense.turrets; import arc.graphics.*; import arc.graphics.g2d.*; @@ -11,12 +11,9 @@ import mindustry.content.*; import mindustry.entities.*; import mindustry.gen.*; import mindustry.graphics.*; -import mindustry.world.*; import mindustry.world.meta.*; -import static mindustry.Vars.*; - -public class PointDefenseTurret extends Block{ +public class PointDefenseTurret extends ReloadTurret{ public final int timerTarget = timers++; public float retargetTime = 5f; @@ -27,9 +24,6 @@ public class PointDefenseTurret extends Block{ public Effect hitEffect = Fx.pointHit; public Effect shootEffect = Fx.sparkShoot; - public float range = 80f; - public float reloadTime = 30f; - public float rotateSpeed = 20; public float shootCone = 5f; public float bulletDamage = 10f; public float shootLength = 3f; @@ -37,13 +31,12 @@ public class PointDefenseTurret extends Block{ public PointDefenseTurret(String name){ super(name); - outlineIcon = true; - update = true; - } + rotateSpeed = 20f; + reloadTime = 30f; - @Override - public void drawPlace(int x, int y, int rotation, boolean valid){ - Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent); + coolantMultiplier = 2f; + //disabled due to version mismatch problems + acceptCoolant = false; } @Override @@ -55,12 +48,10 @@ public class PointDefenseTurret extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks); - stats.add(BlockStat.reload, 60f / reloadTime, StatUnit.none); + stats.add(Stat.reload, 60f / reloadTime, StatUnit.none); } - public class PointDefenseBuild extends Building{ - public float rotation = 90, reload; + public class PointDefenseBuild extends ReloadTurretBuild{ public @Nullable Bullet target; @Override @@ -76,14 +67,18 @@ public class PointDefenseTurret extends Block{ target = null; } + if(acceptCoolant){ + updateCooling(); + } + //look at target if(target != null && target.within(this, range) && target.team != team && target.type() != null && target.type().hittable){ float dest = angleTo(target); rotation = Angles.moveToward(rotation, dest, rotateSpeed * edelta()); - reload -= edelta(); + reload += edelta(); //shoot when possible - if(Angles.within(rotation, dest, shootCone) && reload <= 0f){ + if(Angles.within(rotation, dest, shootCone) && reload >= reloadTime){ if(target.damage() > bulletDamage){ target.damage(target.damage() - bulletDamage); }else{ @@ -95,18 +90,13 @@ public class PointDefenseTurret extends Block{ beamEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, color, new Vec2().set(target)); shootEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, color); hitEffect.at(target.x, target.y, color); - reload = reloadTime; + reload = 0; } }else{ target = null; } } - @Override - public void drawSelect(){ - Drawf.dashCircle(x, y, range, Pal.accent); - } - @Override public void draw(){ Draw.rect(baseRegion, x, y); diff --git a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java index 9647c25bfc..bf365f4439 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java @@ -1,6 +1,7 @@ package mindustry.world.blocks.defense.turrets; import mindustry.entities.bullet.*; +import mindustry.logic.*; import mindustry.world.meta.*; public class PowerTurret extends Turret{ @@ -15,12 +16,12 @@ public class PowerTurret extends Turret{ @Override public void setStats(){ super.setStats(); - stats.add(BlockStat.damage, shootType.damage, StatUnit.none); + stats.add(Stat.damage, shootType.damage, StatUnit.none); } @Override public void init(){ - consumes.powerCond(powerUse, (TurretBuild entity) -> entity.target != null || (entity.logicControlled() && entity.logicShooting)); + consumes.powerCond(powerUse, TurretBuild::isActive); super.init(); } @@ -33,6 +34,15 @@ public class PowerTurret extends Turret{ super.updateTile(); } + @Override + public double sense(LAccess sensor){ + return switch(sensor){ + case ammo -> power.status; + case ammoCapacity -> 1; + default -> super.sense(sensor); + }; + } + @Override public BulletType useAmmo(){ //nothing used directly diff --git a/core/src/mindustry/world/blocks/defense/turrets/ReloadTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ReloadTurret.java new file mode 100644 index 0000000000..33538771a1 --- /dev/null +++ b/core/src/mindustry/world/blocks/defense/turrets/ReloadTurret.java @@ -0,0 +1,49 @@ +package mindustry.world.blocks.defense.turrets; + +import arc.math.*; +import arc.util.*; +import mindustry.type.*; +import mindustry.world.consumers.*; +import mindustry.world.meta.*; +import mindustry.world.meta.values.*; + +import static mindustry.Vars.*; + +public abstract class ReloadTurret extends BaseTurret{ + public float reloadTime = 10f; + + public ReloadTurret(String name){ + super(name); + } + + @Override + public void setStats(){ + super.setStats(); + + if(acceptCoolant){ + stats.add(Stat.booster, new BoosterListValue(reloadTime, consumes.get(ConsumeType.liquid).amount, coolantMultiplier, true, l -> consumes.liquidfilters.get(l.id))); + } + } + + public class ReloadTurretBuild extends BaseTurretBuild{ + public float reload; + + protected void updateCooling(){ + float maxUsed = consumes.get(ConsumeType.liquid).amount; + + Liquid liquid = liquids.current(); + + float used = Math.min(Math.min(liquids.get(liquid), maxUsed * Time.delta), Math.max(0, ((reloadTime - reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed(); + reload += used * liquid.heatCapacity * coolantMultiplier; + liquids.remove(liquid, used); + + if(Mathf.chance(0.06 * used)){ + coolEffect.at(x + Mathf.range(size * tilesize / 2f), y + Mathf.range(size * tilesize / 2f)); + } + } + + protected float baseReloadSpeed(){ + return efficiency(); + } + } +} diff --git a/core/src/mindustry/world/blocks/defense/TractorBeamTurret.java b/core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java similarity index 70% rename from core/src/mindustry/world/blocks/defense/TractorBeamTurret.java rename to core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java index 1f74360ed5..debe26f7e6 100644 --- a/core/src/mindustry/world/blocks/defense/TractorBeamTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java @@ -1,4 +1,4 @@ -package mindustry.world.blocks.defense; +package mindustry.world.blocks.defense.turrets; import arc.graphics.*; import arc.graphics.g2d.*; @@ -9,12 +9,13 @@ import mindustry.annotations.Annotations.*; import mindustry.entities.*; import mindustry.gen.*; import mindustry.graphics.*; -import mindustry.world.*; +import mindustry.type.*; +import mindustry.world.consumers.*; import mindustry.world.meta.*; import static mindustry.Vars.*; -public class TractorBeamTurret extends Block{ +public class TractorBeamTurret extends BaseTurret{ public final int timerTarget = timers++; public float retargetTime = 5f; @@ -22,8 +23,6 @@ public class TractorBeamTurret extends Block{ public @Load("@-laser") TextureRegion laser; public @Load("@-laser-end") TextureRegion laserEnd; - public float range = 80f; - public float rotateSpeed = 10; public float shootCone = 6f; public float laserWidth = 0.6f; public float force = 0.3f; @@ -35,14 +34,11 @@ public class TractorBeamTurret extends Block{ public TractorBeamTurret(String name){ super(name); - update = true; - solid = true; - outlineIcon = true; - } + rotateSpeed = 10f; + coolantMultiplier = 1f; - @Override - public void drawPlace(int x, int y, int rotation, boolean valid){ - Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent); + //disabled due to version mismatch problems + acceptCoolant = false; } @Override @@ -54,17 +50,16 @@ public class TractorBeamTurret extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks); - stats.add(BlockStat.targetsAir, targetAir); - stats.add(BlockStat.targetsGround, targetGround); - stats.add(BlockStat.damage, damage * 60f, StatUnit.perSecond); + stats.add(Stat.targetsAir, targetAir); + stats.add(Stat.targetsGround, targetGround); + stats.add(Stat.damage, damage * 60f, StatUnit.perSecond); } - public class TractorBeamBuild extends Building{ - public float rotation = 90; + public class TractorBeamBuild extends BaseTurretBuild{ public @Nullable Unit target; public float lastX, lastY, strength; public boolean any; + public float coolant = 1f; @Override public void updateTile(){ @@ -74,8 +69,25 @@ public class TractorBeamTurret extends Block{ target = Units.closestEnemy(team, x, y, range, u -> u.checkTarget(targetAir, targetGround)); } + //consume coolant + if(target != null && acceptCoolant){ + float maxUsed = consumes.get(ConsumeType.liquid).amount; + + Liquid liquid = liquids.current(); + + float used = Math.min(Math.min(liquids.get(liquid), maxUsed * Time.delta), Math.max(0, (1f / coolantMultiplier) / liquid.heatCapacity)); + + liquids.remove(liquid, used); + + if(Mathf.chance(0.06 * used)){ + coolEffect.at(x + Mathf.range(size * tilesize / 2f), y + Mathf.range(size * tilesize / 2f)); + } + + coolant = 1f + (used * liquid.heatCapacity * coolantMultiplier); + } + //look at target - if(target != null && target.within(this, range) && target.team() != team && target.type().flying && efficiency() > 0.01f){ + if(target != null && target.within(this, range) && target.team() != team && target.type.flying && efficiency() > 0.01f){ any = true; float dest = angleTo(target); rotation = Angles.moveToward(rotation, dest, rotateSpeed * edelta()); @@ -98,8 +110,8 @@ public class TractorBeamTurret extends Block{ } @Override - public void drawSelect(){ - Drawf.dashCircle(x, y, range, Pal.accent); + public float efficiency() { + return super.efficiency() * coolant; } @Override diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 766de0045c..58abb26b12 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -12,6 +12,7 @@ import arc.util.*; import arc.util.io.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; +import mindustry.core.*; import mindustry.entities.*; import mindustry.entities.Units.*; import mindustry.entities.bullet.*; @@ -20,15 +21,13 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.logic.*; import mindustry.type.*; -import mindustry.world.*; import mindustry.world.blocks.*; import mindustry.world.consumers.*; import mindustry.world.meta.*; -import mindustry.world.meta.values.*; import static mindustry.Vars.*; -public abstract class Turret extends Block{ +public abstract class Turret extends ReloadTurret{ //after being logic-controlled and this amount of time passes, the turret will resume normal AI public final static float logicControlCooldown = 60 * 2; @@ -41,10 +40,9 @@ public abstract class Turret extends Block{ public Effect ammoUseEffect = Fx.none; public Sound shootSound = Sounds.shoot; + public int maxAmmo = 30; public int ammoPerShot = 1; public float ammoEjectBack = 1f; - public float range = 50f; - public float reloadTime = 10f; public float inaccuracy = 0f; public float velocityInaccuracy = 0f; public int shots = 1; @@ -52,7 +50,6 @@ public abstract class Turret extends Block{ public float recoilAmount = 1f; public float restitution = 0.02f; public float cooldown = 0.02f; - public float rotateSpeed = 5f; //in degrees per tick public float shootCone = 8f; public float shootShake = 0f; public float xRand = 0f; @@ -62,11 +59,7 @@ public abstract class Turret extends Block{ public boolean alternate = false; public boolean targetAir = true; public boolean targetGround = true; - public boolean acceptCoolant = true; - /** How much reload is lowered by for each unit of liquid of heat capacity. */ - public float coolantMultiplier = 5f; - /** Effect displayed when coolant is used. */ - public Effect coolEffect = Fx.fuelburn; + public Sortf unitSort = Unit::dst2; protected Vec2 tr = new Vec2(); @@ -106,15 +99,10 @@ public abstract class Turret extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks); - stats.add(BlockStat.inaccuracy, (int)inaccuracy, StatUnit.degrees); - stats.add(BlockStat.reload, 60f / reloadTime * shots, StatUnit.none); - stats.add(BlockStat.targetsAir, targetAir); - stats.add(BlockStat.targetsGround, targetGround); - - if(acceptCoolant){ - stats.add(BlockStat.booster, new BoosterListValue(reloadTime, consumes.get(ConsumeType.liquid).amount, coolantMultiplier, true, l -> consumes.liquidfilters.get(l.id))); - } + stats.add(Stat.inaccuracy, (int)inaccuracy, StatUnit.degrees); + stats.add(Stat.reload, 60f / reloadTime * shots, StatUnit.none); + stats.add(Stat.targetsAir, targetAir); + stats.add(Stat.targetsGround, targetGround); } @Override @@ -132,32 +120,22 @@ public abstract class Turret extends Block{ return new TextureRegion[]{baseRegion, region}; } - @Override - public void drawPlace(int x, int y, int rotation, boolean valid){ - Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.placing); - } - public static abstract class AmmoEntry{ public int amount; public abstract BulletType type(); } - public class TurretBuild extends Building implements ControlBlock, Ranged{ + public class TurretBuild extends ReloadTurretBuild implements ControlBlock{ public Seq ammo = new Seq<>(); public int totalAmmo; - public float reload, rotation = 90, recoil, heat, logicControlTime = -1; + public float recoil, heat, logicControlTime = -1; public int shotCounter; public boolean logicShooting = false; public @Nullable Posc target; public Vec2 targetPos = new Vec2(); public BlockUnitc unit = Nulls.blockUnit; - @Override - public float range(){ - return range; - } - @Override public void created(){ unit = (BlockUnitc)UnitTypes.block.create(team); @@ -167,7 +145,7 @@ public abstract class Turret extends Block{ @Override public void control(LAccess type, double p1, double p2, double p3, double p4){ if(type == LAccess.shoot && !unit.isPlayer()){ - targetPos.set((float)p1, (float)p2); + targetPos.set(World.unconv((float)p1), World.unconv((float)p2)); logicControlTime = logicControlCooldown; logicShooting = !Mathf.zero(p3); } @@ -175,12 +153,28 @@ public abstract class Turret extends Block{ super.control(type, p1, p2, p3, p4); } + @Override + public void control(LAccess type, Object p1, double p2, double p3, double p4){ + if(type == LAccess.shootp && !unit.isPlayer()){ + logicControlTime = logicControlCooldown; + logicShooting = !Mathf.zero(p2); + + if(p1 instanceof Posc){ + targetPosition((Posc)p1); + } + } + + super.control(type, p1, p2, p3, p4); + } + @Override public double sense(LAccess sensor){ return switch(sensor){ + case ammo -> totalAmmo; + case ammoCapacity -> maxAmmo; case rotation -> rotation; - case shootX -> targetPos.x; - case shootY -> targetPos.y; + case shootX -> World.conv(targetPos.x); + case shootY -> World.conv(targetPos.y); case shooting -> (isControlled() ? unit.isShooting() : logicControlled() ? logicShooting : validateTarget()) ? 1 : 0; default -> super.sense(sensor); }; @@ -195,6 +189,23 @@ public abstract class Turret extends Block{ return logicControlTime > 0; } + public boolean isActive(){ + return target != null || (logicControlled() && logicShooting) || (isControlled() && unit.isShooting()); + } + + public void targetPosition(Posc pos){ + if(!hasAmmo()) return; + BulletType bullet = peekAmmo(); + float speed = bullet.speed; + //slow bullets never intersect + if(speed < 0.1f) speed = 9999999f; + + targetPos.set(Predict.intercept(this, pos, speed)); + if(targetPos.isZero()){ + targetPos.set(target); + } + } + @Override public void draw(){ Draw.rect(baseRegion, x, y); @@ -242,15 +253,7 @@ public abstract class Turret extends Block{ }else if(logicControlled()){ //logic behavior canShoot = logicShooting; }else{ //default AI behavior - BulletType type = peekAmmo(); - float speed = type.speed; - //slow bullets never intersect - if(speed < 0.1f) speed = 9999999f; - - targetPos.set(Predict.intercept(this, target, speed)); - if(targetPos.isZero()){ - targetPos.set(target); - } + targetPosition(target); if(Float.isNaN(rotation)){ rotation = 0; @@ -274,11 +277,6 @@ public abstract class Turret extends Block{ } } - @Override - public void drawSelect(){ - Drawf.dashCircle(x, y, range, team.color); - } - @Override public void handleLiquid(Building source, Liquid liquid, float amount){ if(acceptCoolant && liquids.currentAmount() <= 0.001f){ @@ -288,20 +286,6 @@ public abstract class Turret extends Block{ super.handleLiquid(source, liquid, amount); } - protected void updateCooling(){ - float maxUsed = consumes.get(ConsumeType.liquid).amount; - - Liquid liquid = liquids.current(); - - float used = Math.min(Math.min(liquids.get(liquid), maxUsed * Time.delta), Math.max(0, ((reloadTime - reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed(); - reload += used * liquid.heatCapacity * coolantMultiplier; - liquids.remove(liquid, used); - - if(Mathf.chance(0.06 * used)){ - coolEffect.at(x + Mathf.range(size * tilesize / 2f), y + Mathf.range(size * tilesize / 2f)); - } - } - protected boolean validateTarget(){ return !Units.invalidateTarget(target, team, x, y) || isControlled() || logicControlled(); } @@ -328,8 +312,9 @@ public abstract class Turret extends Block{ AmmoEntry entry = ammo.peek(); entry.amount -= ammoPerShot; - if(entry.amount == 0) ammo.pop(); + if(entry.amount <= 0) ammo.pop(); totalAmmo -= ammoPerShot; + totalAmmo = Math.max(totalAmmo, 0); Time.run(reloadTime / 2f, this::ejectEffects); return entry.type(); } @@ -341,7 +326,7 @@ public abstract class Turret extends Block{ /** @return whether the turret has ammo. */ public boolean hasAmmo(){ - return ammo.size > 0 && ammo.peek().amount >= ammoPerShot; + return ammo.size > 0 && ammo.peek().amount >= 1; } protected void updateShooting(){ @@ -410,7 +395,7 @@ public abstract class Turret extends Block{ fshootEffect.at(x + tr.x, y + tr.y, rotation); fsmokeEffect.at(x + tr.x, y + tr.y, rotation); - shootSound.at(tile, Mathf.random(0.9f, 1.1f)); + shootSound.at(x + tr.x, y + tr.y, Mathf.random(0.9f, 1.1f)); if(shootShake > 0){ Effect.shake(shootShake, shootShake, this); @@ -425,10 +410,6 @@ public abstract class Turret extends Block{ ammoUseEffect.at(x - Angles.trnsx(rotation, ammoEjectBack), y - Angles.trnsy(rotation, ammoEjectBack), rotation); } - protected float baseReloadSpeed(){ - return efficiency(); - } - @Override public void write(Writes write){ super.write(write); diff --git a/core/src/mindustry/world/blocks/distribution/Conveyor.java b/core/src/mindustry/world/blocks/distribution/Conveyor.java index 033f1eb8d5..b7d973cfe7 100644 --- a/core/src/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/mindustry/world/blocks/distribution/Conveyor.java @@ -52,7 +52,7 @@ public class Conveyor extends Block implements Autotiler{ super.setStats(); //have to add a custom calculated speed, since the actual movement speed is apparently not linear - stats.add(BlockStat.itemsMoved, displayedSpeed, StatUnit.itemsSecond); + stats.add(Stat.itemsMoved, displayedSpeed, StatUnit.itemsSecond); } @Override @@ -67,7 +67,7 @@ public class Conveyor extends Block implements Autotiler{ @Override public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){ - return (otherblock.outputsItems() || lookingAt(tile, rotation, otherx, othery, otherblock)) + return (otherblock.outputsItems() || (lookingAt(tile, rotation, otherx, othery, otherblock) && otherblock.hasItems)) && lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock); } @@ -156,6 +156,7 @@ public class Conveyor extends Block implements Autotiler{ lastInserted = build.lastInserted; mid = build.mid; minitem = build.minitem; + items.add(build.items); } } @@ -182,7 +183,7 @@ public class Conveyor extends Block implements Autotiler{ @Override public void unitOn(Unit unit){ - if(clogHeat > 0.5f) return; + if(clogHeat > 0.5f || !enabled) return; noSleep(); diff --git a/core/src/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/mindustry/world/blocks/distribution/ItemBridge.java index da162d9398..6e310d0e55 100644 --- a/core/src/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/mindustry/world/blocks/distribution/ItemBridge.java @@ -202,7 +202,7 @@ public class ItemBridge extends Block{ for(int i = 1; i <= range; i++){ for(int j = 0; j < 4; j++){ - Tile other = tile.getNearby(Geometry.d4[j].x * i, Geometry.d4[j].y * i); + Tile other = tile.nearby(Geometry.d4[j].x * i, Geometry.d4[j].y * i); if(linkValid(tile, other)){ boolean linked = other.pos() == link; @@ -336,16 +336,18 @@ public class ItemBridge extends Block{ Tile other = world.tile(link); + if(items.total() >= itemCapacity) return false; + + if(linked(source)) return true; + if(linkValid(tile, other)){ int rel = relativeTo(other); int rel2 = relativeTo(Edges.getFacingEdge(source, this)); - if(rel == rel2) return false; - }else{ - return linked(source) && items.total() < itemCapacity; + return rel != rel2; } - return items.total() < itemCapacity; + return false; } @Override @@ -354,21 +356,23 @@ public class ItemBridge extends Block{ } @Override - public boolean acceptLiquid(Building source, Liquid liquid, float amount){ + public boolean acceptLiquid(Building source, Liquid liquid){ if(team != source.team || !hasLiquids) return false; Tile other = world.tile(link); + if(!(liquids.current() == liquid || liquids.get(liquids.current()) < 0.2f)) return false; + + if(linked(source)) return true; + if(linkValid(tile, other)){ int rel = relativeTo(other.x, other.y); int rel2 = relativeTo(Edges.getFacingEdge(source, this)); - if(rel == rel2) return false; - }else if(!(linked(source))){ - return false; + return rel != rel2; } - return liquids.get(liquid) + amount < liquidCapacity && (liquids.current() == liquid || liquids.get(liquids.current()) < 0.2f); + return false; } protected boolean linked(Building source){ diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java index 115d365a88..9191e7dfe1 100644 --- a/core/src/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java @@ -105,6 +105,10 @@ public class MassDriver extends Block{ Building link = world.build(this.link); boolean hasLink = linkValid(); + if(hasLink){ + this.link = link.pos(); + } + //reload regardless of state if(reload > 0f){ reload = Mathf.clamp(reload - edelta() / reloadTime); @@ -210,9 +214,9 @@ public class MassDriver extends Block{ } if(linkValid()){ - Tile target = world.tile(link); - Drawf.circles(target.drawx(), target.drawy(), (target.block().size / 2f + 1) * tilesize + sin - 2f, Pal.place); - Drawf.arrow(x, y, target.drawx(), target.drawy(), size * tilesize + sin, 4f + sin); + Building target = world.build(link); + Drawf.circles(target.x, target.y, (target.block().size / 2f + 1) * tilesize + sin - 2f, Pal.place); + Drawf.arrow(x, y, target.x, target.y, size * tilesize + sin, 4f + sin); } Drawf.dashCircle(x, y, range, Pal.accent); @@ -305,8 +309,8 @@ public class MassDriver extends Block{ protected boolean linkValid(){ if(link == -1) return false; - Tile link = world.tile(this.link); - return link != null && link.block() instanceof MassDriver && link.team() == tile.team() && tile.dst(link) <= range; + Building link = world.build(this.link); + return link instanceof MassDriverBuild && link.team == team && within(link, range); } @Override diff --git a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java index 7c0bbb7821..08035d9c84 100644 --- a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java @@ -87,7 +87,7 @@ public class PayloadConveyor extends Block{ } int ntrns = 1 + size/2; - Tile next = tile.getNearby(Geometry.d4(rotation).x * ntrns, Geometry.d4(rotation).y * ntrns); + Tile next = tile.nearby(Geometry.d4(rotation).x * ntrns, Geometry.d4(rotation).y * ntrns); blocked = (next != null && next.solid() && !next.block().outputsPayload) || (this.next != null && (this.next.rotation + 2)%4 == rotation); } diff --git a/core/src/mindustry/world/blocks/distribution/Router.java b/core/src/mindustry/world/blocks/distribution/Router.java index cb0ae9807d..766a1bafff 100644 --- a/core/src/mindustry/world/blocks/distribution/Router.java +++ b/core/src/mindustry/world/blocks/distribution/Router.java @@ -1,9 +1,12 @@ package mindustry.world.blocks.distribution; +import arc.math.*; +import arc.util.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.*; import mindustry.world.meta.*; public class Router extends Block{ @@ -20,15 +23,35 @@ public class Router extends Block{ noUpdateDisabled = true; } - public class RouterBuild extends Building{ + public class RouterBuild extends Building implements ControlBlock{ public Item lastItem; public Tile lastInput; public float time; + public @Nullable BlockUnitc unit; + + @Override + public Unit unit(){ + if(unit == null){ + unit = (BlockUnitc)UnitTypes.block.create(team); + unit.tile(this); + } + return (Unit)unit; + } + + @Override + public boolean canControl(){ + return size == 1; + } + + @Override + public boolean shouldAutoTarget(){ + return false; + } @Override public void updateTile(){ if(lastItem == null && items.any()){ - items.clear(); + lastItem = items.first(); } if(lastItem != null){ @@ -72,6 +95,23 @@ public class Router extends Block{ } public Building getTileTarget(Item item, Tile from, boolean set){ + if(unit != null && isControlled()){ + unit.health(health); + unit.ammo(unit.type().ammoCapacity * (items.total() > 0 ? 1f : 0f)); + unit.team(team); + + int angle = Mathf.mod((int)((angleTo(unit.aimX(), unit.aimY()) + 45) / 90), 4); + + if(unit.isShooting()){ + Building other = nearby(angle); + if(other != null && other.acceptItem(this, item)){ + return other; + } + } + + return null; + } + int counter = rotation; for(int i = 0; i < proximity.size; i++){ Building other = proximity.get((i + counter) % proximity.size); diff --git a/core/src/mindustry/world/blocks/distribution/StackConveyor.java b/core/src/mindustry/world/blocks/distribution/StackConveyor.java index ce77b978df..f3c400ad9b 100644 --- a/core/src/mindustry/world/blocks/distribution/StackConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/StackConveyor.java @@ -53,7 +53,7 @@ public class StackConveyor extends Block implements Autotiler{ public void setStats(){ super.setStats(); - stats.add(BlockStat.itemsMoved, Mathf.round(itemCapacity * speed * 60), StatUnit.itemsSecond); + stats.add(Stat.itemsMoved, Mathf.round(itemCapacity * speed * 60), StatUnit.itemsSecond); } @Override @@ -200,14 +200,10 @@ public class StackConveyor extends Block implements Autotiler{ } }else{ //transfer if(state != stateLoad || (items.total() >= getMaximumAccepted(lastItem))){ - if(front() != null - && front().team == team - && front().block instanceof StackConveyor){ - StackConveyorBuild e = (StackConveyorBuild)front(); - + if(front() instanceof StackConveyorBuild e && e.team == team){ // sleep if its occupied if(e.link == -1){ - e.items.addAll(items); + e.items.add(items); e.lastItem = lastItem; e.link = tile.pos(); // ▲ to | from ▼ @@ -227,7 +223,7 @@ public class StackConveyor extends Block implements Autotiler{ if(builds.first() instanceof ConveyorBuild build){ Item item = build.items.first(); if(item != null){ - handleStack(item, build.items.get(itemCapacity), null); + handleStack(item, build.items.get(item), null); } } } diff --git a/core/src/mindustry/world/blocks/environment/Cliff.java b/core/src/mindustry/world/blocks/environment/Cliff.java index d4347a7c97..49dba95d7c 100644 --- a/core/src/mindustry/world/blocks/environment/Cliff.java +++ b/core/src/mindustry/world/blocks/environment/Cliff.java @@ -2,11 +2,13 @@ package mindustry.world.blocks.environment; import arc.graphics.g2d.*; import arc.util.*; +import mindustry.annotations.Annotations.*; import mindustry.graphics.*; import mindustry.world.*; public class Cliff extends Block{ public float size = 11f; + public @Load(value = "cliffmask#", length = 256) TextureRegion[] cliffs; public Cliff(String name){ super(name); @@ -19,15 +21,8 @@ public class Cliff extends Block{ @Override public void drawBase(Tile tile){ - - int r = tile.data; - for(int i = 0; i < 8; i++){ - if((r & (1 << i)) != 0){ - Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.3f + (i >= 4 ? -0.4f : 0.3f))); - Draw.rect(region, tile.worldx(), tile.worldy(), size, size, i * 45f); - } - } - + Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.6f)); + Draw.rect(cliffs[tile.data & 0xff], tile.worldx(), tile.worldy()); Draw.color(); } diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index a62542f5da..113617cc63 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -64,6 +64,8 @@ public class Floor extends Block{ public Block wall = Blocks.air; /** Decoration block. Usually a rock. May be air. */ public Block decoration = Blocks.air; + /** Whether this overlay needs a surface to be on. False for floating blocks, like spawns. */ + public boolean needsSurface = true; protected TextureRegion[][] edges; protected Seq blenders = new Seq<>(); @@ -166,6 +168,11 @@ public class Floor extends Block{ return new TextureRegion[]{Core.atlas.find(Core.atlas.has(name) ? name : name + "1")}; } + /** @return whether this floor has a valid surface on which to place things, e.g. scorch marks. */ + public boolean hasSurface(){ + return !isLiquid && !solid; + } + public boolean isDeep(){ return drownTime > 0; } @@ -178,7 +185,7 @@ public class Floor extends Block{ for(int i = 0; i < 8; i++){ Point2 point = Geometry.d8[i]; - Tile other = tile.getNearby(point); + Tile other = tile.nearby(point); if(other != null && other.floor().cacheLayer == layer && other.floor().edges() != null){ if(!blended.getAndSet(other.floor().id)){ blenders.add(other.floor()); @@ -195,7 +202,7 @@ public class Floor extends Block{ for(int i = 0; i < 8; i++){ Point2 point = Geometry.d8[i]; - Tile other = tile.getNearby(point); + Tile other = tile.nearby(point); if(other != null && doEdge(other.floor()) && other.floor().cacheLayer == cacheLayer && other.floor().edges() != null){ if(!blended.getAndSet(other.floor().id)){ blenders.add(other.floor()); @@ -212,7 +219,7 @@ public class Floor extends Block{ for(Block block : blenders){ for(int i = 0; i < 8; i++){ Point2 point = Geometry.d8[i]; - Tile other = tile.getNearby(point); + Tile other = tile.nearby(point); if(other != null && other.floor() == block){ TextureRegion region = edge((Floor)block, 1 - point.x, 1 - point.y); Draw.rect(region, tile.worldx(), tile.worldy()); @@ -224,7 +231,7 @@ public class Floor extends Block{ //'new' style of edges with shadows instead of colors, not used currently protected void drawEdgesFlat(Tile tile, boolean sameLayer){ for(int i = 0; i < 4; i++){ - Tile other = tile.getNearby(i); + Tile other = tile.nearby(i); if(other != null && doEdge(other.floor())){ Color color = other.floor().mapColor; Draw.color(color.r, color.g, color.b, 1f); diff --git a/core/src/mindustry/world/blocks/environment/OreBlock.java b/core/src/mindustry/world/blocks/environment/OreBlock.java index 943d91076d..c08a3eccce 100644 --- a/core/src/mindustry/world/blocks/environment/OreBlock.java +++ b/core/src/mindustry/world/blocks/environment/OreBlock.java @@ -20,6 +20,7 @@ public class OreBlock extends OverlayFloor{ this.itemDrop = ore; this.variants = 3; this.mapColor.set(ore.color); + this.useColor = true; } /** For mod use only!*/ diff --git a/core/src/mindustry/world/blocks/environment/OverlayFloor.java b/core/src/mindustry/world/blocks/environment/OverlayFloor.java index f7a92ceeb3..4c57943aed 100644 --- a/core/src/mindustry/world/blocks/environment/OverlayFloor.java +++ b/core/src/mindustry/world/blocks/environment/OverlayFloor.java @@ -9,6 +9,7 @@ public class OverlayFloor extends Floor{ public OverlayFloor(String name){ super(name); + useColor = false; } @Override diff --git a/core/src/mindustry/world/blocks/environment/StaticTree.java b/core/src/mindustry/world/blocks/environment/StaticTree.java index 78c6133d2f..9b1a7063f4 100644 --- a/core/src/mindustry/world/blocks/environment/StaticTree.java +++ b/core/src/mindustry/world/blocks/environment/StaticTree.java @@ -21,7 +21,7 @@ public class StaticTree extends StaticWall{ float oy = 0; for(int i = 0; i < 4; i++){ - if(tile.getNearby(i) != null && tile.getNearby(i).block() instanceof StaticWall){ + if(tile.nearby(i) != null && tile.nearby(i).block() instanceof StaticWall){ if(i == 0){ r.setWidth(r.width - crop); diff --git a/core/src/mindustry/world/blocks/experimental/BlockForge.java b/core/src/mindustry/world/blocks/experimental/BlockForge.java index 065cd66e05..251c6820a0 100644 --- a/core/src/mindustry/world/blocks/experimental/BlockForge.java +++ b/core/src/mindustry/world/blocks/experimental/BlockForge.java @@ -50,7 +50,7 @@ public class BlockForge extends PayloadAcceptor{ Draw.rect(outRegion, req.drawx(), req.drawy(), req.rotation * 90); } - public class BlockForgeBuild extends PayloadAcceptorBuild{ + public class BlockForgeBuild extends PayloadAcceptorBuild{ public @Nullable Block recipe; public float progress, time, heat; @@ -82,7 +82,7 @@ public class BlockForge extends PayloadAcceptor{ if(progress >= recipe.buildCost){ consume(); - payload = new BlockPayload(recipe, team); + payload = new BuildPayload(recipe, team); progress = 0f; } }else{ @@ -99,7 +99,7 @@ public class BlockForge extends PayloadAcceptor{ public void buildConfiguration(Table table){ Seq blocks = Vars.content.blocks().select(b -> b.isVisible() && b.size <= 2); - ItemSelection.buildTable(table, blocks, () -> recipe, block -> recipe = block); + ItemSelection.buildTable(table, blocks, () -> recipe, this::configure); } @Override diff --git a/core/src/mindustry/world/blocks/experimental/BlockLoader.java b/core/src/mindustry/world/blocks/experimental/BlockLoader.java index 886ca54421..3e015ec9a6 100644 --- a/core/src/mindustry/world/blocks/experimental/BlockLoader.java +++ b/core/src/mindustry/world/blocks/experimental/BlockLoader.java @@ -50,13 +50,13 @@ public class BlockLoader extends PayloadAcceptor{ Draw.rect(topRegion, req.drawx(), req.drawy()); } - public class BlockLoaderBuild extends PayloadAcceptorBuild{ + public class BlockLoaderBuild extends PayloadAcceptorBuild{ @Override public boolean acceptPayload(Building source, Payload payload){ return super.acceptPayload(source, payload) && - (payload instanceof BlockPayload) && - ((((BlockPayload)payload).entity.block.hasItems && ((BlockPayload)payload).block().unloadable && ((BlockPayload)payload).block().itemCapacity >= 10)/* || + (payload instanceof BuildPayload) && + ((((BuildPayload)payload).build.block.hasItems && ((BuildPayload)payload).block().unloadable && ((BuildPayload)payload).block().itemCapacity >= 10)/* || ((BlockPayload)payload).entity.block().hasLiquids && ((BlockPayload)payload).block().liquidCapacity >= 10f)*/); } @@ -101,8 +101,8 @@ public class BlockLoader extends PayloadAcceptor{ for(int i = 0; i < items.length(); i++){ if(items.get(i) > 0){ Item item = content.item(i); - if(payload.entity.acceptItem(payload.entity, item)){ - payload.entity.handleItem(payload.entity, item); + if(payload.build.acceptItem(payload.build, item)){ + payload.build.handleItem(payload.build, item); items.remove(item, 1); break; } @@ -127,13 +127,13 @@ public class BlockLoader extends PayloadAcceptor{ } public float fraction(){ - return payload == null ? 0f : payload.entity.items.total() / (float)payload.entity.block.itemCapacity; + return payload == null ? 0f : payload.build.items.total() / (float)payload.build.block.itemCapacity; } public boolean shouldExport(){ return payload != null && - ((payload.block().hasLiquids && payload.entity.liquids.total() >= payload.block().liquidCapacity - 0.001f) || - (payload.block().hasItems && payload.entity.items.total() >= payload.block().itemCapacity)); + ((payload.block().hasLiquids && payload.build.liquids.total() >= payload.block().liquidCapacity - 0.001f) || + (payload.block().hasItems && payload.build.items.total() >= payload.block().itemCapacity)); } } } diff --git a/core/src/mindustry/world/blocks/experimental/BlockUnloader.java b/core/src/mindustry/world/blocks/experimental/BlockUnloader.java index a3ce1a60f5..10c542deee 100644 --- a/core/src/mindustry/world/blocks/experimental/BlockUnloader.java +++ b/core/src/mindustry/world/blocks/experimental/BlockUnloader.java @@ -35,9 +35,9 @@ public class BlockUnloader extends BlockLoader{ //load up items a set amount of times for(int j = 0; j < itemsLoaded && !full(); j++){ for(int i = 0; i < items.length(); i++){ - if(payload.entity.items.get(i) > 0){ + if(payload.build.items.get(i) > 0){ Item item = content.item(i); - payload.entity.items.remove(item, 1); + payload.build.items.remove(item, 1); items.add(item, 1); break; } @@ -56,12 +56,12 @@ public class BlockUnloader extends BlockLoader{ @Override public float fraction(){ - return payload == null ? 0f : 1f - payload.entity.items.total() / (float)payload.entity.block.itemCapacity; + return payload == null ? 0f : 1f - payload.build.items.total() / (float)payload.build.block.itemCapacity; } @Override public boolean shouldExport(){ - return payload != null && (payload.block().hasItems && payload.entity.items.empty()); + return payload != null && (payload.block().hasItems && payload.build.items.empty()); } } } diff --git a/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java b/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java index 6b8739b93a..c2af911324 100644 --- a/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java +++ b/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java @@ -11,7 +11,7 @@ public class ArmoredConduit extends Conduit{ public ArmoredConduit(String name){ super(name); - leakResistance = 10f; + leaks = false; } @Override @@ -32,8 +32,8 @@ public class ArmoredConduit extends Conduit{ } @Override - public boolean acceptLiquid(Building source, Liquid liquid, float amount){ - return super.acceptLiquid(source, liquid, amount) && (source.block instanceof Conduit || + public boolean acceptLiquid(Building source, Liquid liquid){ + return super.acceptLiquid(source, liquid) && (source.block instanceof Conduit || source.tile.absoluteRelativeTo(tile.x, tile.y) == rotation); } } diff --git a/core/src/mindustry/world/blocks/liquid/Conduit.java b/core/src/mindustry/world/blocks/liquid/Conduit.java index 8824d44d34..2af6613212 100644 --- a/core/src/mindustry/world/blocks/liquid/Conduit.java +++ b/core/src/mindustry/world/blocks/liquid/Conduit.java @@ -27,7 +27,7 @@ public class Conduit extends LiquidBlock implements Autotiler{ public @Load(value = "@-top-#", length = 5) TextureRegion[] topRegions; public @Load(value = "@-bottom-#", length = 5, fallback = "conduit-bottom-#") TextureRegion[] botRegions; - public float leakResistance = 1.5f; + public boolean leaks = true; public Conduit(String name){ super(name); @@ -120,9 +120,9 @@ public class Conduit extends LiquidBlock implements Autotiler{ } @Override - public boolean acceptLiquid(Building source, Liquid liquid, float amount){ + public boolean acceptLiquid(Building source, Liquid liquid){ noSleep(); - return liquids.get(liquid) + amount < liquidCapacity && (liquids.current() == liquid || liquids.currentAmount() < 0.2f) + return (liquids.current() == liquid || liquids.currentAmount() < 0.2f) && ((source.relativeTo(tile.x, tile.y) + 2) % 4 != rotation); } @@ -131,7 +131,7 @@ public class Conduit extends LiquidBlock implements Autotiler{ smoothLiquid = Mathf.lerpDelta(smoothLiquid, liquids.currentAmount() / liquidCapacity, 0.05f); if(liquids.total() > 0.001f && timer(timerFlow, 1)){ - moveLiquidForward(leakResistance, liquids.current()); + moveLiquidForward(leaks, liquids.current()); noSleep(); }else{ sleep(); diff --git a/core/src/mindustry/world/blocks/liquid/LiquidJunction.java b/core/src/mindustry/world/blocks/liquid/LiquidJunction.java index 2845281d96..80881e2c17 100644 --- a/core/src/mindustry/world/blocks/liquid/LiquidJunction.java +++ b/core/src/mindustry/world/blocks/liquid/LiquidJunction.java @@ -14,7 +14,7 @@ public class LiquidJunction extends LiquidBlock{ @Override public void setStats(){ super.setStats(); - stats.remove(BlockStat.liquidCapacity); + stats.remove(Stat.liquidCapacity); } @Override @@ -41,7 +41,7 @@ public class LiquidJunction extends LiquidBlock{ int dir = source.relativeTo(tile.x, tile.y); dir = (dir + 4) % 4; Building next = nearby(dir); - if(next == null || (!next.acceptLiquid(this, liquid, 0f) && !(next.block instanceof LiquidJunction))){ + if(next == null || (!next.acceptLiquid(this, liquid) && !(next.block instanceof LiquidJunction))){ return this; } return next.getLiquidDestination(this, liquid); diff --git a/core/src/mindustry/world/blocks/liquid/LiquidRouter.java b/core/src/mindustry/world/blocks/liquid/LiquidRouter.java index 60fab24df1..d3befe8233 100644 --- a/core/src/mindustry/world/blocks/liquid/LiquidRouter.java +++ b/core/src/mindustry/world/blocks/liquid/LiquidRouter.java @@ -20,8 +20,8 @@ public class LiquidRouter extends LiquidBlock{ } @Override - public boolean acceptLiquid(Building source, Liquid liquid, float amount){ - return liquids.get(liquid) + amount < liquidCapacity && (liquids.current() == liquid || liquids.currentAmount() < 0.2f); + public boolean acceptLiquid(Building source, Liquid liquid){ + return (liquids.current() == liquid || liquids.currentAmount() < 0.2f); } } } diff --git a/core/src/mindustry/world/blocks/logic/LogicBlock.java b/core/src/mindustry/world/blocks/logic/LogicBlock.java index b5439b3e70..488c44604d 100644 --- a/core/src/mindustry/world/blocks/logic/LogicBlock.java +++ b/core/src/mindustry/world/blocks/logic/LogicBlock.java @@ -8,6 +8,7 @@ import arc.struct.*; import arc.util.*; import arc.util.io.*; import mindustry.*; +import mindustry.core.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.io.*; @@ -116,8 +117,8 @@ public class LogicBlock extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.linkRange, range / 8, StatUnit.blocks); - stats.add(BlockStat.instructions, instructionsPerTick * 60, StatUnit.perSecond); + stats.add(Stat.linkRange, range / 8, StatUnit.blocks); + stats.add(Stat.instructions, instructionsPerTick * 60, StatUnit.perSecond); } @Override @@ -127,8 +128,7 @@ public class LogicBlock extends Block{ @Override public Object pointConfig(Object config, Cons transformer){ - if(config instanceof byte[]){ - byte[] data = (byte[])config; + if(config instanceof byte[] data){ try(DataInputStream stream = new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(data)))){ //discard version for now @@ -279,10 +279,13 @@ public class LogicBlock extends Block{ //store link objects executor.links = new Building[links.count(l -> l.valid && l.active)]; + executor.linkIds.clear(); int index = 0; for(LogicLink link : links){ if(link.active && link.valid){ - executor.links[index ++] = world.build(link.x, link.y); + Building build = world.build(link.x, link.y); + executor.links[index ++] = build; + if(build != null) executor.linkIds.add(build.id); } } @@ -304,9 +307,9 @@ public class LogicBlock extends Block{ assemble.get(asm); } - asm.putConst("@this", this); - asm.putConst("@thisx", x); - asm.putConst("@thisy", y); + asm.getVar("@this").value = this; + asm.putConst("@thisx", World.conv(x)); + asm.putConst("@thisy", World.conv(y)); executor.load(asm); }catch(Exception e){ @@ -331,6 +334,7 @@ public class LogicBlock extends Block{ @Override public void updateTile(){ + executor.team = team; //check for previously invalid links to add after configuration boolean changed = false; @@ -423,7 +427,6 @@ public class LogicBlock extends Block{ @Override public void buildConfiguration(Table table){ - table.button(Icon.pencil, Styles.clearTransi, () -> { Vars.ui.logic.show(code, code -> { configure(compress(code, relativeConnections())); diff --git a/core/src/mindustry/world/blocks/logic/LogicDisplay.java b/core/src/mindustry/world/blocks/logic/LogicDisplay.java index 9a6592ea36..505791e1b0 100644 --- a/core/src/mindustry/world/blocks/logic/LogicDisplay.java +++ b/core/src/mindustry/world/blocks/logic/LogicDisplay.java @@ -38,7 +38,7 @@ public class LogicDisplay extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.displaySize, "@x@", displaySize, displaySize); + stats.add(Stat.displaySize, "@x@", displaySize, displaySize); } public class LogicDisplayBuild extends Building{ @@ -75,15 +75,15 @@ public class LogicDisplay extends Block{ p1 = DisplayCmd.p1(c), p2 = DisplayCmd.p2(c), p3 = DisplayCmd.p3(c), p4 = DisplayCmd.p4(c); switch(type){ - case commandClear: Core.graphics.clear(x/255f, y/255f, p1/255f, 1f); break; - case commandLine: Lines.line(x, y, p1, p2); break; - case commandRect: Fill.crect(x, y, p1, p2); break; - case commandLineRect: Lines.rect(x, y, p1, p2); break; - case commandPoly: Fill.poly(x, y, Math.min(p1, maxSides), p2, p3); break; - case commandLinePoly: Lines.poly(x, y, Math.min(p1, maxSides), p2, p3); break; - case commandTriangle: Fill.tri(x, y, p1, p2, p3, p4); break; - case commandColor: this.color = Color.toFloatBits(x, y, p1, p2); Draw.color(this.color); break; - case commandStroke: this.stroke = x; Lines.stroke(x); break; + case commandClear -> Core.graphics.clear(x / 255f, y / 255f, p1 / 255f, 1f); + case commandLine -> Lines.line(x, y, p1, p2); + case commandRect -> Fill.crect(x, y, p1, p2); + case commandLineRect -> Lines.rect(x, y, p1, p2); + case commandPoly -> Fill.poly(x, y, Math.min(p1, maxSides), p2, p3); + case commandLinePoly -> Lines.poly(x, y, Math.min(p1, maxSides), p2, p3); + case commandTriangle -> Fill.tri(x, y, p1, p2, p3, p4); + case commandColor -> Draw.color(this.color = Color.toFloatBits(x, y, p1, p2)); + case commandStroke -> Lines.stroke(this.stroke = x); } } diff --git a/core/src/mindustry/world/blocks/logic/MemoryBlock.java b/core/src/mindustry/world/blocks/logic/MemoryBlock.java index d215238ced..0329744168 100644 --- a/core/src/mindustry/world/blocks/logic/MemoryBlock.java +++ b/core/src/mindustry/world/blocks/logic/MemoryBlock.java @@ -18,7 +18,7 @@ public class MemoryBlock extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.memoryCapacity, memoryCapacity, StatUnit.none); + stats.add(Stat.memoryCapacity, memoryCapacity, StatUnit.none); } public class MemoryBuild extends Building{ diff --git a/core/src/mindustry/world/blocks/logic/SwitchBlock.java b/core/src/mindustry/world/blocks/logic/SwitchBlock.java index bca47a306a..d27cebb1b3 100644 --- a/core/src/mindustry/world/blocks/logic/SwitchBlock.java +++ b/core/src/mindustry/world/blocks/logic/SwitchBlock.java @@ -37,6 +37,11 @@ public class SwitchBlock extends Block{ } } + @Override + public Boolean config(){ + return enabled; + } + @Override public byte version(){ return 1; diff --git a/core/src/mindustry/world/blocks/payloads/BlockPayload.java b/core/src/mindustry/world/blocks/payloads/BlockPayload.java deleted file mode 100644 index cf22587d98..0000000000 --- a/core/src/mindustry/world/blocks/payloads/BlockPayload.java +++ /dev/null @@ -1,60 +0,0 @@ -package mindustry.world.blocks.payloads; - -import arc.graphics.g2d.*; -import arc.util.io.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.graphics.*; -import mindustry.ui.*; -import mindustry.world.*; - -import static mindustry.Vars.*; - -public class BlockPayload implements Payload{ - public Building entity; - - public BlockPayload(Block block, Team team){ - this.entity = block.newBuilding().create(block, team); - } - - public BlockPayload(Building entity){ - this.entity = entity; - } - - public Block block(){ - return entity.block; - } - - public void place(Tile tile){ - place(tile, 0); - } - - public void place(Tile tile, int rotation){ - tile.setBlock(entity.block, entity.team, rotation, () -> entity); - entity.dropped(); - } - - @Override - public float size(){ - return entity.block.size * tilesize; - } - - @Override - public void write(Writes write){ - write.b(payloadBlock); - write.s(entity.block.id); - write.b(entity.version()); - entity.writeAll(write); - } - - @Override - public void set(float x, float y, float rotation){ - entity.set(x, y); - } - - @Override - public void draw(){ - Drawf.shadow(entity.x, entity.y, entity.block.size * tilesize * 2f); - Draw.rect(entity.block.icon(Cicon.full), entity.x, entity.y); - } -} diff --git a/core/src/mindustry/world/blocks/payloads/BuildPayload.java b/core/src/mindustry/world/blocks/payloads/BuildPayload.java new file mode 100644 index 0000000000..70414f01de --- /dev/null +++ b/core/src/mindustry/world/blocks/payloads/BuildPayload.java @@ -0,0 +1,60 @@ +package mindustry.world.blocks.payloads; + +import arc.graphics.g2d.*; +import arc.util.io.*; +import mindustry.game.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.ui.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +public class BuildPayload implements Payload{ + public Building build; + + public BuildPayload(Block block, Team team){ + this.build = block.newBuilding().create(block, team); + } + + public BuildPayload(Building build){ + this.build = build; + } + + public Block block(){ + return build.block; + } + + public void place(Tile tile){ + place(tile, 0); + } + + public void place(Tile tile, int rotation){ + tile.setBlock(build.block, build.team, rotation, () -> build); + build.dropped(); + } + + @Override + public float size(){ + return build.block.size * tilesize; + } + + @Override + public void write(Writes write){ + write.b(payloadBlock); + write.s(build.block.id); + write.b(build.version()); + build.writeAll(write); + } + + @Override + public void set(float x, float y, float rotation){ + build.set(x, y); + } + + @Override + public void draw(){ + Drawf.shadow(build.x, build.y, build.block.size * tilesize * 2f); + Draw.rect(build.block.icon(Cicon.full), build.x, build.y); + } +} diff --git a/core/src/mindustry/world/blocks/payloads/Payload.java b/core/src/mindustry/world/blocks/payloads/Payload.java index 21b073d56e..0e4773538f 100644 --- a/core/src/mindustry/world/blocks/payloads/Payload.java +++ b/core/src/mindustry/world/blocks/payloads/Payload.java @@ -51,9 +51,9 @@ public interface Payload{ byte type = read.b(); if(type == payloadBlock){ Block block = content.block(read.s()); - BlockPayload payload = new BlockPayload(block, Team.derelict); + BuildPayload payload = new BuildPayload(block, Team.derelict); byte version = read.b(); - payload.entity.readAll(read, version); + payload.build.readAll(read, version); return (T)payload; }else if(type == payloadUnit){ byte id = read.b(); diff --git a/core/src/mindustry/world/blocks/payloads/UnitPayload.java b/core/src/mindustry/world/blocks/payloads/UnitPayload.java index 724df792fa..2292244864 100644 --- a/core/src/mindustry/world/blocks/payloads/UnitPayload.java +++ b/core/src/mindustry/world/blocks/payloads/UnitPayload.java @@ -43,7 +43,7 @@ public class UnitPayload implements Payload{ @Override public boolean dump(){ - if(!Units.canCreate(unit.team, unit.type())){ + if(!Units.canCreate(unit.team, unit.type)){ deactiveTime = 1f; return false; } @@ -74,7 +74,7 @@ public class UnitPayload implements Payload{ @Override public void draw(){ Drawf.shadow(unit.x, unit.y, 20); - Draw.rect(unit.type().icon(Cicon.full), unit.x, unit.y, unit.rotation - 90); + Draw.rect(unit.type.icon(Cicon.full), unit.x, unit.y, unit.rotation - 90); //draw warning if(deactiveTime > 0){ diff --git a/core/src/mindustry/world/blocks/power/Battery.java b/core/src/mindustry/world/blocks/power/Battery.java index 03e7d66193..e78cb31b3a 100644 --- a/core/src/mindustry/world/blocks/power/Battery.java +++ b/core/src/mindustry/world/blocks/power/Battery.java @@ -20,7 +20,7 @@ public class Battery extends PowerDistributor{ super(name); outputsPower = true; consumesPower = true; - flags = EnumSet.of(BlockFlag.powerResupply); + flags = EnumSet.of(BlockFlag.battery); } public class BatteryBuild extends Building{ diff --git a/core/src/mindustry/world/blocks/power/ImpactReactor.java b/core/src/mindustry/world/blocks/power/ImpactReactor.java index a24fecf2b4..f5dc985d1e 100644 --- a/core/src/mindustry/world/blocks/power/ImpactReactor.java +++ b/core/src/mindustry/world/blocks/power/ImpactReactor.java @@ -55,7 +55,7 @@ public class ImpactReactor extends PowerGenerator{ super.setStats(); if(hasItems){ - stats.add(BlockStat.productionTime, itemDuration / 60f, StatUnit.seconds); + stats.add(Stat.productionTime, itemDuration / 60f, StatUnit.seconds); } } diff --git a/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java b/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java index 2d82bfa4c7..12b3f6d691 100644 --- a/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java +++ b/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java @@ -72,7 +72,7 @@ public class ItemLiquidGenerator extends PowerGenerator{ super.setStats(); if(hasItems){ - stats.add(BlockStat.productionTime, itemDuration / 60f, StatUnit.seconds); + stats.add(Stat.productionTime, itemDuration / 60f, StatUnit.seconds); } } diff --git a/core/src/mindustry/world/blocks/power/NuclearReactor.java b/core/src/mindustry/world/blocks/power/NuclearReactor.java index ac449d90db..85fe183993 100644 --- a/core/src/mindustry/world/blocks/power/NuclearReactor.java +++ b/core/src/mindustry/world/blocks/power/NuclearReactor.java @@ -5,6 +5,7 @@ import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; +import arc.struct.*; import arc.util.*; import arc.util.io.*; import mindustry.annotations.Annotations.*; @@ -47,6 +48,7 @@ public class NuclearReactor extends PowerGenerator{ hasItems = true; hasLiquids = true; rebuildable = false; + flags = EnumSet.of(BlockFlag.reactor); } @Override @@ -54,7 +56,7 @@ public class NuclearReactor extends PowerGenerator{ super.setStats(); if(hasItems){ - stats.add(BlockStat.productionTime, itemDuration / 60f, StatUnit.seconds); + stats.add(Stat.productionTime, itemDuration / 60f, StatUnit.seconds); } } diff --git a/core/src/mindustry/world/blocks/power/PowerGenerator.java b/core/src/mindustry/world/blocks/power/PowerGenerator.java index 2307093f27..ae9453d675 100644 --- a/core/src/mindustry/world/blocks/power/PowerGenerator.java +++ b/core/src/mindustry/world/blocks/power/PowerGenerator.java @@ -12,13 +12,13 @@ import mindustry.world.meta.*; public class PowerGenerator extends PowerDistributor{ /** The amount of power produced per tick in case of an efficiency of 1.0, which represents 100%. */ public float powerProduction; - public BlockStat generationType = BlockStat.basePowerGeneration; + public Stat generationType = Stat.basePowerGeneration; public PowerGenerator(String name){ super(name); sync = true; baseExplosiveness = 5f; - flags = EnumSet.of(BlockFlag.producer); + flags = EnumSet.of(BlockFlag.generator); } @Override diff --git a/core/src/mindustry/world/blocks/power/PowerNode.java b/core/src/mindustry/world/blocks/power/PowerNode.java index 245c3d4f7e..042b03099e 100644 --- a/core/src/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/mindustry/world/blocks/power/PowerNode.java @@ -112,14 +112,20 @@ public class PowerNode extends PowerBlock{ (UI.formatAmount((int)entity.power.graph.getLastPowerStored())), UI.formatAmount((int)entity.power.graph.getLastCapacity())), () -> Pal.powerBar, () -> Mathf.clamp(entity.power.graph.getLastPowerStored() / entity.power.graph.getLastCapacity()))); + + bars.add("connections", entity -> new Bar(() -> + Core.bundle.format("bar.powerlines", entity.power.links.size, maxNodes), + () -> Pal.items, + () -> (float)entity.power.links.size / (float)maxNodes + )); } @Override public void setStats(){ super.setStats(); - stats.add(BlockStat.powerRange, laserRange, StatUnit.blocks); - stats.add(BlockStat.powerConnections, maxNodes, StatUnit.none); + stats.add(Stat.powerRange, laserRange, StatUnit.blocks); + stats.add(Stat.powerConnections, maxNodes, StatUnit.none); } @Override diff --git a/core/src/mindustry/world/blocks/power/ThermalGenerator.java b/core/src/mindustry/world/blocks/power/ThermalGenerator.java index e29b7a6bdb..154bd02a0c 100644 --- a/core/src/mindustry/world/blocks/power/ThermalGenerator.java +++ b/core/src/mindustry/world/blocks/power/ThermalGenerator.java @@ -22,7 +22,7 @@ public class ThermalGenerator extends PowerGenerator{ public void setStats(){ super.setStats(); - stats.add(BlockStat.tiles, attribute, floating); + stats.add(Stat.tiles, attribute, floating); } @Override diff --git a/core/src/mindustry/world/blocks/production/AttributeSmelter.java b/core/src/mindustry/world/blocks/production/AttributeSmelter.java index 987b14e63b..c2650ab030 100644 --- a/core/src/mindustry/world/blocks/production/AttributeSmelter.java +++ b/core/src/mindustry/world/blocks/production/AttributeSmelter.java @@ -37,7 +37,7 @@ public class AttributeSmelter extends GenericSmelter{ public void setStats(){ super.setStats(); - stats.add(BlockStat.affinities, attribute, boostScale); + stats.add(Stat.affinities, attribute, boostScale); } public class AttributeSmelterBuild extends SmelterBuild{ diff --git a/core/src/mindustry/world/blocks/production/Cultivator.java b/core/src/mindustry/world/blocks/production/Cultivator.java index 2dc97d82f6..a5aede4e25 100644 --- a/core/src/mindustry/world/blocks/production/Cultivator.java +++ b/core/src/mindustry/world/blocks/production/Cultivator.java @@ -42,7 +42,7 @@ public class Cultivator extends GenericCrafter{ public void setStats(){ super.setStats(); - stats.add(BlockStat.affinities, attribute); + stats.add(Stat.affinities, attribute); } @Override diff --git a/core/src/mindustry/world/blocks/production/Drill.java b/core/src/mindustry/world/blocks/production/Drill.java index 7b86f1d1f5..ef4ab64b27 100644 --- a/core/src/mindustry/world/blocks/production/Drill.java +++ b/core/src/mindustry/world/blocks/production/Drill.java @@ -16,7 +16,9 @@ import mindustry.graphics.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; +import mindustry.world.blocks.environment.*; import mindustry.world.meta.*; +import mindustry.world.meta.values.*; import static mindustry.Vars.*; @@ -135,29 +137,11 @@ public class Drill extends Block{ public void setStats(){ super.setStats(); - stats.add(BlockStat.drillTier, table -> { - Seq list = content.blocks().select(b -> b.isFloor() && b.asFloor().itemDrop != null && b.asFloor().itemDrop.hardness <= tier); + stats.add(Stat.drillTier, new BlockFilterValue(b -> b instanceof Floor f && f.itemDrop != null && f.itemDrop.hardness <= tier)); - table.table(l -> { - l.left(); - - for(int i = 0; i < list.size; i++){ - Block item = list.get(i); - - l.image(item.icon(Cicon.small)).size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3); - l.add(item.localizedName).left().padLeft(1).padRight(4); - if(i % 5 == 4){ - l.row(); - } - } - }); - - - }); - - stats.add(BlockStat.drillSpeed, 60f / drillTime * size * size, StatUnit.itemsSecond); + stats.add(Stat.drillSpeed, 60f / drillTime * size * size, StatUnit.itemsSecond); if(liquidBoostIntensity != 1){ - stats.add(BlockStat.boostEffect, liquidBoostIntensity * liquidBoostIntensity, StatUnit.timesSpeed); + stats.add(Stat.boostEffect, liquidBoostIntensity * liquidBoostIntensity, StatUnit.timesSpeed); } } diff --git a/core/src/mindustry/world/blocks/production/Fracker.java b/core/src/mindustry/world/blocks/production/Fracker.java index d894cf05b5..d2dbd5bf69 100644 --- a/core/src/mindustry/world/blocks/production/Fracker.java +++ b/core/src/mindustry/world/blocks/production/Fracker.java @@ -21,7 +21,7 @@ public class Fracker extends SolidPump{ public void setStats(){ super.setStats(); - stats.add(BlockStat.productionTime, itemUseTime / 60f, StatUnit.seconds); + stats.add(Stat.productionTime, itemUseTime / 60f, StatUnit.seconds); } @Override @@ -45,7 +45,7 @@ public class Fracker extends SolidPump{ Draw.rect(region, x, y); super.drawCracks(); - Drawf.liquid(liquidRegion, x, y, liquids.total() / liquidCapacity, result.color); + Drawf.liquid(liquidRegion, x, y, liquids.get(result) / liquidCapacity, result.color); Draw.rect(rotatorRegion, x, y, pumpTime); Draw.rect(topRegion, x, y); diff --git a/core/src/mindustry/world/blocks/production/GenericCrafter.java b/core/src/mindustry/world/blocks/production/GenericCrafter.java index 434c9f4b65..c992be7d78 100644 --- a/core/src/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/mindustry/world/blocks/production/GenericCrafter.java @@ -2,6 +2,7 @@ package mindustry.world.blocks.production; import arc.graphics.g2d.*; import arc.math.*; +import arc.struct.*; import arc.util.io.*; import mindustry.content.*; import mindustry.entities.*; @@ -23,9 +24,6 @@ public class GenericCrafter extends Block{ public DrawBlock drawer = new DrawBlock(); - //public Cons drawer = null; - //public Prov drawIcons = null; - public GenericCrafter(String name){ super(name); update = true; @@ -34,6 +32,7 @@ public class GenericCrafter extends Block{ idleSound = Sounds.machine; sync = true; idleSoundVolume = 0.03f; + flags = EnumSet.of(BlockFlag.factory); } @Override @@ -44,14 +43,14 @@ public class GenericCrafter extends Block{ } super.setStats(); - stats.add(BlockStat.productionTime, craftTime / 60f, StatUnit.seconds); + stats.add(Stat.productionTime, craftTime / 60f, StatUnit.seconds); if(outputItem != null){ - stats.add(BlockStat.output, outputItem); + stats.add(Stat.output, outputItem); } if(outputLiquid != null){ - stats.add(BlockStat.output, outputLiquid.liquid, outputLiquid.amount, false); + stats.add(Stat.output, outputLiquid.liquid, outputLiquid.amount, false); } } diff --git a/core/src/mindustry/world/blocks/production/Incinerator.java b/core/src/mindustry/world/blocks/production/Incinerator.java index 1e16aa4faa..d51caf06c2 100644 --- a/core/src/mindustry/world/blocks/production/Incinerator.java +++ b/core/src/mindustry/world/blocks/production/Incinerator.java @@ -73,7 +73,7 @@ public class Incinerator extends Block{ } @Override - public boolean acceptLiquid(Building source, Liquid liquid, float amount){ + public boolean acceptLiquid(Building source, Liquid liquid){ return heat > 0.5f; } } diff --git a/core/src/mindustry/world/blocks/production/LiquidConverter.java b/core/src/mindustry/world/blocks/production/LiquidConverter.java index 84868d9b61..8a9725d42d 100644 --- a/core/src/mindustry/world/blocks/production/LiquidConverter.java +++ b/core/src/mindustry/world/blocks/production/LiquidConverter.java @@ -26,8 +26,8 @@ public class LiquidConverter extends GenericCrafter{ @Override public void setStats(){ super.setStats(); - stats.remove(BlockStat.output); - stats.add(BlockStat.output, outputLiquid.liquid, outputLiquid.amount * craftTime, false); + stats.remove(Stat.output); + stats.add(Stat.output, outputLiquid.liquid, outputLiquid.amount * craftTime, false); } public class LiquidConverterBuild extends GenericCrafterBuild{ diff --git a/core/src/mindustry/world/blocks/production/PayloadAcceptor.java b/core/src/mindustry/world/blocks/production/PayloadAcceptor.java index 75cfde865f..3b4693c250 100644 --- a/core/src/mindustry/world/blocks/production/PayloadAcceptor.java +++ b/core/src/mindustry/world/blocks/production/PayloadAcceptor.java @@ -95,7 +95,7 @@ public class PayloadAcceptor extends Block{ updatePayload(); payRotation = Mathf.slerpDelta(payRotation, rotate ? rotdeg() : 90f, 0.3f); - payVector.approachDelta(Vec2.ZERO, payloadSpeed); + payVector.approach(Vec2.ZERO, payloadSpeed * delta()); return hasArrived(); } @@ -105,7 +105,7 @@ public class PayloadAcceptor extends Block{ updatePayload(); - payVector.trns(rotdeg(), payVector.len() + edelta() * payloadSpeed); + payVector.trns(rotdeg(), payVector.len() + delta() * payloadSpeed); payRotation = rotdeg(); if(payVector.len() >= size * tilesize/2f){ diff --git a/core/src/mindustry/world/blocks/production/Pump.java b/core/src/mindustry/world/blocks/production/Pump.java index fa2f67999f..c4a6313129 100644 --- a/core/src/mindustry/world/blocks/production/Pump.java +++ b/core/src/mindustry/world/blocks/production/Pump.java @@ -26,7 +26,7 @@ public class Pump extends LiquidBlock{ @Override public void setStats(){ super.setStats(); - stats.add(BlockStat.output, 60f * pumpAmount * size * size, StatUnit.liquidSecond); + stats.add(Stat.output, 60f * pumpAmount * size * size, StatUnit.liquidSecond); } @Override diff --git a/core/src/mindustry/world/blocks/production/Separator.java b/core/src/mindustry/world/blocks/production/Separator.java index bcf66984e3..d9b355cc70 100644 --- a/core/src/mindustry/world/blocks/production/Separator.java +++ b/core/src/mindustry/world/blocks/production/Separator.java @@ -41,14 +41,14 @@ public class Separator extends Block{ super.setStats(); - stats.add(BlockStat.output, new ItemFilterValue(item -> { + stats.add(Stat.output, new ItemFilterValue(item -> { for(ItemStack i : results){ if(item == i.item) return true; } return false; })); - stats.add(BlockStat.productionTime, craftTime / 60f, StatUnit.seconds); + stats.add(Stat.productionTime, craftTime / 60f, StatUnit.seconds); } public class SeparatorBuild extends Building{ diff --git a/core/src/mindustry/world/blocks/production/SolidPump.java b/core/src/mindustry/world/blocks/production/SolidPump.java index 3b29665fde..d49a6499ac 100644 --- a/core/src/mindustry/world/blocks/production/SolidPump.java +++ b/core/src/mindustry/world/blocks/production/SolidPump.java @@ -53,10 +53,10 @@ public class SolidPump extends Pump{ public void setStats(){ super.setStats(); - stats.remove(BlockStat.output); - stats.add(BlockStat.output, result, 60f * pumpAmount, true); + stats.remove(Stat.output); + stats.add(Stat.output, result, 60f * pumpAmount, true); if(attribute != null){ - stats.add(baseEfficiency > 0.0001f ? BlockStat.affinities : BlockStat.tiles, attribute); + stats.add(baseEfficiency > 0.0001f ? Stat.affinities : Stat.tiles, attribute); } } diff --git a/core/src/mindustry/world/blocks/sandbox/LiquidVoid.java b/core/src/mindustry/world/blocks/sandbox/LiquidVoid.java index 0f49ffd3a7..3eeb628db8 100644 --- a/core/src/mindustry/world/blocks/sandbox/LiquidVoid.java +++ b/core/src/mindustry/world/blocks/sandbox/LiquidVoid.java @@ -21,7 +21,7 @@ public class LiquidVoid extends Block{ public class LiquidVoidBuild extends Building{ @Override - public boolean acceptLiquid(Building source, Liquid liquid, float amount){ + public boolean acceptLiquid(Building source, Liquid liquid){ return enabled; } diff --git a/core/src/mindustry/world/blocks/sandbox/PowerVoid.java b/core/src/mindustry/world/blocks/sandbox/PowerVoid.java index c423ba6caf..e97622c609 100644 --- a/core/src/mindustry/world/blocks/sandbox/PowerVoid.java +++ b/core/src/mindustry/world/blocks/sandbox/PowerVoid.java @@ -11,8 +11,8 @@ public class PowerVoid extends PowerBlock{ } @Override - public void init(){ - super.init(); - stats.remove(BlockStat.powerUse); + public void setStats(){ + super.setStats(); + stats.remove(Stat.powerUse); } } diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index 372042b5bc..039c7cc3cf 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -14,6 +14,7 @@ import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.logic.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; @@ -46,10 +47,11 @@ public class CoreBlock extends StorageBlock{ update = true; hasItems = true; priority = TargetPriority.core; - flags = EnumSet.of(BlockFlag.core, BlockFlag.producer, BlockFlag.unitModifier); + flags = EnumSet.of(BlockFlag.core, BlockFlag.unitModifier); unitCapModifier = 10; activeSound = Sounds.respawning; activeSoundVolume = 1f; + group = BlockGroup.none; } @Remote(called = Loc.server) @@ -75,12 +77,16 @@ public class CoreBlock extends StorageBlock{ public void setStats(){ super.setStats(); - stats.add(BlockStat.buildTime, 0, StatUnit.seconds); + stats.add(Stat.buildTime, 0, StatUnit.seconds); + } - bars.add("capacity", (CoreBuild e) -> - new Bar( - () -> Core.bundle.format("bar.capacity", UI.formatAmount(e.storageCapacity)), - () -> Pal.items, + @Override + public void setBars(){ + super.setBars(); + + bars.add("capacity", (CoreBuild e) -> new Bar( + () -> Core.bundle.format("bar.capacity", UI.formatAmount(e.storageCapacity)), + () -> Pal.items, () -> e.items.total() / ((float)e.storageCapacity * content.items().count(i -> i.unlockedNow())) )); } @@ -156,6 +162,13 @@ public class CoreBlock extends StorageBlock{ public int storageCapacity; //note that this unit is never actually used for control; the possession handler makes the player respawn when this unit is controlled public BlockUnitc unit = Nulls.blockUnit; + public boolean noEffect = false; + + @Override + public double sense(LAccess sensor){ + if(sensor == LAccess.itemCapacity) return storageCapacity; + return super.sense(sensor); + } @Override public void created(){ @@ -187,6 +200,21 @@ public class CoreBlock extends StorageBlock{ return false; } + @Override + public void onDestroyed(){ + super.onDestroyed(); + + //add a spawn to the map for future reference - waves should be disabled, so it shouldn't matter + if(state.isCampaign() && team == state.rules.waveTeam){ + //do not recache + tile.setOverlayQuiet(Blocks.spawn); + + if(!spawner.getSpawns().contains(tile)){ + spawner.getSpawns().add(tile); + } + } + } + @Override public void drawLight(){ Drawf.light(team, x, y, 30f * size, Pal.accent, 0.5f + Mathf.absin(20f, 0.1f)); @@ -194,7 +222,7 @@ public class CoreBlock extends StorageBlock{ @Override public boolean acceptItem(Building source, Item item){ - return items.get(item) < getMaximumAccepted(item); + return items.get(item) < getMaximumAccepted(item) || incinerate(); } @Override @@ -263,6 +291,10 @@ public class CoreBlock extends StorageBlock{ return tile instanceof StorageBuild && (((StorageBuild)tile).linkedCore == core || ((StorageBuild)tile).linkedCore == null); } + public boolean incinerate(){ + return state.isCampaign(); + } + @Override public float handleDamage(float amount){ if(player != null && team == player.team()){ @@ -303,10 +335,31 @@ public class CoreBlock extends StorageBlock{ state.teams.registerCore(this); } + @Override + public void itemTaken(Item item){ + if(state.isCampaign() && team == state.rules.defaultTeam){ + //update item taken amount + state.secinfo.handleCoreItem(item, -1); + } + } + @Override public void handleItem(Building source, Item item){ if(net.server() || !net.active()){ - super.handleItem(source, item); + if(team == state.rules.defaultTeam){ + state.secinfo.handleCoreItem(item, 1); + } + + if(items.get(item) >= getMaximumAccepted(item)){ + //create item incineration effect at random intervals + if(!noEffect){ + incinerateEffect(this, source); + } + noEffect = false; + }else{ + super.handleItem(source, item); + } + if(state.rules.tutorial){ Events.fire(new CoreItemDeliverEvent()); } diff --git a/core/src/mindustry/world/blocks/storage/StorageBlock.java b/core/src/mindustry/world/blocks/storage/StorageBlock.java index 6b022bf2f6..b7581b4dfb 100644 --- a/core/src/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/mindustry/world/blocks/storage/StorageBlock.java @@ -1,12 +1,16 @@ package mindustry.world.blocks.storage; +import arc.math.*; import arc.struct.*; import arc.util.*; +import mindustry.content.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.storage.CoreBlock.*; +import mindustry.world.meta.*; -public abstract class StorageBlock extends Block{ +public class StorageBlock extends Block{ public StorageBlock(String name){ super(name); @@ -14,6 +18,7 @@ public abstract class StorageBlock extends Block{ solid = true; update = false; destructible = true; + group = BlockGroup.storage; } @Override @@ -21,6 +26,16 @@ public abstract class StorageBlock extends Block{ return false; } + public static void incinerateEffect(Building self, Building source){ + if(Mathf.chance(0.3)){ + Tile edge = Edges.getFacingEdge(source, self); + Tile edge2 = Edges.getFacingEdge(self, source); + if(edge != null && edge2 != null){ + Fx.coreBurn.at((edge.worldx() + edge2.worldx())/2f, (edge.worldy() + edge2.worldy())/2f); + } + } + } + public class StorageBuild extends Building{ protected @Nullable Building linkedCore; @@ -29,6 +44,19 @@ public abstract class StorageBlock extends Block{ return linkedCore != null ? linkedCore.acceptItem(source, item) : items.get(item) < getMaximumAccepted(item); } + @Override + public void handleItem(Building source, Item item){ + if(linkedCore != null){ + if(linkedCore.items.get(item) >= ((CoreBuild)linkedCore).storageCapacity){ + incinerateEffect(this, source); + } + ((CoreBuild)linkedCore).noEffect = true; + linkedCore.handleItem(source, item); + }else{ + super.handleItem(source, item); + } + } + @Override public int getMaximumAccepted(Item item){ return itemCapacity; @@ -45,7 +73,7 @@ public abstract class StorageBlock extends Block{ public void overwrote(Seq previous){ for(Building other : previous){ if(other.items != null){ - items.addAll(other.items); + items.add(other.items); } } diff --git a/core/src/mindustry/world/blocks/storage/Unloader.java b/core/src/mindustry/world/blocks/storage/Unloader.java index 86ce15956e..524d6eb939 100644 --- a/core/src/mindustry/world/blocks/storage/Unloader.java +++ b/core/src/mindustry/world/blocks/storage/Unloader.java @@ -66,6 +66,7 @@ public class Unloader extends Block{ }else{ other.items.remove(item, 1); } + other.itemTaken(item); } } } diff --git a/core/src/mindustry/world/blocks/units/Reconstructor.java b/core/src/mindustry/world/blocks/units/Reconstructor.java index fa2783f30f..9374e0d801 100644 --- a/core/src/mindustry/world/blocks/units/Reconstructor.java +++ b/core/src/mindustry/world/blocks/units/Reconstructor.java @@ -3,6 +3,7 @@ package mindustry.world.blocks.units; import arc.*; import arc.graphics.g2d.*; import arc.math.*; +import arc.struct.*; import arc.util.*; import arc.util.io.*; import mindustry.*; @@ -21,7 +22,7 @@ import static mindustry.Vars.*; public class Reconstructor extends UnitBlock{ public float constructTime = 60 * 2; - public UnitType[][] upgrades = {}; + public Seq upgrades = new Seq<>(); public int[] capacities; public Reconstructor(String name){ @@ -50,11 +51,11 @@ public class Reconstructor extends UnitBlock{ () -> e.unit() == null ? "[lightgray]" + Iconc.cancel : Core.bundle.format("bar.unitcap", Fonts.getUnicodeStr(e.unit().name), - teamIndex.countType(e.team, e.unit()), + e.team.data().countType(e.unit()), Units.getCap(e.team) ), () -> Pal.power, - () -> e.unit() == null ? 0f : (float)teamIndex.countType(e.team, e.unit()) / Units.getCap(e.team) + () -> e.unit() == null ? 0f : (float)e.team.data().countType(e.unit()) / Units.getCap(e.team) )); } @@ -62,7 +63,23 @@ public class Reconstructor extends UnitBlock{ public void setStats(){ super.setStats(); - stats.add(BlockStat.productionTime, constructTime / 60f, StatUnit.seconds); + stats.add(Stat.productionTime, constructTime / 60f, StatUnit.seconds); + stats.add(Stat.output, table -> { + table.row(); + for(var upgrade : upgrades){ + float size = 8*3; + if(upgrade[0].unlockedNow() && upgrade[1].unlockedNow()){ + table.image(upgrade[0].icon(Cicon.small)).size(size).padRight(4).padLeft(10).scaling(Scaling.fit).right(); + table.add(upgrade[0].localizedName).left(); + + table.add("[lightgray] -> "); + + table.image(upgrade[1].icon(Cicon.small)).size(size).padRight(4).scaling(Scaling.fit); + table.add(upgrade[1].localizedName).left(); + table.row(); + } + } + }); } @Override @@ -89,7 +106,7 @@ public class Reconstructor extends UnitBlock{ return this.payload == null && relativeTo(source) != rotation && payload instanceof UnitPayload - && hasUpgrade(((UnitPayload)payload).unit.type()); + && hasUpgrade(((UnitPayload)payload).unit.type); } @Override @@ -113,9 +130,9 @@ public class Reconstructor extends UnitBlock{ if(constructing() && hasArrived()){ Draw.draw(Layer.blockOver, () -> { Draw.alpha(1f - progress/ constructTime); - Draw.rect(payload.unit.type().icon(Cicon.full), x, y, rotdeg() - 90); + Draw.rect(payload.unit.type.icon(Cicon.full), x, y, rotdeg() - 90); Draw.reset(); - Drawf.construct(this, upgrade(payload.unit.type()), rotdeg() - 90f, progress / constructTime, speedScl, time); + Drawf.construct(this, upgrade(payload.unit.type), rotdeg() - 90f, progress / constructTime, speedScl, time); }); }else{ Draw.z(Layer.blockOver); @@ -134,7 +151,7 @@ public class Reconstructor extends UnitBlock{ if(payload != null){ //check if offloading - if(!hasUpgrade(payload.unit.type())){ + if(!hasUpgrade(payload.unit.type)){ moveOutPayload(); }else{ //update progress if(moveInPayload()){ @@ -145,7 +162,7 @@ public class Reconstructor extends UnitBlock{ //upgrade the unit if(progress >= constructTime){ - payload.unit = upgrade(payload.unit.type()).create(payload.unit.team()); + payload.unit = upgrade(payload.unit.type).create(payload.unit.team()); progress = 0; Effect.shake(2f, 3f, this); Fx.producesmoke.at(this); @@ -167,12 +184,12 @@ public class Reconstructor extends UnitBlock{ public UnitType unit(){ if(payload == null) return null; - UnitType t = upgrade(payload.unit.type()); + UnitType t = upgrade(payload.unit.type); return t != null && t.unlockedNow() ? t : null; } public boolean constructing(){ - return payload != null && hasUpgrade(payload.unit.type()); + return payload != null && hasUpgrade(payload.unit.type); } public boolean hasUpgrade(UnitType type){ @@ -181,7 +198,7 @@ public class Reconstructor extends UnitBlock{ } public UnitType upgrade(UnitType type){ - UnitType[] r = Structs.find(upgrades, arr -> arr[0] == type); + UnitType[] r = upgrades.find(u -> u[0] == type); return r == null ? null : r[1]; } diff --git a/core/src/mindustry/world/blocks/units/RepairPoint.java b/core/src/mindustry/world/blocks/units/RepairPoint.java index abcc4bf738..789f7a8901 100644 --- a/core/src/mindustry/world/blocks/units/RepairPoint.java +++ b/core/src/mindustry/world/blocks/units/RepairPoint.java @@ -42,7 +42,7 @@ public class RepairPoint extends Block{ @Override public void setStats(){ super.setStats(); - stats.add(BlockStat.range, repairRadius / tilesize, StatUnit.blocks); + stats.add(Stat.range, repairRadius / tilesize, StatUnit.blocks); } @Override diff --git a/core/src/mindustry/world/blocks/units/ResupplyPoint.java b/core/src/mindustry/world/blocks/units/ResupplyPoint.java index c6d5e0aa18..6402b20147 100644 --- a/core/src/mindustry/world/blocks/units/ResupplyPoint.java +++ b/core/src/mindustry/world/blocks/units/ResupplyPoint.java @@ -2,6 +2,7 @@ package mindustry.world.blocks.units; import arc.func.*; import arc.graphics.*; +import arc.struct.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.game.*; @@ -9,6 +10,7 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.AmmoTypes.*; import mindustry.world.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -24,6 +26,7 @@ public class ResupplyPoint extends Block{ super(name); solid = update = true; hasItems = true; + flags = EnumSet.of(BlockFlag.resupply); } @Override @@ -62,10 +65,10 @@ public class ResupplyPoint extends Block{ public static boolean resupply(Team team, float x, float y, float range, float ammoAmount, Color ammoColor, Boolf valid){ if(!state.rules.unitAmmo) return false; - Unit unit = Units.closest(team, x, y, range, u -> u.type().ammoType instanceof ItemAmmoType && u.ammo <= u.type().ammoCapacity - ammoAmount && valid.get(u)); + Unit unit = Units.closest(team, x, y, range, u -> u.type.ammoType instanceof ItemAmmoType && u.ammo <= u.type.ammoCapacity - ammoAmount && valid.get(u)); if(unit != null){ Fx.itemTransfer.at(x, y, ammoAmount / 2f, ammoColor, unit); - unit.ammo = Math.min(unit.ammo + ammoAmount, unit.type().ammoCapacity); + unit.ammo = Math.min(unit.ammo + ammoAmount, unit.type.ammoCapacity); return true; } diff --git a/core/src/mindustry/world/blocks/units/UnitFactory.java b/core/src/mindustry/world/blocks/units/UnitFactory.java index 9b96b6f084..500385966e 100644 --- a/core/src/mindustry/world/blocks/units/UnitFactory.java +++ b/core/src/mindustry/world/blocks/units/UnitFactory.java @@ -14,6 +14,7 @@ import mindustry.entities.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.logic.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.world.blocks.*; @@ -21,12 +22,10 @@ import mindustry.world.blocks.payloads.*; import mindustry.world.consumers.*; import mindustry.world.meta.*; -import static mindustry.Vars.*; - public class UnitFactory extends UnitBlock{ public int[] capacities; - public UnitPlan[] plans = new UnitPlan[0]; + public Seq plans = new Seq<>(4); public UnitFactory(String name){ super(name); @@ -41,11 +40,11 @@ public class UnitFactory extends UnitBlock{ rotate = true; config(Integer.class, (UnitFactoryBuild tile, Integer i) -> { - tile.currentPlan = i < 0 || i >= plans.length ? -1 : i; + tile.currentPlan = i < 0 || i >= plans.size ? -1 : i; tile.progress = 0; }); - consumes.add(new ConsumeItemDynamic((UnitFactoryBuild e) -> e.currentPlan != -1 ? plans[e.currentPlan].requirements : ItemStack.empty)); + consumes.add(new ConsumeItemDynamic((UnitFactoryBuild e) -> e.currentPlan != -1 ? plans.get(e.currentPlan).requirements : ItemStack.empty)); } @Override @@ -71,11 +70,11 @@ public class UnitFactory extends UnitBlock{ () -> e.unit() == null ? "[lightgray]" + Iconc.cancel : Core.bundle.format("bar.unitcap", Fonts.getUnicodeStr(e.unit().name), - teamIndex.countType(e.team, e.unit()), + e.team.data().countType(e.unit()), Units.getCap(e.team) ), () -> Pal.power, - () -> e.unit() == null ? 0f : (float)teamIndex.countType(e.team, e.unit()) / Units.getCap(e.team) + () -> e.unit() == null ? 0f : (float)e.team.data().countType(e.unit()) / Units.getCap(e.team) )); } @@ -88,7 +87,7 @@ public class UnitFactory extends UnitBlock{ public void setStats(){ super.setStats(); - stats.remove(BlockStat.itemCapacity); + stats.remove(Stat.itemCapacity); } @Override @@ -121,7 +120,13 @@ public class UnitFactory extends UnitBlock{ public int currentPlan = -1; public float fraction(){ - return currentPlan == -1 ? 0 : progress / plans[currentPlan].time; + return currentPlan == -1 ? 0 : progress / plans.get(currentPlan).time; + } + + @Override + public Object senseObject(LAccess sensor){ + if(sensor == LAccess.config) return currentPlan == -1 ? null : plans.get(currentPlan).unit; + return super.senseObject(sensor); } @Override @@ -129,7 +134,7 @@ public class UnitFactory extends UnitBlock{ Seq units = Seq.with(plans).map(u -> u.unit).filter(u -> u.unlockedNow()); if(units.any()){ - ItemSelection.buildTable(table, units, () -> currentPlan == -1 ? null : plans[currentPlan].unit, unit -> configure(Structs.indexOf(plans, u -> u.unit == unit))); + ItemSelection.buildTable(table, units, () -> currentPlan == -1 ? null : plans.get(currentPlan).unit, unit -> configure(plans.indexOf(u -> u.unit == unit))); }else{ table.table(Styles.black3, t -> t.add("@none").color(Color.lightGray)); } @@ -150,11 +155,11 @@ public class UnitFactory extends UnitBlock{ table.table(t -> { t.left(); t.image().update(i -> { - i.setDrawable(currentPlan == -1 ? Icon.cancel : reg.set(plans[currentPlan].unit.icon(Cicon.medium))); + i.setDrawable(currentPlan == -1 ? Icon.cancel : reg.set(plans.get(currentPlan).unit.icon(Cicon.medium))); i.setScaling(Scaling.fit); i.setColor(currentPlan == -1 ? Color.lightGray : Color.white); }).size(32).padBottom(-4).padRight(2); - t.label(() -> currentPlan == -1 ? "@none" : plans[currentPlan].unit.localizedName).color(Color.lightGray); + t.label(() -> currentPlan == -1 ? "@none" : plans.get(currentPlan).unit.localizedName).color(Color.lightGray); }).left(); } @@ -169,7 +174,7 @@ public class UnitFactory extends UnitBlock{ Draw.rect(outRegion, x, y, rotdeg()); if(currentPlan != -1){ - UnitPlan plan = plans[currentPlan]; + UnitPlan plan = plans.get(currentPlan); Draw.draw(Layer.blockOver, () -> Drawf.construct(this, plan.unit, rotdeg() - 90f, progress / plan.time, speedScl, time)); } @@ -185,7 +190,7 @@ public class UnitFactory extends UnitBlock{ @Override public void updateTile(){ - if(currentPlan < 0 || currentPlan >= plans.length){ + if(currentPlan < 0 || currentPlan >= plans.size){ currentPlan = -1; } @@ -200,7 +205,7 @@ public class UnitFactory extends UnitBlock{ moveOutPayload(); if(currentPlan != -1 && payload == null){ - UnitPlan plan = plans[currentPlan]; + UnitPlan plan = plans.get(currentPlan); if(progress >= plan.time && consValid()){ progress = 0f; @@ -230,11 +235,11 @@ public class UnitFactory extends UnitBlock{ @Override public boolean acceptItem(Building source, Item item){ return currentPlan != -1 && items.get(item) < getMaximumAccepted(item) && - Structs.contains(plans[currentPlan].requirements, stack -> stack.item == item); + Structs.contains(plans.get(currentPlan).requirements, stack -> stack.item == item); } public @Nullable UnitType unit(){ - return currentPlan == - 1 ? null : plans[currentPlan].unit; + return currentPlan == - 1 ? null : plans.get(currentPlan).unit; } @Override diff --git a/core/src/mindustry/world/consumers/Consume.java b/core/src/mindustry/world/consumers/Consume.java index 410d041a03..3066dbb9bb 100644 --- a/core/src/mindustry/world/consumers/Consume.java +++ b/core/src/mindustry/world/consumers/Consume.java @@ -69,5 +69,5 @@ public abstract class Consume{ public abstract boolean valid(Building entity); - public abstract void display(BlockStats stats); + public abstract void display(Stats stats); } diff --git a/core/src/mindustry/world/consumers/ConsumeItemDynamic.java b/core/src/mindustry/world/consumers/ConsumeItemDynamic.java index a2dd079c20..0c18e77741 100644 --- a/core/src/mindustry/world/consumers/ConsumeItemDynamic.java +++ b/core/src/mindustry/world/consumers/ConsumeItemDynamic.java @@ -73,7 +73,7 @@ public class ConsumeItemDynamic extends Consume{ } @Override - public void display(BlockStats stats){ + public void display(Stats stats){ //should be handled by the block } } diff --git a/core/src/mindustry/world/consumers/ConsumeItemFilter.java b/core/src/mindustry/world/consumers/ConsumeItemFilter.java index e9e98041c4..93d70a46f3 100644 --- a/core/src/mindustry/world/consumers/ConsumeItemFilter.java +++ b/core/src/mindustry/world/consumers/ConsumeItemFilter.java @@ -70,7 +70,7 @@ public class ConsumeItemFilter extends Consume{ } @Override - public void display(BlockStats stats){ - stats.add(booster ? BlockStat.booster : BlockStat.input, new ItemFilterValue(filter)); + public void display(Stats stats){ + stats.add(booster ? Stat.booster : Stat.input, new ItemFilterValue(filter)); } } diff --git a/core/src/mindustry/world/consumers/ConsumeItems.java b/core/src/mindustry/world/consumers/ConsumeItems.java index 01909e2a14..f43746db87 100644 --- a/core/src/mindustry/world/consumers/ConsumeItems.java +++ b/core/src/mindustry/world/consumers/ConsumeItems.java @@ -63,7 +63,7 @@ public class ConsumeItems extends Consume{ } @Override - public void display(BlockStats stats){ - stats.add(booster ? BlockStat.booster : BlockStat.input, new ItemListValue(items)); + public void display(Stats stats){ + stats.add(booster ? Stat.booster : Stat.input, new ItemListValue(items)); } } diff --git a/core/src/mindustry/world/consumers/ConsumeLiquid.java b/core/src/mindustry/world/consumers/ConsumeLiquid.java index 90f3bf0687..839b59c607 100644 --- a/core/src/mindustry/world/consumers/ConsumeLiquid.java +++ b/core/src/mindustry/world/consumers/ConsumeLiquid.java @@ -45,7 +45,7 @@ public class ConsumeLiquid extends ConsumeLiquidBase{ } @Override - public void display(BlockStats stats){ - stats.add(booster ? BlockStat.booster : BlockStat.input, liquid, amount * timePeriod, timePeriod == 60); + public void display(Stats stats){ + stats.add(booster ? Stat.booster : Stat.input, liquid, amount * timePeriod, timePeriod == 60); } } diff --git a/core/src/mindustry/world/consumers/ConsumeLiquidBase.java b/core/src/mindustry/world/consumers/ConsumeLiquidBase.java index f2cae7676e..47b1eb8834 100644 --- a/core/src/mindustry/world/consumers/ConsumeLiquidBase.java +++ b/core/src/mindustry/world/consumers/ConsumeLiquidBase.java @@ -23,6 +23,6 @@ public abstract class ConsumeLiquidBase extends Consume{ } protected float use(Building entity){ - return Math.min(amount * entity.delta(), entity.block.liquidCapacity); + return Math.min(amount * entity.edelta(), entity.block.liquidCapacity); } } diff --git a/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java b/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java index 962023488b..851cf75fd2 100644 --- a/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java +++ b/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java @@ -49,7 +49,7 @@ public class ConsumeLiquidFilter extends ConsumeLiquidBase{ } @Override - public void display(BlockStats stats){ - stats.add(booster ? BlockStat.booster : BlockStat.input, new LiquidFilterValue(filter, amount * timePeriod, timePeriod == 60f)); + public void display(Stats stats){ + stats.add(booster ? Stat.booster : Stat.input, new LiquidFilterValue(filter, amount * timePeriod, timePeriod == 60f)); } } diff --git a/core/src/mindustry/world/consumers/ConsumePower.java b/core/src/mindustry/world/consumers/ConsumePower.java index 2dc55dbb11..67b23d6c4c 100644 --- a/core/src/mindustry/world/consumers/ConsumePower.java +++ b/core/src/mindustry/world/consumers/ConsumePower.java @@ -54,11 +54,11 @@ public class ConsumePower extends Consume{ } @Override - public void display(BlockStats stats){ + public void display(Stats stats){ if(buffered){ - stats.add(BlockStat.powerCapacity, capacity, StatUnit.none); + stats.add(Stat.powerCapacity, capacity, StatUnit.none); }else{ - stats.add(BlockStat.powerUse, usage * 60f, StatUnit.powerSecond); + stats.add(Stat.powerUse, usage * 60f, StatUnit.powerSecond); } } diff --git a/core/src/mindustry/world/consumers/Consumers.java b/core/src/mindustry/world/consumers/Consumers.java index 4ce410aa04..a811a24d52 100644 --- a/core/src/mindustry/world/consumers/Consumers.java +++ b/core/src/mindustry/world/consumers/Consumers.java @@ -109,7 +109,7 @@ public class Consumers{ return optionalResults; } - public void display(BlockStats stats){ + public void display(Stats stats){ for(Consume c : map){ if(c != null){ c.display(stats); diff --git a/core/src/mindustry/world/meta/BlockFlag.java b/core/src/mindustry/world/meta/BlockFlag.java index c818ba642a..ca4ded3db3 100644 --- a/core/src/mindustry/world/meta/BlockFlag.java +++ b/core/src/mindustry/world/meta/BlockFlag.java @@ -4,16 +4,24 @@ package mindustry.world.meta; public enum BlockFlag{ /** Enemy core; primary target for all units. */ core, - /** Producer of important goods. */ - producer, - /** A turret. */ + /** Vault/container/etc */ + storage, + /** Something that generates power. */ + generator, + /** Any turret. */ turret, + /** A block that transforms resources. */ + factory, /** Repair point. */ repair, /** Rally point. */ rally, /** Block that stored power for resupply. */ - powerResupply, + battery, + /** Block used for resupply. */ + resupply, + /** Any reactor block. */ + reactor, /** Any block that boosts unit capacity. */ unitModifier; diff --git a/core/src/mindustry/world/meta/BlockStat.java b/core/src/mindustry/world/meta/BlockStat.java deleted file mode 100644 index 05e45acbfe..0000000000 --- a/core/src/mindustry/world/meta/BlockStat.java +++ /dev/null @@ -1,68 +0,0 @@ -package mindustry.world.meta; - -import arc.*; - -import java.util.*; - -/** Describes one type of stat for a block. */ -public enum BlockStat{ - health(StatCategory.general), - size(StatCategory.general), - displaySize(StatCategory.general), - buildTime(StatCategory.general), - buildCost(StatCategory.general), - memoryCapacity(StatCategory.general), - - itemCapacity(StatCategory.items), - itemsMoved(StatCategory.items), - launchTime(StatCategory.items), - maxConsecutive(StatCategory.items), - - liquidCapacity(StatCategory.liquids), - - powerCapacity(StatCategory.power), - powerUse(StatCategory.power), - powerDamage(StatCategory.power), - powerRange(StatCategory.power), - powerConnections(StatCategory.power), - basePowerGeneration(StatCategory.power), - - tiles(StatCategory.crafting), - input(StatCategory.crafting), - output(StatCategory.crafting), - productionTime(StatCategory.crafting), - drillTier(StatCategory.crafting), - drillSpeed(StatCategory.crafting), - maxUnits(StatCategory.crafting), - linkRange(StatCategory.crafting), - instructions(StatCategory.crafting), - - speedIncrease(StatCategory.shooting), - repairTime(StatCategory.shooting), - range(StatCategory.shooting), - shootRange(StatCategory.shooting), - inaccuracy(StatCategory.shooting), - shots(StatCategory.shooting), - reload(StatCategory.shooting), - powerShot(StatCategory.shooting), - targetsAir(StatCategory.shooting), - targetsGround(StatCategory.shooting), - damage(StatCategory.shooting), - ammo(StatCategory.shooting), - shieldHealth(StatCategory.shooting), - cooldownTime(StatCategory.shooting), - - booster(StatCategory.optional), - boostEffect(StatCategory.optional), - affinities(StatCategory.optional); - - public final StatCategory category; - - BlockStat(StatCategory category){ - this.category = category; - } - - public String localized(){ - return Core.bundle.get("blocks." + name().toLowerCase(Locale.ROOT)); - } -} diff --git a/core/src/mindustry/world/meta/Stat.java b/core/src/mindustry/world/meta/Stat.java new file mode 100644 index 0000000000..2a8d88a7d1 --- /dev/null +++ b/core/src/mindustry/world/meta/Stat.java @@ -0,0 +1,88 @@ +package mindustry.world.meta; + +import arc.*; + +import java.util.*; + +/** Describes one type of stat for content. */ +public enum Stat{ + health, + size, + displaySize, + buildTime, + buildCost, + memoryCapacity, + explosiveness, + flammability, + radioactivity, + heatCapacity, + viscosity, + temperature, + speed, + buildSpeed, + mineSpeed, + mineTier, + payloadCapacity, + commandLimit, + baseDeflectChance, + lightningChance, + lightningDamage, + abilities, + + itemCapacity(StatCat.items), + itemsMoved(StatCat.items), + launchTime(StatCat.items), + maxConsecutive(StatCat.items), + + liquidCapacity(StatCat.liquids), + + powerCapacity(StatCat.power), + powerUse(StatCat.power), + powerDamage(StatCat.power), + powerRange(StatCat.power), + powerConnections(StatCat.power), + basePowerGeneration(StatCat.power), + + tiles(StatCat.crafting), + input(StatCat.crafting), + output(StatCat.crafting), + productionTime(StatCat.crafting), + drillTier(StatCat.crafting), + drillSpeed(StatCat.crafting), + maxUnits(StatCat.crafting), + linkRange(StatCat.crafting), + instructions(StatCat.crafting), + + speedIncrease(StatCat.shooting), + repairTime(StatCat.shooting), + range(StatCat.shooting), + shootRange(StatCat.shooting), + inaccuracy(StatCat.shooting), + shots(StatCat.shooting), + reload(StatCat.shooting), + powerShot(StatCat.shooting), + targetsAir(StatCat.shooting), + targetsGround(StatCat.shooting), + damage(StatCat.shooting), + ammo(StatCat.shooting), + shieldHealth(StatCat.shooting), + cooldownTime(StatCat.shooting), + + booster(StatCat.optional), + boostEffect(StatCat.optional), + affinities(StatCat.optional); + + public final StatCat category; + + Stat(StatCat category){ + this.category = category; + } + + Stat(){ + this.category = StatCat.general; + } + + public String localized(){ + return Core.bundle.get("stat." + name().toLowerCase(Locale.ROOT)); + } +} diff --git a/core/src/mindustry/world/meta/StatCategory.java b/core/src/mindustry/world/meta/StatCat.java similarity index 91% rename from core/src/mindustry/world/meta/StatCategory.java rename to core/src/mindustry/world/meta/StatCat.java index e6c91b04bb..8dfd42d3c5 100644 --- a/core/src/mindustry/world/meta/StatCategory.java +++ b/core/src/mindustry/world/meta/StatCat.java @@ -3,7 +3,7 @@ package mindustry.world.meta; import arc.*; /** A specific category for a stat. */ -public enum StatCategory{ +public enum StatCat{ general, power, liquids, diff --git a/core/src/mindustry/world/meta/StatUnit.java b/core/src/mindustry/world/meta/StatUnit.java index 42825f0379..b2a866be3e 100644 --- a/core/src/mindustry/world/meta/StatUnit.java +++ b/core/src/mindustry/world/meta/StatUnit.java @@ -9,6 +9,7 @@ import java.util.*; */ public enum StatUnit{ blocks, + blocksSquared, powerSecond, liquidSecond, itemsSecond, diff --git a/core/src/mindustry/world/meta/BlockStats.java b/core/src/mindustry/world/meta/Stats.java similarity index 55% rename from core/src/mindustry/world/meta/BlockStats.java rename to core/src/mindustry/world/meta/Stats.java index ff93a217a9..68f96ff260 100644 --- a/core/src/mindustry/world/meta/BlockStats.java +++ b/core/src/mindustry/world/meta/Stats.java @@ -2,54 +2,71 @@ package mindustry.world.meta; import arc.struct.ObjectMap.*; import arc.struct.*; +import arc.util.*; import mindustry.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.meta.values.*; /** Hold and organizes a list of block stats. */ -public class BlockStats{ - private final OrderedMap>> map = new OrderedMap<>(); +public class Stats{ + /** Whether to display stats with categories. If false, categories are completely ignored during display. */ + public boolean useCategories = false; + /** Whether these stats are initialized yet. */ + public boolean intialized = false; + + @Nullable + private OrderedMap>> map; private boolean dirty; /** Adds a single float value with this stat, formatted to 2 decimal places. */ - public void add(BlockStat stat, float value, StatUnit unit){ + public void add(Stat stat, float value, StatUnit unit){ add(stat, new NumberValue(value, unit)); } + /** Adds a single float value with this stat and no unit. */ + public void add(Stat stat, float value){ + add(stat, value, StatUnit.none); + } + + /** Adds an integer percent stat value. Value is assumed to be in the 0-1 range. */ + public void addPercent(Stat stat, float value){ + add(stat, new NumberValue((int)(value * 100), StatUnit.percent)); + } + /** Adds a single y/n boolean value. */ - public void add(BlockStat stat, boolean value){ + public void add(Stat stat, boolean value){ add(stat, new BooleanValue(value)); } /** Adds an item value. */ - public void add(BlockStat stat, Item item){ + public void add(Stat stat, Item item){ add(stat, new ItemListValue(new ItemStack(item, 1))); } /** Adds an item value. */ - public void add(BlockStat stat, ItemStack item){ + public void add(Stat stat, ItemStack item){ add(stat, new ItemListValue(item)); } /** Adds an item value. */ - public void add(BlockStat stat, Liquid liquid, float amount, boolean perSecond){ + public void add(Stat stat, Liquid liquid, float amount, boolean perSecond){ add(stat, new LiquidValue(liquid, amount, perSecond)); } - public void add(BlockStat stat, Attribute attr){ + public void add(Stat stat, Attribute attr){ add(stat, attr, false, 1f); } - public void add(BlockStat stat, Attribute attr, float scale){ + public void add(Stat stat, Attribute attr, float scale){ add(stat, attr, false, scale); } - public void add(BlockStat stat, Attribute attr, boolean floating){ + public void add(Stat stat, Attribute attr, boolean floating){ add(stat, attr, floating, 1f); } - public void add(BlockStat stat, Attribute attr, boolean floating, float scale){ + public void add(Stat stat, Attribute attr, boolean floating, float scale){ for(Block block : Vars.content.blocks()){ if(!block.isFloor() || block.asFloor().attributes.get(attr) == 0 || (block.asFloor().isLiquid && !floating)) continue; add(stat, new FloorEfficiencyValue(block.asFloor(), block.asFloor().attributes.get(attr) * scale)); @@ -57,12 +74,14 @@ public class BlockStats{ } /** Adds a single string value with this stat. */ - public void add(BlockStat stat, String format, Object... args){ + public void add(Stat stat, String format, Object... args){ add(stat, new StringValue(format, args)); } /** Adds a stat value. */ - public void add(BlockStat stat, StatValue value){ + public void add(Stat stat, StatValue value){ + if(map == null) map = new OrderedMap<>(); + if(!map.containsKey(stat.category)){ map.put(stat.category, new OrderedMap<>()); } @@ -73,7 +92,9 @@ public class BlockStats{ } /** Removes a stat, if it exists. */ - public void remove(BlockStat stat){ + public void remove(Stat stat){ + if(map == null) map = new OrderedMap<>(); + if(!map.containsKey(stat.category) || !map.get(stat.category).containsKey(stat)){ throw new RuntimeException("No stat entry found: \"" + stat + "\" in block."); } @@ -83,11 +104,13 @@ public class BlockStats{ dirty = true; } - public OrderedMap>> toMap(){ + public OrderedMap>> toMap(){ + if(map == null) map = new OrderedMap<>(); + //sort stats by index if they've been modified if(dirty){ map.orderedKeys().sort(); - for(Entry>> entry : map.entries()){ + for(Entry>> entry : map.entries()){ entry.value.orderedKeys().sort(); } diff --git a/core/src/mindustry/world/meta/values/AmmoListValue.java b/core/src/mindustry/world/meta/values/AmmoListValue.java index d0d8624ea9..359b958a96 100644 --- a/core/src/mindustry/world/meta/values/AmmoListValue.java +++ b/core/src/mindustry/world/meta/values/AmmoListValue.java @@ -50,6 +50,10 @@ public class AmmoListValue implements StatValue{ sep(bt, Core.bundle.format("bullet.knockback", Strings.fixed(type.knockback, 1))); } + if(type.pierce || type.pierceCap != -1){ + sep(bt, type.pierceCap == -1 ? "@bullet.infinitepierce" : Core.bundle.format("bullet.pierce", type.pierceCap)); + } + if((type.status == StatusEffects.burning || type.status == StatusEffects.melting) || type.incendAmount > 0){ sep(bt, "@bullet.incendiary"); } diff --git a/core/src/mindustry/world/meta/values/BlockFilterValue.java b/core/src/mindustry/world/meta/values/BlockFilterValue.java new file mode 100644 index 0000000000..3c4d0fe56e --- /dev/null +++ b/core/src/mindustry/world/meta/values/BlockFilterValue.java @@ -0,0 +1,37 @@ +package mindustry.world.meta.values; + +import arc.func.*; +import arc.scene.ui.layout.*; +import arc.struct.*; +import mindustry.ui.*; +import mindustry.world.*; +import mindustry.world.meta.*; + +import static mindustry.Vars.*; + +public class BlockFilterValue implements StatValue{ + public final Boolf pred; + + public BlockFilterValue(Boolf pred){ + this.pred = pred; + } + + @Override + public void display(Table table){ + Seq list = content.blocks().select(pred); + + table.table(l -> { + l.left(); + + for(int i = 0; i < list.size; i++){ + Block item = list.get(i); + + l.image(item.icon(Cicon.small)).size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3); + l.add(item.localizedName).left().padLeft(1).padRight(4); + if(i % 5 == 4){ + l.row(); + } + } + }); + } +} diff --git a/core/src/mindustry/world/meta/values/BlockListValue.java b/core/src/mindustry/world/meta/values/BlockListValue.java new file mode 100644 index 0000000000..a1cd5adffe --- /dev/null +++ b/core/src/mindustry/world/meta/values/BlockListValue.java @@ -0,0 +1,33 @@ +package mindustry.world.meta.values; + +import arc.scene.ui.layout.*; +import arc.struct.*; +import mindustry.ui.*; +import mindustry.world.*; +import mindustry.world.meta.*; + +public class BlockListValue implements StatValue{ + public final Seq list; + + public BlockListValue(Seq list){ + this.list = list; + } + + @Override + public void display(Table table){ + + table.table(l -> { + l.left(); + + for(int i = 0; i < list.size; i++){ + Block item = list.get(i); + + l.image(item.icon(Cicon.small)).size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3); + l.add(item.localizedName).left().padLeft(1).padRight(4); + if(i % 5 == 4){ + l.row(); + } + } + }); + } +} diff --git a/core/src/mindustry/world/modules/ItemModule.java b/core/src/mindustry/world/modules/ItemModule.java index 16d49484f0..6cd96985cb 100644 --- a/core/src/mindustry/world/modules/ItemModule.java +++ b/core/src/mindustry/world/modules/ItemModule.java @@ -243,6 +243,16 @@ public class ItemModule extends BlockModule{ } } + public void add(ItemSeq stacks){ + stacks.each(this::add); + } + + public void add(ItemModule items){ + for(int i = 0; i < items.items.length; i++){ + add(i, items.items[i]); + } + } + public void add(Item item, int amount){ add(item.id, amount); } @@ -261,12 +271,6 @@ public class ItemModule extends BlockModule{ } } - public void addAll(ItemModule items){ - for(int i = 0; i < items.items.length; i++){ - add(i, items.items[i]); - } - } - public void remove(Item item, int amount){ amount = Math.min(amount, items[item.id]); diff --git a/desktop/build.gradle b/desktop/build.gradle index 6b383b958d..628d28147c 100644 --- a/desktop/build.gradle +++ b/desktop/build.gradle @@ -1,8 +1,7 @@ -import com.badlogicgames.packr.Packr -import com.badlogicgames.packr.PackrConfig +import com.badlogicgames.packr.* -import java.nio.ByteBuffer -import java.security.MessageDigest +import java.nio.* +import java.security.* sourceSets.main.java.srcDirs = [ "src/" ] diff --git a/desktop/src/mindustry/desktop/DesktopLauncher.java b/desktop/src/mindustry/desktop/DesktopLauncher.java index bd9ec3e81b..76b72e3ca3 100644 --- a/desktop/src/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/mindustry/desktop/DesktopLauncher.java @@ -227,7 +227,9 @@ public class DesktopLauncher extends ClientLauncher{ @Override public void updateLobby(){ - SVars.net.updateLobby(); + if(SVars.net != null){ + SVars.net.updateLobby(); + } } @Override diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java index 7e7c9ecef3..9338aafc5b 100644 --- a/desktop/src/mindustry/desktop/steam/SStats.java +++ b/desktop/src/mindustry/desktop/steam/SStats.java @@ -7,7 +7,7 @@ import mindustry.*; import mindustry.content.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; -import mindustry.game.Stats.*; +import mindustry.game.GameStats.*; import mindustry.gen.*; import mindustry.type.*; @@ -60,7 +60,7 @@ public class SStats implements SteamUserStatsCallback{ // active10Phantoms.complete(); //} - if(Groups.unit.count(u -> u.type() == UnitTypes.crawler && u.team() == player.team()) >= 50){ + if(Groups.unit.count(u -> u.type == UnitTypes.crawler && u.team() == player.team()) >= 50){ active50Crawlers.complete(); } diff --git a/fastlane/metadata/android/cs-CZ/changelogs/29661.txt b/fastlane/metadata/android/cs-CZ/changelogs/29661.txt new file mode 100644 index 0000000000..7d218735fd --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/29661.txt @@ -0,0 +1,9 @@ +- Opraveny některé chyby +- A některé opraveny nebyly +- Přidáno 6 nových jednotek, které zaplnily chybějící povýšení na T4/5 +- Přidán obrys jednotek pro vizuálbí čistotu, možná bude později odebráno +- Přidán povrch typu bláto (příspěvek od ThePlayerA) +- Přidána cena výzkumu k jednotkám v technologickém stromě +- Přidána schopnost hry nahradit malé kusy zdí přímo většími +- Přidána možnost vybrat si cíl vyslání (jen zběžně testováno) +- Přidány barvy týmů pro uskladněné bloky (příspěek od Voz-Duh) diff --git a/fastlane/metadata/android/cs-CZ/changelogs/29664.txt b/fastlane/metadata/android/cs-CZ/changelogs/29664.txt new file mode 100644 index 0000000000..8a5413885e --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/29664.txt @@ -0,0 +1,9 @@ +Toto je malá aktualizace. Neobsahuje mnoho nového obsahu, hlavně opravy chyb. +Další plánovaná aktualizace se zaměří na kampaň a pravděpodobně zabere více času. + +- Opravy chyb +- Přidána barva týmu pro řídicí středisko (příspěvek od Voz-Duh) +- Vyčištěny některé sprajty jednotek tak, aby ladily s V6 stylem (částěčný příspěvek od Voz-Duh) +- Přidána podpora na Androidu pro modifikace založené na Javě (aktuálně prakticky bez dokumentace) +- Přidána vysoce kapacitní pamě%tový banka (2x2) pro logické procesory +- Vyvážení hry diff --git a/fastlane/metadata/android/en-US/changelogs/29670.txt b/fastlane/metadata/android/en-US/changelogs/29670.txt new file mode 100644 index 0000000000..3a1e1f7b28 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29670.txt @@ -0,0 +1,9 @@ +Mindustry 6.0 is now in beta. This means most mechanics outside of the campaign have been more or less finalized. Any significant new content is unlikely to be added. + +- Added Foreshadow turret +- Added Tsunami turret (initial implementation by Slava0135, sprite by EyeOfDarkness) +- Added logic unit control system +- Added space floor block +- Added button to center map to editor +- Added rule setting for enemy lights +- Changed armored conduits to not leak diff --git a/fastlane/metadata/android/en-US/changelogs/29672.txt b/fastlane/metadata/android/en-US/changelogs/29672.txt new file mode 100644 index 0000000000..04c1a277ad --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29672.txt @@ -0,0 +1,6 @@ +- Fixed "host game" crash, as well as some other prominent bugs +- Logic: Breaking change: All coordinates are now in tiles, not in "world units" +- Logic: Added sensors for ammo (units/turrets) +- Campaign: Added research button in mobile multiplayer (check pause menu) +- Campaign: Added tech tree sharing in multiplayer - only the host can research +- Campaign: Re-added sector invasions, any sector near an enemy base can be invaded diff --git a/fastlane/metadata/android/in/full_description.txt b/fastlane/metadata/android/in/full_description.txt new file mode 100644 index 0000000000..2597618097 --- /dev/null +++ b/fastlane/metadata/android/in/full_description.txt @@ -0,0 +1,14 @@ +Buat rantai pasokan pengantar berjalan yang rumit untuk memasukkan amunisi ke menara Anda, menghasilkan bahan yang akan digunakan untuk membangun, dan mempertahankan bangunan Anda dari gelombang musuh. Bermain dengan teman-teman Anda dalam game co-op multipemain lintas platform, atau tantang mereka dalam pertandingan PvP berbasis tim. + +Fitur: +- 24 peta bawaan +- Kampanye, lengkap dengan pohon teknologi dan area yang dapat dibuka +- 4 bos gelombang yang kuat untuk dikalahkan +- Sistem transportasi energi, cairan dan barang +- 19 jenis drone, mech, dan kapal +- 120+ blok teknologi untuk dikuasai +- 75+ blok lingkungan yang berbeda +- Multipemain lintas platform melalui jaringan lokal atau server khusus +- Aturan permainan khusus: Ubah biaya blok, statistik musuh, item awal, waktu gelombang, dan lainnya +- Editor yang andal, dengan alat untuk menghasilkan sumber daya, medan, dekorasi, dan menerapkan simetri ke peta secara acak +- Tata letak gelombang peta yang dapat disesuaikan \ No newline at end of file diff --git a/fastlane/metadata/android/in/short_description.txt b/fastlane/metadata/android/in/short_description.txt new file mode 100644 index 0000000000..2d6a63c557 --- /dev/null +++ b/fastlane/metadata/android/in/short_description.txt @@ -0,0 +1 @@ +Sebuah game pertahanan menara sandbox berbasis pabrik. \ No newline at end of file diff --git a/fastlane/metadata/android/in/summary.txt b/fastlane/metadata/android/in/summary.txt new file mode 100644 index 0000000000..2d6a63c557 --- /dev/null +++ b/fastlane/metadata/android/in/summary.txt @@ -0,0 +1 @@ +Sebuah game pertahanan menara sandbox berbasis pabrik. \ No newline at end of file diff --git a/fastlane/metadata/android/in/title.txt b/fastlane/metadata/android/in/title.txt new file mode 100644 index 0000000000..2beb939017 --- /dev/null +++ b/fastlane/metadata/android/in/title.txt @@ -0,0 +1 @@ +Mindustry \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index b4210058e3..f73761a7bf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=6fca97cecdf28a696b2c19097f70960485a62743 +archash=f8ef0f3a72de0f79ca49da895fed0b6889cd597e diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 0000000000..e1dfa83815 --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,4 @@ +before_install: + - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh + - source install-jdk.sh --feature 14 + - jshell --version \ No newline at end of file diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 1e0aa942ab..7e1be67c52 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -30,6 +30,7 @@ import java.time.*; import java.time.format.*; import java.util.*; +import static arc.util.ColorCodes.*; import static arc.util.Log.*; import static mindustry.Vars.*; @@ -37,7 +38,7 @@ public class ServerControl implements ApplicationListener{ private static final int roundExtraTime = 12; private static final int maxLogLength = 1024 * 512; - protected static String[] tags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""}; + protected static String[] tags = {"&lc&fb[D]&fr", "&lb&fb[I]&fr", "&ly&fb[W]&fr", "&lr&fb[E]", ""}; protected static DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("MM-dd-yyyy HH:mm:ss"), autosaveDate = DateTimeFormatter.ofPattern("MM-dd-yyyy_HH-mm-ss"); @@ -55,6 +56,8 @@ public class ServerControl implements ApplicationListener{ private ServerSocket serverSocket; private PrintWriter socketOutput; + private String yes; + public ServerControl(String[] args){ Core.settings.defaults( "bans", "", @@ -72,22 +75,27 @@ public class ServerControl implements ApplicationListener{ lastMode = Gamemode.survival; } - Log.setLogger((level, text) -> { - String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr"); + logger = (level1, text) -> { + String result = bold + lightBlack + "[" + dateTime.format(LocalDateTime.now()) + "] " + reset + format(tags[level1.ordinal()] + " " + text + "&fr"); System.out.println(result); if(Config.logging.bool()){ - logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + formatColors(tags[level.ordinal()] + " " + text + "&fr", false)); + logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + formatColors(tags[level1.ordinal()] + " " + text + "&fr", false)); } if(socketOutput != null){ try{ socketOutput.println(formatColors(text + "&fr", false)); - }catch(Throwable e){ - err("Error occurred logging to socket: @", e.getClass().getSimpleName()); + }catch(Throwable e1){ + err("Error occurred logging to socket: @", e1.getClass().getSimpleName()); } } - }); + }; + + formatter = (text, useColors, arg) -> { + text = Strings.format(text.replace("@", "&fb&lb@&fr"), arg); + return useColors ? addColors(text) : removeColors(text); + }; Time.setDeltaProvider(() -> Core.graphics.getDeltaTime() * 60f); @@ -113,12 +121,12 @@ public class ServerControl implements ApplicationListener{ if(args.length > 0){ commands.addAll(Strings.join(" ", args).split(",")); - info("&lmFound @ command-line arguments to parse.", commands.size); + info("Found @ command-line arguments to parse.", commands.size); } if(!Config.startCommands.string().isEmpty()){ String[] startup = Strings.join(" ", Config.startCommands.string()).split(","); - info("&lmFound @ startup commands.", startup.length); + info("Found @ startup commands.", startup.length); commands.addAll(startup); } @@ -126,7 +134,7 @@ public class ServerControl implements ApplicationListener{ CommandResponse response = handler.handleMessage(s); if(response.type != ResponseType.valid){ err("Invalid command argument sent: '@': @", s, response.type.name()); - err("Argument usage: &lc , "); + err("Argument usage: &lb , "); } } }); @@ -139,7 +147,7 @@ public class ServerControl implements ApplicationListener{ if(Version.build == -1){ warn("&lyYour server is running a custom build, which means that client checking is disabled."); - warn("&lyIt is highly advised to specify which version you're using by building with gradle args &lc-Pbuildversion=&lm&ly."); + warn("&lyIt is highly advised to specify which version you're using by building with gradle args &lb&fb-Pbuildversion=&lr"); } //set up default shuffle mode @@ -152,9 +160,9 @@ public class ServerControl implements ApplicationListener{ Events.on(GameOverEvent.class, event -> { if(inExtraRound) return; if(state.rules.waves){ - info("&lcGame over! Reached wave &ly@&lc with &ly@&lc players online on map &ly@&lc.", state.wave, Groups.player.size(), Strings.capitalize(state.map.name())); + info("Game over! Reached wave @ with @ players online on map @.", state.wave, Groups.player.size(), Strings.capitalize(state.map.name())); }else{ - info("&lcGame over! Team &ly@&lc is victorious with &ly@&lc players online on map &ly@&lc.", event.winner.name, Groups.player.size(), Strings.capitalize(state.map.name())); + info("Game over! Team @ is victorious with @ players online on map @.", event.winner.name, Groups.player.size(), Strings.capitalize(state.map.name())); } //set next map to be played @@ -207,11 +215,11 @@ public class ServerControl implements ApplicationListener{ String fileName = "auto_" + mapName + "_" + date + "." + saveExtension; Fi file = saveDirectory.child(fileName); - info("&lbAutosaving..."); + info("Autosaving..."); try{ SaveIO.save(file); - info("&lbAutosave completed."); + info("Autosave completed."); }catch(Throwable e){ err("Autosave failed.", e); } @@ -239,25 +247,25 @@ public class ServerControl implements ApplicationListener{ Timer.schedule(() -> Core.settings.forceSave(), saveInterval, saveInterval); if(!mods.list().isEmpty()){ - info("&lc@ mods loaded.", mods.list().size); + info("@ mods loaded.", mods.list().size); } toggleSocket(Config.socketInput.bool()); - info("&lcServer loaded. Type &ly'help'&lc for help."); + info("Server loaded. Type @ for help.", "'help'"); } private void registerCommands(){ handler.register("help", "Displays this command list.", arg -> { info("Commands:"); for(Command command : handler.getCommandList()){ - info(" &y" + command.text + (command.paramText.isEmpty() ? "" : " ") + command.paramText + " - &lm" + command.description); + info(" &b&lb " + command.text + (command.paramText.isEmpty() ? "" : " &lc&fi") + command.paramText + "&fr - &lw" + command.description); } }); handler.register("version", "Displays server version info.", arg -> { - info("&lmVersion: &lyMindustry @-@ @ / build @", Version.number, Version.modifier, Version.type, Version.build + (Version.revision == 0 ? "" : "." + Version.revision)); - info("&lmJava Version: &ly@", System.getProperty("java.version")); + info("Version: Mindustry @-@ @ / build @", Version.number, Version.modifier, Version.type, Version.build + (Version.revision == 0 ? "" : "." + Version.revision)); + info("Java Version: @", System.getProperty("java.version")); }); handler.register("exit", "Exit the server application.", arg -> { @@ -297,7 +305,7 @@ public class ServerControl implements ApplicationListener{ result = maps.all().find(map -> map.name().equalsIgnoreCase(arg[0].replace('_', ' ')) || map.name().equalsIgnoreCase(arg[0])); if(result == null){ - err("No map with name &y'@'&lr found.", arg[0]); + err("No map with name '@' found.", arg[0]); return; } }else{ @@ -327,21 +335,21 @@ public class ServerControl implements ApplicationListener{ if(!maps.all().isEmpty()){ info("Maps:"); for(Map map : maps.all()){ - info(" &ly@: &lb&fi@ / @x@", map.name(), map.custom ? "Custom" : "Default", map.width, map.height); + info(" @: &fi@ / @x@", map.name(), map.custom ? "Custom" : "Default", map.width, map.height); } }else{ info("No maps found."); } - info("&lyMap directory: &lb&fi@", customMapDirectory.file().getAbsoluteFile().toString()); + info("Map directory: &fi@", customMapDirectory.file().getAbsoluteFile().toString()); }); handler.register("reloadmaps", "Reload all maps from disk.", arg -> { int beforeMaps = maps.all().size; maps.reload(); if(maps.all().size > beforeMaps){ - info("&lc@&ly new map(s) found and reloaded.", maps.all().size - beforeMaps); + info("@ new map(s) found and reloaded.", maps.all().size - beforeMaps); }else{ - info("&lyMaps reloaded."); + info("Maps reloaded."); } }); @@ -350,23 +358,23 @@ public class ServerControl implements ApplicationListener{ info("Status: &rserver closed"); }else{ info("Status:"); - info(" &lyPlaying on map &fi@&fb &lb/&ly Wave @", Strings.capitalize(state.map.name()), state.wave); + info(" Playing on map &fi@ / Wave @", Strings.capitalize(state.map.name()), state.wave); if(state.rules.waves){ - info("&ly @ enemies.", state.enemies); + info(" @ enemies.", state.enemies); }else{ - info("&ly @ seconds until next wave.", (int)(state.wavetime / 60)); + info(" @ seconds until next wave.", (int)(state.wavetime / 60)); } - info(" &ly@ FPS, @ MB used.", Core.graphics.getFramesPerSecond(), Core.app.getJavaHeap() / 1024 / 1024); + info(" @ FPS, @ MB used.", Core.graphics.getFramesPerSecond(), Core.app.getJavaHeap() / 1024 / 1024); if(Groups.player.size() > 0){ - info(" &lyPlayers: @", Groups.player.size()); + info(" Players: @", Groups.player.size()); for(Player p : Groups.player){ - info(" &y@ / @", p.name(), p.uuid()); + info(" @ / @", p.name, p.uuid()); } }else{ - info(" &lyNo players connected."); + info(" No players connected."); } } }); @@ -375,30 +383,30 @@ public class ServerControl implements ApplicationListener{ if(!mods.list().isEmpty()){ info("Mods:"); for(LoadedMod mod : mods.list()){ - info(" &ly@ &lcv@", mod.meta.displayName(), mod.meta.version); + info(" @ &fi@", mod.meta.displayName(), mod.meta.version); } }else{ info("No mods found."); } - info("&lyMod directory: &lb&fi@", modDirectory.file().getAbsoluteFile().toString()); + info("Mod directory: &fi@", modDirectory.file().getAbsoluteFile().toString()); }); handler.register("mod", "", "Display information about a loaded plugin.", arg -> { LoadedMod mod = mods.list().find(p -> p.meta.name.equalsIgnoreCase(arg[0])); if(mod != null){ - info("Name: &ly@", mod.meta.displayName()); - info("Internal Name: &ly@", mod.name); - info("Version: &ly@", mod.meta.version); - info("Author: &ly@", mod.meta.author); - info("Path: &ly@", mod.file.path()); - info("Description: &ly@", mod.meta.description); + info("Name: @", mod.meta.displayName()); + info("Internal Name: @", mod.name); + info("Version: @", mod.meta.version); + info("Author: @", mod.meta.author); + info("Path: @", mod.file.path()); + info("Description: @", mod.meta.description); }else{ - info("No mod with name &ly'@'&lg found."); + info("No mod with name '@' found."); } }); handler.register("js", "", "Run arbitrary Javascript.", arg -> { - info("&lc" + mods.getScripts().runConsole(arg[0])); + info("&fi&lw&fb" + mods.getScripts().runConsole(arg[0])); }); handler.register("say", "", "Send a message to all players.", arg -> { @@ -409,7 +417,7 @@ public class ServerControl implements ApplicationListener{ Call.sendMessage("[scarlet][[Server]:[] " + arg[0]); - info("&lyServer: &lb@", arg[0]); + info("&fi&lcServer: &fr@", "&lw" + arg[0]); }); @@ -424,7 +432,7 @@ public class ServerControl implements ApplicationListener{ JsonValue base = JsonIO.json().fromJson(null, rules); if(arg.length == 0){ - Log.info("&lyRules:\n@", JsonIO.print(rules)); + Log.info("Rules:\n@", JsonIO.print(rules)); }else if(arg.length == 1){ Log.err("Invalid usage. Specify which rule to remove or add."); }else{ @@ -436,7 +444,7 @@ public class ServerControl implements ApplicationListener{ boolean remove = arg[0].equals("remove"); if(remove){ if(base.has(arg[1])){ - Log.info("Rule &lc'@'&lg removed.", arg[1]); + Log.info("Rule '@' removed.", arg[1]); base.remove(arg[1]); }else{ Log.err("Rule not defined, so not removed."); @@ -460,7 +468,7 @@ public class ServerControl implements ApplicationListener{ base.remove(value.name); } base.addChild(arg[1], value); - Log.info("Changed rule: &ly@", value.toString().replace("\n", " ")); + Log.info("Changed rule: @", value.toString().replace("\n", " ")); }catch(Throwable e){ Log.err("Error parsing rule JSON: @", e.getMessage()); } @@ -499,7 +507,7 @@ public class ServerControl implements ApplicationListener{ handler.register("playerlimit", "[off/somenumber]", "Set the server player limit.", arg -> { if(arg.length == 0){ - info("Player limit is currently &lc@.", netServer.admins.getPlayerLimit() == 0 ? "off" : netServer.admins.getPlayerLimit()); + info("Player limit is currently @.", netServer.admins.getPlayerLimit() == 0 ? "off" : netServer.admins.getPlayerLimit()); return; } if(arg[0].equals("off")){ @@ -519,11 +527,11 @@ public class ServerControl implements ApplicationListener{ handler.register("config", "[name] [value...]", "Configure server settings.", arg -> { if(arg.length == 0){ - info("&lyAll config values:"); + info("All config values:"); for(Config c : Config.all){ - Log.info("&ly| &lc@:&lm @", c.name(), c.get()); - Log.info("&ly| | @", c.description); - Log.info("&ly|"); + Log.info("&lk| @: @", c.name(), "&lc&fi" + c.get()); + Log.info("&lk| | &lw" + c.description); + Log.info("&lk|"); } return; } @@ -531,7 +539,7 @@ public class ServerControl implements ApplicationListener{ try{ Config c = Config.valueOf(arg[0]); if(arg.length == 1){ - Log.info("&lc'@'&lg is currently &lc@.", c.name(), c.get()); + Log.info("'@' is currently @.", c.name(), c.get()); }else{ if(c.isBool()){ c.set(arg[1].equals("on") || arg[1].equals("true")); @@ -546,7 +554,7 @@ public class ServerControl implements ApplicationListener{ c.set(arg[1]); } - Log.info("&lc@&lg set to &lc@.", c.name(), c.get()); + Log.info("@ set to @.", c.name(), c.get()); Core.settings.forceSave(); } }catch(IllegalArgumentException e){ @@ -556,9 +564,9 @@ public class ServerControl implements ApplicationListener{ handler.register("subnet-ban", "[add/remove] [address]", "Ban a subnet. This simply rejects all connections with IPs starting with some string.", arg -> { if(arg.length == 0){ - Log.info("Subnets banned: &lc@", netServer.admins.getSubnetBans().isEmpty() ? "" : ""); + Log.info("Subnets banned: @", netServer.admins.getSubnetBans().isEmpty() ? "" : ""); for(String subnet : netServer.admins.getSubnetBans()){ - Log.info("&ly " + subnet + ""); + Log.info("&lw " + subnet + ""); } }else if(arg.length == 1){ err("You must provide a subnet to add or remove."); @@ -570,7 +578,7 @@ public class ServerControl implements ApplicationListener{ } netServer.admins.addSubnetBan(arg[1]); - Log.info("Banned &ly@&lc**", arg[1]); + Log.info("Banned @**", arg[1]); }else if(arg[0].equals("remove")){ if(!netServer.admins.getSubnetBans().contains(arg[1])){ err("That subnet isn't banned."); @@ -578,7 +586,7 @@ public class ServerControl implements ApplicationListener{ } netServer.admins.removeSubnetBan(arg[1]); - Log.info("Unbanned &ly@&lc**", arg[1]); + Log.info("Unbanned @**", arg[1]); }else{ err("Incorrect usage. You must provide add/remove as the second argument."); } @@ -587,12 +595,12 @@ public class ServerControl implements ApplicationListener{ handler.register("whitelisted", "List the entire whitelist.", arg -> { if(netServer.admins.getWhitelisted().isEmpty()){ - info("&lyNo whitelisted players found."); + info("No whitelisted players found."); return; } - info("&lyWhitelist:"); - netServer.admins.getWhitelisted().each(p -> Log.info("- &ly@", p.lastName)); + info("Whitelist:"); + netServer.admins.getWhitelisted().each(p -> info("- @", p.lastName)); }); handler.register("whitelist-add", "", "Add a player to the whitelist by ID.", arg -> { @@ -603,7 +611,7 @@ public class ServerControl implements ApplicationListener{ } netServer.admins.whitelist(arg[0]); - info("Player &ly'@'&lg has been whitelisted.", info.lastName); + info("Player '@' has been whitelisted.", info.lastName); }); handler.register("whitelist-remove", "", "Remove a player to the whitelist by ID.", arg -> { @@ -614,18 +622,18 @@ public class ServerControl implements ApplicationListener{ } netServer.admins.unwhitelist(arg[0]); - info("Player &ly'@'&lg has been un-whitelisted.", info.lastName); + info("Player '@' has been un-whitelisted.", info.lastName); }); handler.register("shuffle", "[none/all/custom/builtin]", "Set map shuffling mode.", arg -> { if(arg.length == 0){ - info("Shuffle mode current set to &ly'@'&lg.", maps.getShuffleMode()); + info("Shuffle mode current set to '@'.", maps.getShuffleMode()); }else{ try{ ShuffleMode mode = ShuffleMode.valueOf(arg[0]); Core.settings.put("shufflemode", mode.name()); maps.setShuffleMode(mode); - info("Shuffle mode set to &ly'@'&lg.", arg[0]); + info("Shuffle mode set to '@'.", arg[0]); }catch(Exception e){ err("Invalid shuffle mode."); } @@ -636,7 +644,7 @@ public class ServerControl implements ApplicationListener{ Map res = maps.all().find(map -> map.name().equalsIgnoreCase(arg[0].replace('_', ' ')) || map.name().equalsIgnoreCase(arg[0])); if(res != null){ nextMapOverride = res; - Log.info("Next map set to &ly'@'.", res.name()); + Log.info("Next map set to '@'.", res.name()); }else{ Log.err("No map '@' found.", arg[0]); } @@ -692,9 +700,9 @@ public class ServerControl implements ApplicationListener{ if(bans.size == 0){ info("No ID-banned players have been found."); }else{ - info("&lyBanned players [ID]:"); + info("Banned players [ID]:"); for(PlayerInfo info : bans){ - info(" &ly @ / Last known name: '@'", info.id, info.lastName); + info(" @ / Last known name: '@'", info.id, info.lastName); } } @@ -703,13 +711,13 @@ public class ServerControl implements ApplicationListener{ if(ipbans.size == 0){ info("No IP-banned players have been found."); }else{ - info("&lmBanned players [IP]:"); + info("Banned players [IP]:"); for(String string : ipbans){ PlayerInfo info = netServer.admins.findByIP(string); if(info != null){ - info(" &lm '@' / Last known name: '@' / ID: '@'", string, info.lastName, info.id); + info(" '@' / Last known name: '@' / ID: '@'", string, info.lastName, info.id); }else{ - info(" &lm '@' (No known name or info)", string); + info(" '@' (No known name or info)", string); } } } @@ -763,7 +771,7 @@ public class ServerControl implements ApplicationListener{ netServer.admins.unAdminPlayer(target.id); } if(playert != null) playert.admin = add; - info("Changed admin status of player: &ly@", target.lastName); + info("Changed admin status of player: @", target.lastName); }else{ err("Nobody with that name or ID could be found. If adding an admin by name, make sure they're online; otherwise, use their UUID."); } @@ -775,7 +783,7 @@ public class ServerControl implements ApplicationListener{ if(admins.size == 0){ info("No admins have been found."); }else{ - info("&lyAdmins:"); + info("Admins:"); for(PlayerInfo info : admins){ info(" &lm @ / ID: '@' / IP: '@'", info.lastName, info.id, info.lastIP); } @@ -786,10 +794,10 @@ public class ServerControl implements ApplicationListener{ if(Groups.player.size() == 0){ info("No players are currently in the server."); }else{ - info("&lyPlayers: @", Groups.player.size()); + info("Players: @", Groups.player.size()); for(Player user : Groups.player){ PlayerInfo userInfo = user.getInfo(); - info(" &lm @ / ID: '@' / IP: '@' / Admin: '@'", userInfo.lastName, userInfo.id, userInfo.lastIP, userInfo.admin); + info(" &lm @ / ID: @ / IP: @ / Admin: @", userInfo.lastName, userInfo.id, userInfo.lastIP, userInfo.admin); } } }); @@ -847,7 +855,7 @@ public class ServerControl implements ApplicationListener{ info("Save files: "); for(Fi file : saveDirectory.list()){ if(file.extension().equals(saveExtension)){ - info("| &ly@", file.nameWithoutExtension()); + info("| @", file.nameWithoutExtension()); } } }); @@ -858,7 +866,7 @@ public class ServerControl implements ApplicationListener{ return; } - info("&lyCore destroyed."); + info("Core destroyed."); inExtraRound = false; Events.fire(new GameOverEvent(Team.crux)); }); @@ -868,16 +876,16 @@ public class ServerControl implements ApplicationListener{ ObjectSet infos = netServer.admins.findByName(arg[0]); if(infos.size > 0){ - info("&lgPlayers found: @", infos.size); + info("Players found: @", infos.size); int i = 0; for(PlayerInfo info : infos){ - info("&lc[@] Trace info for player '@' / UUID @", i++, info.lastName, info.id); - info(" &lyall names used: @", info.names); - info(" &lyIP: @", info.lastIP); - info(" &lyall IPs used: @", info.ips); - info(" &lytimes joined: @", info.timesJoined); - info(" &lytimes kicked: @", info.timesKicked); + info("[@] Trace info for player '@' / UUID @", i++, info.lastName, info.id); + info(" all names used: @", info.names); + info(" IP: @", info.lastIP); + info(" all IPs used: @", info.ips); + info(" times joined: @", info.timesJoined); + info(" times kicked: @", info.timesKicked); } }else{ info("Nobody with that name could be found."); @@ -889,11 +897,11 @@ public class ServerControl implements ApplicationListener{ ObjectSet infos = netServer.admins.searchNames(arg[0]); if(infos.size > 0){ - info("&lgPlayers found: @", infos.size); + info("Players found: @", infos.size); int i = 0; for(PlayerInfo info : infos){ - info("- &lc[@] &ly'@'&lc / &lm@", i++, info.lastName, info.id); + info("- [@] '@' / @", i++, info.lastName, info.id); } }else{ info("Nobody with that name could be found."); @@ -904,7 +912,15 @@ public class ServerControl implements ApplicationListener{ int pre = (int)(Core.app.getJavaHeap() / 1024 / 1024); System.gc(); int post = (int)(Core.app.getJavaHeap() / 1024 / 1024); - info("&ly@&lg MB collected. Memory usage now at &ly@&lg MB.", pre - post, post); + info("@ MB collected. Memory usage now at @ MB.", pre - post, post); + }); + + handler.register("yes", "Run the last suggested incorrect command.", arg -> { + if(yes == null){ + err("There is nothing to say yes to."); + }else{ + handleCommandString(yes); + } }); mods.eachClass(p -> p.registerServerCommands(handler)); @@ -937,6 +953,7 @@ public class ServerControl implements ApplicationListener{ if(closest != null){ err("Command not found. Did you mean \"" + closest.text + "\"?"); + yes = line.replace(response.runCommand, closest.text); }else{ err("Invalid command. Type 'help' for help."); } @@ -944,6 +961,8 @@ public class ServerControl implements ApplicationListener{ err("Too few command arguments. Usage: " + response.command.text + " " + response.command.paramText); }else if(response.type == ResponseType.manyArguments){ err("Too many command arguments. Usage: " + response.command.text + " " + response.command.paramText); + }else if(response.type == ResponseType.valid){ + yes = null; } } @@ -1023,7 +1042,7 @@ public class ServerControl implements ApplicationListener{ serverSocket.bind(new InetSocketAddress(Config.socketInputAddress.string(), Config.socketInputPort.num())); while(true){ Socket client = serverSocket.accept(); - info("&lmReceived command socket connection: &lb@", serverSocket.getLocalSocketAddress()); + info("&lkReceived command socket connection: &fi@", serverSocket.getLocalSocketAddress()); BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); socketOutput = new PrintWriter(client.getOutputStream(), true); String line; @@ -1031,7 +1050,7 @@ public class ServerControl implements ApplicationListener{ String result = line; Core.app.post(() -> handleCommandString(result)); } - info("&lmLost command socket connection: &lb@", serverSocket.getLocalSocketAddress()); + info("&lkLost command socket connection: &fi@", serverSocket.getLocalSocketAddress()); socketOutput = null; } }catch(BindException b){ diff --git a/server/src/mindustry/server/ServerLauncher.java b/server/src/mindustry/server/ServerLauncher.java index 4c8a2bb8e6..ad274954ea 100644 --- a/server/src/mindustry/server/ServerLauncher.java +++ b/server/src/mindustry/server/ServerLauncher.java @@ -29,10 +29,10 @@ public class ServerLauncher implements ApplicationListener{ Vars.platform = new Platform(){}; Vars.net = new Net(platform.getNet()); - Log.setLogger((level, text) -> { - String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr"); - System.out.println(result); - }); + logger = (level1, text) -> { + String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level1.ordinal()] + " " + text + "&fr"); + System.out.println(result); + }; new HeadlessApplication(new ServerLauncher(), null, throwable -> CrashSender.send(throwable, f -> {})); }catch(Throwable t){ CrashSender.send(t, f -> {}); diff --git a/servers.json b/servers.json index 8bb2e2097c..5990afd487 100644 --- a/servers.json +++ b/servers.json @@ -35,6 +35,12 @@ { "address": "aamindustry.play.ai:6568" }, + { + "address": "aamindustry.play.ai:6569" + }, + { + "address": "aamindustry.play.ai:6570" + }, { "address": "mindustry.atannergaming.com" }, @@ -70,5 +76,11 @@ }, { "address": "pandorum.su:9999" + }, + { + "address": "mindustryranked.ddns.net" + }, + { + "address": "attack.pearkin.net" } ] diff --git a/servers_be.json b/servers_be.json index 5ebfae37df..ae667423c5 100644 --- a/servers_be.json +++ b/servers_be.json @@ -7,5 +7,14 @@ }, { "address": "md.surrealment.com" + }, + { + "address": "routerchain.ddns.net" + }, + { + "address": "mindustry.pl:6660" + }, + { + "address": "be.wayzer.cf" } ] diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index d689dbd5df..7dbff14310 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -36,7 +36,7 @@ public class ApplicationTests{ try{ boolean[] begins = {false}; Throwable[] exceptionThrown = {null}; - Log.setUseColors(false); + Log.useColors = false; ApplicationCore core = new ApplicationCore(){ @Override @@ -145,7 +145,7 @@ public class ApplicationTests{ tile.build.items.add(Items.coal, 5); tile.build.items.add(Items.titanium, 50); assertEquals(tile.build.items.total(), 55); - tile.build.items.remove(Items.phasefabric, 10); + tile.build.items.remove(Items.phaseFabric, 10); tile.build.items.remove(Items.titanium, 10); assertEquals(tile.build.items.total(), 45); } @@ -424,6 +424,15 @@ public class ApplicationTests{ assertEquals(300, world.height()); } + @Test + void load108Save(){ + resetWorld(); + SaveIO.load(Core.files.internal("108.msav")); + + assertEquals(256, world.width()); + assertEquals(256, world.height()); + } + @Test void arrayIterators(){ Seq arr = Seq.with("a", "b" , "c", "d", "e", "f"); diff --git a/tests/src/test/java/SectorTests.java b/tests/src/test/java/SectorTests.java index 4110670eed..6f07e77313 100644 --- a/tests/src/test/java/SectorTests.java +++ b/tests/src/test/java/SectorTests.java @@ -66,7 +66,7 @@ public class SectorTests{ outer: for(int i = 1; i <= 1000; i++){ for(SpawnGroup spawn : spawns){ - if(spawn.effect == StatusEffects.boss && spawn.getUnitsSpawned(i) > 0){ + if(spawn.effect == StatusEffects.boss && spawn.getSpawned(i) > 0){ bossWave = i; break outer; } @@ -84,7 +84,7 @@ public class SectorTests{ for(int i = 1; i <= bossWave; i++){ int total = 0; for(SpawnGroup spawn : spawns){ - total += spawn.getUnitsSpawned(i); + total += spawn.getSpawned(i); } assertNotEquals(0, total, "Sector " + zone + " has no spawned enemies at wave " + i); diff --git a/tests/src/test/java/power/FakeGraphics.java b/tests/src/test/java/power/FakeGraphics.java index 378f675224..5f64aa61f3 100644 --- a/tests/src/test/java/power/FakeGraphics.java +++ b/tests/src/test/java/power/FakeGraphics.java @@ -63,11 +63,6 @@ public class FakeGraphics extends Graphics{ return 0; } - @Override - public float getRawDeltaTime(){ - return 0; - } - @Override public int getFramesPerSecond(){ return 0; diff --git a/tests/src/test/java/power/ItemLiquidGeneratorTests.java b/tests/src/test/java/power/ItemLiquidGeneratorTests.java index 08f636c566..1e2224753f 100644 --- a/tests/src/test/java/power/ItemLiquidGeneratorTests.java +++ b/tests/src/test/java/power/ItemLiquidGeneratorTests.java @@ -87,7 +87,7 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{ final float expectedRemainingLiquidAmount = Math.max(0.0f, availableLiquidAmount - expectedConsumptionPerTick * Time.delta); createGenerator(inputType); - assertTrue(entity.acceptLiquid(null, liquid, availableLiquidAmount), inputType + " | " + parameterDescription + ": Liquids which will be declined by the generator don't need to be tested - The code won't be called for those cases."); + assertTrue(entity.acceptLiquid(null, liquid), inputType + " | " + parameterDescription + ": Liquids which will be declined by the generator don't need to be tested - The code won't be called for those cases."); entity.liquids.add(liquid, availableLiquidAmount); entity.cons.update(); diff --git a/tests/src/test/java/power/PowerTestFixture.java b/tests/src/test/java/power/PowerTestFixture.java index 994130a596..ceed02b530 100644 --- a/tests/src/test/java/power/PowerTestFixture.java +++ b/tests/src/test/java/power/PowerTestFixture.java @@ -28,16 +28,16 @@ public class PowerTestFixture{ headless = true; Core.graphics = new FakeGraphics(); Core.files = new MockFiles(); - Vars.state = new GameState(); - Vars.tree = new FileTree(); Vars.content = new ContentLoader(){ @Override public void handleMappableContent(MappableContent content){ } }; + Vars.state = new GameState(); + Vars.tree = new FileTree(); content.createBaseContent(); - Log.setUseColors(false); + Log.useColors = false; Time.setDeltaProvider(() -> 0.5f); } diff --git a/tests/src/test/resources/108.msav b/tests/src/test/resources/108.msav new file mode 100644 index 0000000000..9653e63d16 Binary files /dev/null and b/tests/src/test/resources/108.msav differ diff --git a/tools/build.gradle b/tools/build.gradle index 3266834485..42b27b3ccb 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -3,15 +3,12 @@ sourceSets.main.java.srcDirs = ["src/"] import arc.struct.* import arc.graphics.* import arc.packer.* -import arc.util.Tmp +import arc.util.* -import javax.imageio.ImageIO -import java.awt.* -import java.awt.image.BufferedImage -import java.util.List -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit +import javax.imageio.* +import java.awt.Graphics2D +import java.awt.image.* +import java.util.concurrent.* def genFolder = "../core/assets-raw/sprites_out/generated/" def doAntialias = !project.hasProperty("disableAntialias") diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 401feb9ec5..645b2ea7f0 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -78,11 +78,84 @@ public class Generators{ } }); + ImagePacker.generate("cliffs", () -> { + int size = 64; + Color dark = new Color(0.5f, 0.5f, 0.6f, 1f).mul(0.98f); + Color mid = Color.lightGray; + + Image[] images = new Image[8]; + for(int i = 0; i < 8; i++){ + images[i] = ImagePacker.get("cliff" + i); + } + + for(int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++){ + Image result = new Image(size, size); + byte[][] mask = new byte[size][size]; + + byte val = (byte)i; + //check each bit/direction + for(int j = 0; j < 8; j++){ + if((val & (1 << j)) != 0){ + if(j % 2 == 1 && (((val & (1 << (j + 1))) != 0) != ((val & (1 << (j - 1))) != 0))){ + continue; + } + + Image image = images[j]; + image.each((x, y) -> { + Color color = image.getColor(x, y); + if(color.a > 0.1){ + //white -> bit 1 -> top + //black -> bit 2 -> bottom + mask[x][y] |= (color.r > 0.5f ? 1 : 2); + } + }); + } + } + + result.each((x, y) -> { + byte m = mask[x][y]; + if(m != 0){ + //mid + if(m == 3){ + //find nearest non-mid color + byte best = 0; + float bestDst = 0; + boolean found = false; + //expand search range until found + for(int rad = 9; rad < 64; rad += 7){ + for(int cx = Math.max(x - rad, 0); cx <= Math.min(x + rad, size - 1); cx++){ + for(int cy = Math.max(y - rad, 0); cy <= Math.min(y + rad, size - 1); cy++){ + byte nval = mask[cx][cy]; + if(nval == 1 || nval == 2){ + float dst2 = Mathf.dst2(cx, cy, x, y); + if(dst2 <= rad * rad && (!found || dst2 < bestDst)){ + best = nval; + bestDst = dst2; + found = true; + } + } + } + } + } + + if(found){ + m = best; + } + } + + result.draw(x, y, m == 1 ? Color.white : m == 2 ? dark : mid); + } + }); + + result.save("../blocks/environment/cliffmask" + (val & 0xff)); + } + }); + ImagePacker.generate("cracks", () -> { RidgedPerlin r = new RidgedPerlin(1, 3); - for(int size = 1; size <= Block.maxCrackSize; size++){ + for(int size = 1; size <= BlockRenderer.maxCrackSize; size++){ int dim = size * 32; - int steps = Block.crackRegions; + int steps = BlockRenderer.crackRegions; for(int i = 0; i < steps; i++){ float fract = i / (float)steps; diff --git a/tools/src/mindustry/tools/ImagePacker.java b/tools/src/mindustry/tools/ImagePacker.java index 2533f99af9..1142de8a26 100644 --- a/tools/src/mindustry/tools/ImagePacker.java +++ b/tools/src/mindustry/tools/ImagePacker.java @@ -28,10 +28,10 @@ public class ImagePacker{ Vars.headless = true; ArcNativesLoader.load(); - Log.setLogger(new NoopLogHandler()); + Log.logger = new NoopLogHandler(); Vars.content = new ContentLoader(); Vars.content.createBaseContent(); - Log.setLogger(new DefaultLogHandler()); + Log.logger = new DefaultLogHandler(); Fi.get("../../../assets-raw/sprites_out").walk(path -> { if(!path.extEquals("png")) return;